I2C通信协议(软件I2C和硬件I2C)

news2024/12/28 19:37:01

相比于之前学的异步全双工且需要两条通信线的串口通信,I2C则为同步半双工,仅需要一条通信线,全双工与半双工区别如下:

全双工(Full Duplex)半双工(Half Duplex)
数据传输方式同时双向传输交替单向传输
通道数量两条独立通道(一条发送,一条接收)一条通道(或交替使用同一条通道)
效率高(同时发送和接收)较低(不能同时发送和接收)
延迟低(无需等待对方发送完毕)较高(需要等待对方发送完毕)
成本较高(需要更多硬件支持)较低(硬件需求较少)
系统复杂度较高(设计和维护较复杂)较低(设计和维护较简单)
应用场景电话通信、视频通话、实时数据传输等对讲机通信、低功耗无线传感器网络等

I2C通信一共需要四根线:VCC,GND,SDA(数据线),SCL(时钟线)因为有时钟线,I2C通信为同步时序,因此对时间的要求不是那么严格,通常可以很好的用软件进行模拟;

需要用I2C通信的模块一般有:OLED显示屏,MPU6050(陀螺仪),AT24C02(存储器)

在串口通信中,通常为两个设备通过串口点对点的通信,而在I2C通信中,有一条I2C总线,多个设备挂载到总线上,同时进行通信,所以I2C又分为:一主多从,固定多主多从,可变多主多从

一主多从:通信时只有一个主机,而从机可以有多个,主机控制整个通信过程,包括初始化通信,开始通信,发送数据,接收数据,以及终止通信等等,在该过程中,主机就像一个教室里的班主任,而从机就像学生,学生的一切动作都需要听从班主任安排;

固定多主多从:通信时有多个主机(且主机数量以固定,其他从机不可变为主机),多个从机,通信时需要多个主机(只有一个起作用)中的一个跳出来充当主机,若多个主机同时想充当主机时,则需要进行总线仲裁,获胜的设备可以充当主机,在该过程中,多个主机就相当于多位老师一起在讲台上,正所谓一山不容二虎,老师们需要比较之后才能得到上台讲话的机会;

可变多主多从:通信时有多个主机(所有设备都可以充当主机),在通信时需要一个设备跳出来充当主机,在该过程中,所有设备相当于学生开始全坐在,需要发言时举手,然后站起来说话;

当然我们平常在使用stm32时只需要掌握一主多从模式就行了,多主多从模式了解就行

下面是一张一主多从的硬件电路图

在硬件接线上所有设备SCL都要连一起,SDA同理;

为了避免两个设备同时输出且一个输出高电平,一个输出低电平导致的电源短路,SDA和SCL均要配置成开漏输出模式,SDA和SCL个添加一个上拉电阻(一般为4.7KΩ)此时为弱上拉;

SCL线从始至终都只能由主机控制,而SDA在主机接收数据和接收应答的时候可由从机暂时控制;

I2C时序基本单元:(SDA与SCL默认上拉为高电平)

起始条件:SCL高电平期间,SDA下降沿;

终止条件:SCL高电平期间,SDA上升沿;

发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,循环上述过程8次,即可发送一个字节

接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA,从机对SDA进行控制)
发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答


接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

从机地址:用于主机确定从机设备的名字,每个从机都具有唯一的地址,从机地址具有7位和10位,通常用7位地址就够了,7位地址比较简单1且应用范围最广,例:MPU6050的地址为1101000,地址中分为可变部分和不可变部分,一般为最后几位,MPU6050的可变地址为最后一位,可以由AD0引脚确定,引脚接低电平,则它的地址为1101000,反之则为1101001,可变部分用于两个相同的模块在一条总线上时区分

I2C时序

指定地址写:对于指定设备(Slave Address)在指定地址(Reg Address)下写入指定数据Data

