一、MPU6050初始化
1、开启对应时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
2、配置GPIO
GPIO_InitTypeDef GPIO_InitStructure1;
GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure1.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure1.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure1);
3、初始化使能IIC
I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
//stm32作为从机时才使用
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 50000;
//时钟占空比:只有在时钟频率大于100KHz,进入到快速状态时才有用,在小于等于100KHz的标准速度下,占空比是固定的1:1
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_Init(I2C2, &I2C_InitStructure);
I2C_Cmd(I2C2, ENABLE);
4、初始化MPU6050
//对MPU6050硬件电路进行初始化配置
//芯片的写寄存器功能,需要解除芯片的睡眠模式,否则写入是无效的
//睡眠模式 是电源管理寄存器1 的SLEEP控制的,写入0x00,解除睡眠模式,该寄存器地址为 0x6B;
//解除睡眠,选择陀螺仪时钟
MPU6050_Write_Reg(MPU6050_PWR_MGMT_1, 0x01);
//6 轴均不待机
MPU6050_Write_Reg(MPU6050_PWR_MGMT_2, 0x00);
//采样分频为 10
MPU6050_Write_Reg(MPU6050_SMPLRT_DIV, 0x09);
//滤波参数给最大
MPU6050_Write_Reg(MPU6050_CONFIG, 0x06);
//陀螺仪和下面加速度计都选择最大量程
MPU6050_Write_Reg(MPU6050_GYRO_CONFIG, 0x18);
MPU6050_Write_Reg(MPU6050_ACCEL_CONFIG, 0x18);
二、超时退出
注:硬件I2C,需要等待标志位判定成功后,再进行下一位,程序中出现了大量的while死循环等待,在程序中是比较危险的,一旦有一个事件一直没有产生,就会让整个程序卡死,对于死循环等待,可以加一个超时退出机制
//超时退出函数,里面封装了I2C_CheckEvent()
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;
}
}
}
三、指定地址写
void MPU6050_Write_Reg(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);
//这里不需要等待 EV8_1 事件
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);
}
四、指定地址读
uint8_t MPU6050_Read_Reg(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);
//这里不需要等待 EV8_1 事件
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);
//注, 再接收一个字节数据时(接收最后一个字节时,需要提前先设置ack 和 stop,再接收数据)
I2C_AcknowledgeConfig(I2C2, DISABLE);
I2C_GenerateSTOP(I2C2, ENABLE);
//再等待EV7事件之后,再读取 DR 获取数据
MPU6050_WaitEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);
data = I2C_ReceiveData(I2C2);
//接收完成后 ack 置 1(默认状态 ack 就是1 给从机应答,
//在最后一个字节之前,临时将 ack 置 0,给非应答,所以在接收函数的最后需要恢复 默认的 ack = 1)
//这样做是为了方便指定地址收多个字节
I2C_AcknowledgeConfig(I2C2, ENABLE);
return data;
}
其他操作参考上一节