STM32---I2C通讯

发布时间 2023-10-11 12:08:44作者: 好香芋泥煎意面

STM32的I2C通讯可以使用两种方式实现,分别是软件I2C,和硬件I2C。软件I2C主要是通过代码手动翻转电平来模拟时序;硬件I2C主要使用通过STM32自带的硬件外设实现。以下,我着重讲述一下硬件I2C的部分。

 

想要使用硬件I2C,主要分为以下四个步骤:

第一步,开启GPIO和I2C的时钟

跟GPIO一样,I2C需要开启时钟。

 

第二步,把IIC对应的GPIO口初始化成-复用开漏模式-

使用硬件I2C时,一般都是将引脚设置为复用开漏模式。

 

第三步,使用结构体配置IIC

跟GPIO一样,I2C也有结构体,通过配置结构体来确认I2C的通讯参数。

 

第四步,I2C_CMD使能硬件I2C

使能硬件I2C。

 

好了,现在我们知道具体的步骤了,具体讲述以下几个I2C常用的函数。

/* ---------------------------------------------- 常用I2C函数 ----------------------------------------------  */
void I2C_GenerateStart()//IIC产生起始条件
/* 具体可以查看手册  CR1_START位 */

void I2C_GenerateStop()//IIC产生终止条件
/* 具体可以查看手册 CR1_STOP位 */

void I2C_AcknowledeConfig()//配置IIC的应答使能
/* 具体可以查看手册 CR1_ACK位 */

void I2C_SendData()//用于传输IIC数据
/* 具体可以查看手册 DR寄存器
DR(数据寄存器)的-发送器模式-

*/

uint8_t I2C_ReceiveData ()//接受IIC传输的数据
/* 具体可以查看手册 DR寄存器
DR(数据寄存器)的-接收器模式-

*/

I2C_Send7bitAddress()//IIC发送7位地址
/* 设置了地址最低位

如果地址最低位为1-就是读
如果地址最低位为0-就是写

*/

 

既然知道了这几个函数,但是怎么去判断函数有没有执行(怎么去判断函数执行到了哪里)。这时,我们可以通过使用状态检测函数来识别当前状态,以便捕捉到I2C的时序。

 

/* ---------------------------------------------- IIC状态检测函数 ----------------------------------------------  */

 

Basic State Monitoring//基本状态监控-通过检测寄存器的状态,来判断当前状态


I2C_CheckEvent ()//同时判断一个或多个标志位,来确定EV_X是否发生

FlagStatus I2C_GetFlagStatus()//获取IIC标志位
void I2C_ClearFlag()//清除IIC标志位
FlagStatus I2C_GetITFlagStatus()//获取IIC中断标志位
void I2C_ClearITPendingBit()//清除IIC中断标志位

 

/* ---------------------------------------------- 硬件IIC代码----------------------------------------------  */

 

既然知道了如何进行I2C通讯,那么就开始写代码吧,一下是硬件I2C的代码部分

I2C_Init(){


RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2 ,ENABLE);//开启I2C外设的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);//开启GPIOB的时钟


GPIO_TypeDef GPIO_InitStructure ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//复用开漏模式
GPIO_InitStructure.GPIO_Pin =GPIO_PIN_10|GPIO_PIN_11;//pin10和pin11
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHZ;//50MHZ
GPIO(GPIO_B ,&GPIO_InitStructure);


I2C_InitTypeDef I2C_InitStructure ;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C ;//IIC模式-I2CI2C模式; SMBusDevice-SMBus总线的设备; SMBusHost-SMBus总线的主机;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;//应答位配置,默认是应答的。
I2C_InitStructure.I2C_ClockSpeed =50000 ;//时钟频率 ,必须是400kHZ以下的速度。
I2C_InitStructure.I2C_DutyCycle =I2C_DutyCycle_2;时钟占空比,只有进入到快速状态时才有用 100kHZ -40kHZ。小于100kHZ占空比是1:1
I2C_InitStructure.I2C_AcknowledgeAddress =I2C_AcknowledgeAddress_7bit ;//STM32作为从机,可以相应几位的地址。
I2C_InitStructure.I2C_OwnAddress1 = 0x00 ;

I2C_Init(I2C2 , &I2C_InitStructure);
I2C_Cmd (I2C2 ,Enable);

}

void I2C_Wirte (Uint8_t RegAddress,Uint8_t Data ){

I2C_GenerateStart(I2C2 ,ENABLE );//起始
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);//等待EV5事件发生

I2C_Send7bitAddress(I2C2 , MPU6050_Address , I2C_Direction_Transmitter);//发送7位地址主机地址
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);//等待EV6事件发生
I2C_SendData(I2C2, RegAddress);
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING)!=SUCCESS);//等待EV8事件发生

I2C_SendData(I2C2,Data);
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);//等待EV8_2事件发生,终止
I2C_GenerateStop(I2C2 ,ENABLE);


}

Uint8_t I2C_Read (Uint8_t RegAddress){

I2C_GenerateStart(I2C2 ,Enable );//起始
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);//等待EV5事件发生

I2C_Send7bitAddress(I2C2 , MPU6050_Address , I2C_Direction_Transmitter);//发送7位地址
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)!=SUCCESS);//等待EV6事件发生
I2C_SendData(I2C2, RegAddress);
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED)!=SUCCESS);//等待EV8事件发生

I2C_GenerateStart(I2C2 ,Enable );//起始
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_MODE_SELECT)!=SUCCESS);//等待EV5事件发生

I2C_Send7bitAddress(I2C2 , MPU6050_Address , I2C_Direction_Receiver);//发送7位地址从机地址
While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)!=SUCCESS);//等待从机EV6事件发生
//接收一个数据之前就要提前设置好ACK位和STOP位

I2C_AcknowledeConfig(I2C2, DISABLE);
I2C_GenerateStop(I2C2 ,ENABLE);


While (I2C_CheckEvent (I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED)!=SUCCESS);//等待从机EV6_1事件发生
DATA = I2C_ReceiveData(I2C2);
I2C_AcknowledeConfig(I2C2, ENABLE);

return DATA;

}

 

以上,如有错误,请帮忙指正。