时序逻辑:主机首先发送一个起始条件,然后发送一个字节(8位:7位地址加一位读写位(0为写入,1为读出)),之后从机给应答位(0为应答,1为非应答),主机再发送一个字节(此时为要操作的寄存器的地址),从机发送应答位,之后主机再向从机发送要写入的寄存器的数据了,从机产生非应答,最后主机产生停止条件

当前地址读:对于指定设备(Slave Address)在当前地址指针指示的地址下,读取从机数据

时序逻辑:主机首先发送一个起始条件,然后发送一个字节(地址加读写位),之后从机给应答位,主机接收一个字节,主机产生非应答,最后主机产生停止条件;通过与指定地址写对比,当前地址读缺少了主机发送操作的寄存器的地址,那么主机读取的数据来自从机的哪个寄存器?在从机中所有寄存器被分配到了一个线性区域中,一个单独的指针指向寄存器,这个指针上电默认指向0地址,每写入一个字节或读出一个字节后,该指针自动自增一次;由此可知,那么主机读取的数据就是当前指针指示的寄存器,并且指针自增加一;

例:若先调用一次指定地址写,操作的寄存器地址为0x19,那当前指针的值就变为0x1A了,再调用一次当前地址读,此时读取的数据就是0x1A寄存器中的数据了,并且由于指针自加一,下次再调用当前地址读就是读取0x1B的数据了;

指定地址读:由于当前地址读的应用范围有限,所以有了另一个时序:指定地址读,对于指定设备(Slave Address)在指定地址(Reg Address)下读取从机数据

指定地址读为指定地址写的前半部分刚指定地址还没开始写数据的时候,重新发送一个起始条件,然后执行当前地址读操作

时序逻辑:主机首先发送一个起始条件,然后发送一个字节(地址加读写位),之后从机给应答位,主机再发送一个字节(此时为要读取的寄存器的地址),从机发送应答位,之后重新发送起始条件,因为改变读写操作只能在起始条件的下一个字节的最后一位,然后发送一个字节(地址加读写位),之后主机接收一个字节,主机产生非应答,最后主机产生停止条件

 软件I2C工程代码:

I2C初始化

void MyI2C_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

写SCL,SDA,读SDA

void MyI2C_W_SCL(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}

BitAction 为枚举类型,之中的值非0即1

起始条件

void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

停止条件

void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

发送一个字节

void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

接收一个字节

uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;
	MyI2C_W_SDA(1);
	for (i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1);
		if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}
		MyI2C_W_SCL(0);
	}
	return Byte;
}

发送应答位

void MyI2C_SendAck(uint8_t AckBit)
{
	MyI2C_W_SDA(AckBit);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

接收应答位

uint8_t MyI2C_ReceiveAck(void)
{
	uint8_t AckBit;
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	AckBit = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return AckBit;
}

MPU6050利用软件I2C通信:MPU6050从机地址为0xD0,所以将地址宏定义为MPU6050_ADDRESS

MPU6050指定地址写数据

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

MPU6050指定地址读数据

uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(RegAddress);
	MyI2C_ReceiveAck();
	
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS | 0x01);
	MyI2C_ReceiveAck();
	Data = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	MyI2C_Stop();
	
	return Data;
}

MPU6050寄存器宏定义

#define	MPU6050_SMPLRT_DIV		0x19
#define	MPU6050_CONFIG			0x1A
#define	MPU6050_GYRO_CONFIG		0x1B
#define	MPU6050_ACCEL_CONFIG	0x1C

