I2C
一. 常用库函数
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);
void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT);
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);
void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);
二. 初始化(硬件I2C,适配MPU6050)
voidMPU6050_Init(void){/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);//开启I2C2的时钟(硬件I2C外设时钟,APB1总线)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB的时钟(I2C引脚时钟)/*GPIO初始化(I2C引脚:SCL=PB11,SDA=PB10)*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD;//模式:复用开漏输出(I2C专用模式)GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_11;//引脚:PB10(SDA)、PB11(SCL)GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化GPIOB对应引脚/*硬件I2C初始化*/I2C_InitTypeDef I2C_InitStructure;//定义I2C初始化结构体变量I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;//模式:标准I2C模式I2C_InitStructure.I2C_ClockSpeed=50000;//时钟速度:50KHz(MPU6050适配速率)I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;//时钟占空比:Tlow/Thigh = 2I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;//应答使能:开启(I2C通信必备)I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;//应答地址:7位地址模式I2C_InitStructure.I2C_OwnAddress1=0x00;//自身地址:主机模式下无效,设为0x00即可I2C_Init(I2C2,&I2C_InitStructure);//将结构体配置应用到I2C2外设/*I2C使能*/I2C_Cmd(I2C2,ENABLE);//使能I2C2,硬件I2C开始工作}初始化关键说明
时钟配置:硬件I2C2挂载在APB1总线,时钟需通过RCC_APB1PeriphClockCmd开启;GPIO引脚(PB10、PB11)挂载在APB2总线,需单独开启时钟。
GPIO配置:I2C引脚必须配置为GPIO_Mode_AF_OD(复用开漏输出),开漏输出可实现I2C总线的线与逻辑,无需额外上拉电阻(硬件内部已集成)。
I2C核心参数:时钟速度50KHz(MPU6050支持100KHz和50KHz,50KHz稳定性更高);应答使能必须开启,否则无法完成I2C通信的应答交互。
注意事项
硬件I2C引脚固定:I2C2的SCL对应PB11、SDA对应PB10,不可随意更改(硬件外设与引脚固定映射),若需使用其他I2C外设(如I2C1),需对应修改引脚和时钟配置。
事件等待超时:MPU6050_WaitEvent函数设置了超时保护(10000次计数),若超时未检测到指定事件,会跳出循环,可在超时处添加错误处理代码(如指示灯提示)。
应答配置:读取单字节数据时,需提前失能应答、申请停止条件,读取完成后恢复应答使能,避免影响后续多字节读取操作。
从机地址:MPU6050的默认I2C从机地址为0xD0(7位地址为0x68,左移1位加写方向位0,即0x68<<1=0xD0),若传感器AD0引脚接高电平,地址变为0xD2。
数据拼接:MPU6050的加速度计、陀螺仪数据为16位,需读取高8位(H)和低8位(L),通过“(DataH << 8) | DataL”拼接为完整的16位数据,注意数据为有符号数(最高位为符号位)。
时钟速度:I2C时钟速度建议设为50KHz或100KHz,过高会导致通信不稳定,MPU6050最大支持400KHz,但实际使用中50KHz稳定性最优。
三. 读写示例
#defineMPU6050_ADDRESS0xD0//MPU6050的I2C从机地址/** * 函 数:MPU6050等待事件 * 参 数:同I2C_CheckEvent * 返 回 值:无 */voidMPU6050_WaitEvent(I2C_TypeDef*I2Cx,uint32_tI2C_EVENT){uint32_tTimeout;Timeout=10000;//给定超时计数时间while(I2C_CheckEvent(I2Cx,I2C_EVENT)!=SUCCESS)//循环等待指定事件{Timeout--;//等待时,计数值自减if(Timeout==0)//自减到0后,等待超时{/*超时的错误处理代码,可以添加到此处*/break;//跳出等待,不等了}}}/** * 函 数:MPU6050写寄存器 * 参 数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述 * 参 数:Data 要写入寄存器的数据,范围:0x00~0xFF * 返 回 值:无 */voidMPU6050_WriteReg(uint8_tRegAddress,uint8_tData){I2C_GenerateSTART(I2C2,ENABLE);//硬件I2C生成起始条件MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//硬件I2C发送从机地址,方向为发送MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6I2C_SendData(I2C2,RegAddress);//硬件I2C发送寄存器地址MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);//等待EV8I2C_SendData(I2C2,Data);//硬件I2C发送数据MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待EV8_2I2C_GenerateSTOP(I2C2,ENABLE);//硬件I2C生成终止条件}/** * 函 数:MPU6050读寄存器 * 参 数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述 * 返 回 值:读取寄存器的数据,范围:0x00~0xFF */uint8_tMPU6050_ReadReg(uint8_tRegAddress){uint8_tData;I2C_GenerateSTART(I2C2,ENABLE);//硬件I2C生成起始条件MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);//硬件I2C发送从机地址,方向为发送MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待EV6I2C_SendData(I2C2,RegAddress);//硬件I2C发送寄存器地址MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待EV8_2I2C_GenerateSTART(I2C2,ENABLE);//硬件I2C生成重复起始条件MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//等待EV5I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);//硬件I2C发送从机地址,方向为接收MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//等待EV6I2C_AcknowledgeConfig(I2C2,DISABLE);//在接收最后一个字节之前提前将应答失能I2C_GenerateSTOP(I2C2,ENABLE);//在接收最后一个字节之前提前申请停止条件MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);//等待EV7Data=I2C_ReceiveData(I2C2);//接收数据寄存器I2C_AcknowledgeConfig(I2C2,ENABLE);//将应答恢复为使能,为了不影响后续可能产生的读取多字节操作returnData;}