接线图
![](https://i-blog.csdnimg.cn/direct/c2abe62f4bc148bd8b8af5e741b68712.png)
函数介绍
生成起始条件
cs
void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState);
生成终止条件
cs
void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState);
配置在收到一个字节后,是否给从机应答(配置ACK位)
cs
void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState);
发送数据,就是把Data这个数据直接写入到DR寄存器
cs
void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data);
读取DR的数据
cs
uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx);
发送7位地址的专用函数
cs
void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction);
代码配置
配置硬件I2C读写初始化函数
1.定义结构体变量
bash
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体变量
I2C_InitTypeDef I2C_InitStructure;//定义I2C结构体变量
2.开启时钟
bash
//开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);//开启I2C2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启GPIO B族的时钟
3.配置GPIO
bash
//配置GPIO
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);
4.初始化I2C2外设
bash
//配置I2C2
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //I2C模式
I2C_InitStructure.I2C_ClockSpeed = 50000; //配置SCL的时钟频率
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //时钟占空比
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //应答位配置
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//从机响应几位地址的配置
I2C_InitStructure.I2C_OwnAddress1 = 0x00; //自身地址1
I2C_Init(I2C2, &I2C_InitStructure);
使能I2C
bash
//使能I2C2
I2C_Cmd(I2C2, ENABLE);
整体代码
cs
//------------------------------硬件I2C读写--------------------------------------
void I2C_Init2(void)
{
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体变量
I2C_InitTypeDef I2C_InitStructure;//定义I2C结构体变量
//开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);//开启I2C2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启GPIO B族的时钟
//配置GPIO
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);
//配置I2C2
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //I2C模式
I2C_InitStructure.I2C_ClockSpeed = 50000; //配置SCL的时钟频率
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //时钟占空比
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //应答位配置
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//从机响应几位地址的配置
I2C_InitStructure.I2C_OwnAddress1 = 0x00; //自身地址1
I2C_Init(I2C2, &I2C_InitStructure);
//使能I2C2
I2C_Cmd(I2C2, ENABLE);
}
//------------------------------硬件I2C读写--------------------------------------
MPU6050配置
cs
//从机地址
#define MPU6050_ADDRESS 0xD0
cs
void MPU6050_Init(void)
{
I2C_Init2();
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);
}
指定地址写时序
![](https://i-blog.csdnimg.cn/direct/7592bbc7f66f434e961118078b2e3c7e.png)
cs
//指定地址写时序
void MPU6050_WriteReg(uint8_t RegAddRess, uint8_t Data)
{
//生成起始条件
I2C_GenerateSTART(I2C2, ENABLE);
//等待EV5事件到来,检查EV5事件
while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
//发送从机地址 方向为发送
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
//等待事件 EV6
while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
//写入DR,发送数据
I2C_SendData(I2C2, RegAddRess);
//等待事件 EV8
while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);
//发送数据
I2C_SendData(I2C2, Data);
//等待事件 EV8_2
while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);
//终止条件
I2C_GenerateSTOP(I2C2, ENABLE);
}
指定地址读时序
![](https://i-blog.csdnimg.cn/direct/a87b1079134f4ce38ea105f54013c4db.png)
cs
//指定地址读时序
uint8_t MPU6050_ReadReg(uint8_t RegAddRess)
{
uint8_t Data;
//起始条件
I2C_GenerateSTART(I2C2, ENABLE);
//等待事件 EV5
while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
//发送从机地址 方向为发送
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
//等待事件 EV6
while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
//发送寄存器地址
I2C_SendData(I2C2, RegAddRess);
//等待事件 EV8_2
while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);
//重复起始条件
I2C_GenerateSTART(I2C2, ENABLE);
//等待事件 EV5
while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
//发送从机地址 方向为接收
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver);
//等待事件 EV6
while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);
//配置ACK位
I2C_AcknowledgeConfig(I2C2, DISABLE);
//终止条件
I2C_GenerateSTOP(I2C2, ENABLE);
//等待事件 EV7
while(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
//读取DR
Data = I2C_ReceiveData(I2C2);
I2C_AcknowledgeConfig(I2C2, ENABLE);
return Data;
}
主函数
cs
#include "MyI2C.h"
#include "MPU6050.h"
int main(void)
{
int16_t AX, AY, AZ, GX, GY, GZ;
uint8_t ID;
OLED_Init();
MPU6050_Init();
OLED_ShowString(1, 1, "ID:");
ID = MPU6050_GetID();
OLED_ShowHexNum(1, 4, ID, 2);
while(1)
{
MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);
OLED_ShowSignedNum(2, 1, AX, 5);
OLED_ShowSignedNum(3, 1, AY, 5);
OLED_ShowSignedNum(4, 1, AZ, 5);
OLED_ShowSignedNum(2, 8, GX, 5);
OLED_ShowSignedNum(3, 8, GY, 5);
OLED_ShowSignedNum(4, 8, GZ, 5);
}
}
优化死循环
超时退出机制,防止卡死
cs
void MPU6050_WaitEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
uint32_t TimeOut = 10000;
while(I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS)
{
TimeOut--;
if(TimeOut == 0)
{
break;
}
}
}
将读写时序函数里的while全部替换
cs
//指定地址写时序
void MPU6050_WriteReg(uint8_t RegAddRess, uint8_t Data)
{
//生成起始条件
I2C_GenerateSTART(I2C2, ENABLE);
//等待EV5事件到来,检查EV5事件
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
//发送从机地址 方向为发送
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
//等待事件 EV6
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
//写入DR,发送数据
I2C_SendData(I2C2, RegAddRess);
//等待事件 EV8
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
//发送数据
I2C_SendData(I2C2, Data);
//等待事件 EV8_2
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
//终止条件
I2C_GenerateSTOP(I2C2, ENABLE);
}
//指定地址读时序
uint8_t MPU6050_ReadReg(uint8_t RegAddRess)
{
uint8_t Data;
//起始条件
I2C_GenerateSTART(I2C2, ENABLE);
//等待事件 EV5
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
//发送从机地址 方向为发送
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Transmitter);
//等待事件 EV6
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
//发送寄存器地址
I2C_SendData(I2C2, RegAddRess);
//等待事件 EV8_2
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
//重复起始条件
I2C_GenerateSTART(I2C2, ENABLE);
//等待事件 EV5
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
//发送从机地址 方向为接收
I2C_Send7bitAddress(I2C2, MPU6050_ADDRESS, I2C_Direction_Receiver);
//等待事件 EV6
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
//配置ACK位
I2C_AcknowledgeConfig(I2C2, DISABLE);
//终止条件
I2C_GenerateSTOP(I2C2, ENABLE);
//等待事件 EV7
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);
//读取DR
Data = I2C_ReceiveData(I2C2);
I2C_AcknowledgeConfig(I2C2, ENABLE);
return Data;
}
![](https://i-blog.csdnimg.cn/direct/18c17f9fb40044f9ab380304e2ccd1e5.jpeg)