#define	MPU6050_ACCEL_XOUT_H	0x3B
#define	MPU6050_ACCEL_XOUT_L	0x3C
#define	MPU6050_ACCEL_YOUT_H	0x3D
#define	MPU6050_ACCEL_YOUT_L	0x3E
#define	MPU6050_ACCEL_ZOUT_H	0x3F
#define	MPU6050_ACCEL_ZOUT_L	0x40
#define	MPU6050_TEMP_OUT_H		0x41
#define	MPU6050_TEMP_OUT_L		0x42
#define	MPU6050_GYRO_XOUT_H		0x43
#define	MPU6050_GYRO_XOUT_L		0x44
#define	MPU6050_GYRO_YOUT_H		0x45
#define	MPU6050_GYRO_YOUT_L		0x46
#define	MPU6050_GYRO_ZOUT_H		0x47
#define	MPU6050_GYRO_ZOUT_L		0x48

#define	MPU6050_PWR_MGMT_1		0x6B
#define	MPU6050_PWR_MGMT_2		0x6C
#define	MPU6050_WHO_AM_I		0x75

MPU6050初始化

void MPU6050_Init(void)
{
	MyI2C_Init();//软件I2C引脚初始化
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);//配置电源管理器1(解除睡眠模式)
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);//配置电源管理器2
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);//配置采样率分频--十分频(值越小越快)
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);//配置外部同步和数字低通滤波寄存器
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);//配置陀螺仪寄存器
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);//配置量程寄存器
}

MPU6050接收数据:(在主函数里传六个变量的地址达到返回六个值的目的,还可以将这六个变量打包成一个结构体,在主函数里直接传结构体的地址即可)

void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	uint8_t DataH, DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}

        在主函数里接收数据:

int16_t AX, AY, AZ, GX, GY, GZ;
MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);

MPU6050读取ID号

uint8_t MPU6050_GetID(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

硬件I2C

硬件I2C简介

I2C基本结构:数据的收发由数据寄存器和移位寄存器来控制,并且在移位寄存器中高位先行

硬件I2C工程代码:由于硬件I2C有自己的库函数,所以不需要用户自己再建立I2C模块了,只需初始化对应GPIO口(复用开漏输出)

在软件模拟I2C中,每个时序都是加了延时的阻塞型,而在硬件I2C中,每完成一步,产生相应的标志位,可以通过判断标志位的状态来控制时序的进行,而有的状态需要多个标志位,所以在硬件I2C中将标志位融合成了事件,即通过判断事件是否发生即可知道时序的进行状态,在判断事件的产生时有许多的while死循环,一旦某个环节出错了之后,程序就会卡死,所以检查事件的产生还要加上一个超时判断

MPU6050事件是否产生

void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
	uint32_t Timeout;
	Timeout = 10000;
	while (I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS)
	{
		Timeout --;
		if (Timeout == 0)
		{
			break;
		}
	}
}

MPU6050指定地址写数据

void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	I2C_GenerateSTART(I2C2, ENABLE);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2, RegAddress);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
	
	I2C_SendData(I2C2, Data);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	I2C_GenerateSTOP(I2C2, ENABLE);
}

MPU6050指定地址读数据

uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	I2C_GenerateSTART(I2C2, ENABLE);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2, RegAddress);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	I2C_GenerateSTART(I2C2, ENABLE);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver);
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
	
	I2C_AcknowledgeConfig(I2C2, DISABLE);
	I2C_GenerateSTOP(I2C2, ENABLE);
	
	MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);
	Data = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2, ENABLE);
	
	return Data;
}

MPU6050初始化

void MPU6050_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_ClockSpeed = 50000;//配置I2C时钟频率
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//配置I2C时钟占空比
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//配置I2C应答位使能
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//从机地址7位还是10位
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;//从机地址
	I2C_Init(I2C2, &I2C_InitStructure);
	
	I2C_Cmd(I2C2, ENABLE);
	
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2064012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux 磁盘满了,程序运行失败,如何处理?df -h

场景&#xff1a;紧急呼救&#xff0c;上传图片失败了。我一脸懵&#xff0c;服务器这是又咋地了&#xff0c;别邪乎姐姐&#xff0c;姐姐胆子小啊。 一、寻找问题原因 1、OSS出问题了&#xff1f; 然后我尝试了 IOS 的APP是没问题的&#xff0c;Android提示上传失败&#xf…

