cpp
//MPU6050
#include "stm32f10x.h" // Device header
#include "MPU6050_Reg.h"
#define MPU6050_ADDRESS 0xD0
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;
}
}
}
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);
}
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);
MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);
Data =I2C_ReceiveData(I2C2);
I2C_GenerateSTOP(I2C2,ENABLE);
I2C_AcknowledgeConfig(I2C2,ENABLE);
return Data;
}
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_Ack=I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed=100000;
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);
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);
}
uint8_t MPU6050_GetID(void)
{
return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}
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;
}
1.硬件I2C区别于软件I2C,我们不需要再操作SCL,SDA,只需要像操作其他外设那样配置好参数,至于电平的变换,硬件自己会做,不需要我们关注。
2.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;
}
}
}
硬件I2C用I2C_CheckEvent,检查事件是否完成,这里给他加了一个超时保护封装。
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时,除了开始和终止,和软件一样有三步,发送设备地址,发送寄存器地址,发送数据。
I2C_EVENT_MASTER_MODE_SELECT:STM32被选为主机
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED:STM32被选为主机且处于发送模式
I2C_EVENT_MASTER_BYTE_TRANSMITTING:STM32被选为主机且正在发送数据
I2C_EVENT_MASTER_BYTE_TRANSMITTED:STM32被选为主机且发送数据完成
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;
}
读寄存器的流程是开始I2C通信,发送设备地址(写),发送寄存器地址,重新开始,发送设备地址(读),关闭应答,结束I2C通信,等待数据接收,后存入Data,打开应答
I2C开始后,无论读写都要先发送地址,把指针放到寄存器的位置上,在读的时候,需要重新开启,改变方向为读.
由于我们这里每次都只读一个字节,所以在找到地址后,需要关闭应答,不然它默认是开启应答,MPU6050还会继续发送,
谁接收数据谁发送应答,在读的时候,MPU6050发送数据,STM32接收,所以是STM32发送还要不要继续接收的应答.
一定是先关应答,后读数,如果反过来,读完数了,再关应答,从机下一组数已经到了,主机却不想要了,会导致主机从机的状态机不一致,混乱。
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);
Delay_ms(100);
}
每隔100ms做一次取数显示,其实取数加显示应该是30ms左右,我试过10ms,结果是数不动了,有时候还全是0,这里不知道为什么,deepseek也不能说准,以后有设备再排查吧