Excel技巧(一)

快捷键技巧 原文链接 选取某一行的数据直到最后一行&#xff1a;【CTRL SHIFT ↓ 】或者选取一行后按住SHIFT键&#xff0c;双击下边线就可以快速选取区域。 如果表格中有多行空行&#xff0c;可以先按CTRL SHIFT END&#xff0c;再按CTRL SHIFT 上下键调整&#xff0c;…

CodeLLDB的快速安装

1、CodeLLDB很难安装 ‌‌CodeLLDB插件是一个基于‌LLDB的调试器插件&#xff0c;专为‌Visual Studio Code设计&#xff0c;旨在提供类似于传统集成开发环境&#xff08;IDE&#xff09;的调试体验。‌ 它支持‌C、‌C和‌Objective-C程序的调试&#xff0c;包括设置断点、查…

这4款工具可以教会你如何用AI写ppt.

随着AI工具的盛行&#xff0c;AI办公工具也组建越来越多&#xff0c;我们可以用AI帮助生成各种文档&#xff0c;包括PPT。今天我就帮大家总结一波专业又好用的ai生成PPT的工具&#xff0c;一共有4款。 1、笔灵ppt 直通车&#xff1a;https://ibiling.cn/ppt-zone 首先要说的这…

颠茄和草本曼陀罗参考基因组(茄科)

茄科的代表性物种之二&#xff1a;颠茄和草本曼陀罗 来源文献 Revealing evolution of tropane alkaloid biosynthesis by analyzing two genomes in the Solanaceae family 推荐 惕佫酰假托品合酶的发现-文献精读28 参考链接 https://ngdc.cncb.ac.cn/gwh/Assembly/29467/s…

【Python零基础】Python中的函数

文章目录 前言一、函数定义二、传递实参三、返回值四、传递列表五、传递任意数量实参六、把函数存储在模块中七、函数定义指南总结 前言 在Python中&#xff0c;函数是一段可重用的代码块&#xff0c;用于执行特定任务。函数可以通过定义关键字 def 来创建&#xff0c;并且通常…

网络安全-防火墙安全策略初认识

文章目录 前言理论介绍1. 安全策略1.1 定义&#xff1a;1.2 关键术语&#xff1a; 2. 防火墙状态监测 实战步骤1&#xff1a;实验环境搭建步骤2&#xff1a;配置实现 总结1. 默认安全策略2. 自定义安全策略3. 防火墙状态会话表 前言 who&#xff1a;本文主要写给入门防火墙的技…

容器篇(Java - 集合)

目录 有意者可加 一、集合 1. 出现的背景 2. 带大家具体了解下集合 3. 集合带来了哪些好处 4. 集合的特点 5. 集合和数组对比 6. 数组和集合应用场景&#xff08;对比&#xff09; 6.1 数组的应用场景 1. 存储一组数据 2. 图像处理 3. 矩阵运算 4. 缓存 6.2 集合…

基于Python的mediapipe和opencv的人体骨骼、人体姿态关键点的实时跟踪项目

随着计算机视觉技术的发展&#xff0c;人体姿态估计在虚拟现实、运动分析、人机交互等领域得到了广泛应用。传统的姿态估计方法通常依赖于深度学习模型&#xff0c;需要大量的计算资源。而 Google 开发的 MediaPipe 框架则提供了高效且易于使用的解决方案&#xff0c;它可以在各…

78、 ansible----playbook

一、ansible模块 11、防火墙和网络模块&#xff1a; [roottest1 ~]# ansible 192.168.168.23 -m iptables -a chainINPUT protocolICMP source192.168.168.22 jumpREJECT -b ##-b后台&#xff0c;拒绝[roottest3 ~]# yum -y install nginx[roottest3 ~]# systemctl restart …

论文合集下载丨第十九届全国人机语音通讯学术会议

2024年8月15日至18日&#xff0c;第十九届全国人机语音通讯学术会议&#xff08;NCMMSC&#xff09;暨CCF语音对话与听觉专委会2024年学术年会在新疆乌鲁木齐成功召开。 会议论文集下载方式在文末 &#x1f447; 全国人机语音通讯学术会议作为语音技术领域内的专家、学者及科研…

为什么需要文献综述模板和创建文献综述技巧

为什么需要文献综述模板&#xff1f; 文献综述模板可以作为特定主题的指南。如果您的时间有限&#xff0c;无法进行更多研究&#xff0c;文献综述大纲示例可以为您提供帮助&#xff0c;因为它可以为您提供您打算研究的内容的概述。 甚至各个领域的专业人士也依赖文学评论来了解…

易灵思FPGA-Trion的MIPI设置使用

一、MIPI简介&#xff1f; 不需要各种资料上一大堆对物理层MIPI传输协议的讲解&#xff0c;实话说&#xff0c;我也不是特别能吃透其中的时序&#xff0c;所以不多研究&#xff1b;所有的FGPA如果带MIPI &#xff0c;那就只研究控制器就行了 &#xff0c;没必要舍近求远 二、硬…

NVM安装管理node.js版本(简单易懂)

一、前言 1.1 简介 NVM&#xff08;Node Version Manager&#xff09;是 node.js 的版本管理器&#xff0c;用 shell 脚本切换机器中不同版本的 nodejs。 Nodejs为什么需要多个版本&#xff1f; 有经验的开发者可能遇到过&#xff0c;某个依赖包明确nodejs是某个版本&#…

深度学习--RNN以及RNN的延伸

循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类能够处理序列数据的神经网络&#xff0c;在自然语言处理、时间序列分析等任务中得到了广泛应用。RNN能够通过其内部的循环结构&#xff0c;捕捉到序列中前后项之间的关系。下面我将从原理、作用、应用…

【AI绘画】Midjourney提示词详解:精细化技巧与高效实践指南

文章目录 &#x1f4af;Midjourney提示词基础结构1 图片链接1.1 上传流程 2 文字描述3 后置参数 &#x1f4af;Midjourney提示词的文字描述结构全面剖析1 主体主体细节描述2 环境背景2.1 环境2.2 光线2.3 色彩2.4 氛围 3 视角4 景别构图5 艺术风格6 图片制作方法7 作品质量万能…

振动分析-20-振动三要素的理解及决定设备分析水平的因素

1 对频谱分析的定位 一般咨询一个振动问题,很多人往往是要求把各种频谱贴上来看看,却很少有人问,振动过程、检修经历、设备结构、振动位置、振动方向、负荷关系、油温变化、转速影响等等。 刚刚接触振动检测时,对有关频谱分析方面资料如饥似渴,对于早期从事振动诊断的朋…

CentOS 7使用RPM安装MySQL

MySQL是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;允许用户高效地存储、管理和检索数据。它被广泛用于各种应用&#xff0c;从小型的web应用到大型企业解决方案。 MySQL提供了丰富的功能&#xff0c;包括支持多个存储引擎、事务能力、数据完整性…

Google Earth Engine(GEE)——计算非监督分类的中的面积和占比

函数: aggregate_sum(property) Aggregates over a given property of the objects in a collection, calculating the sum of the values of the selected property. 对一个集合中的对象的特定属性进行聚合,计算所选属性值的总和。 Arguments: this:collection (Featur…

嵌入式初学-C语言-二九

C语言编译步骤 预处理编译汇编链接 什么是预处理 预处理就是在源文件&#xff08;如.c文件&#xff09;编译之前&#xff0c;所进行的一部分预备操作&#xff0c;这部分操作是由预处理程序自动完成&#xff0c;当源文件在编译时&#xff0c;编译器会自动调用预处理指令的解析…