MPU6050是一个6轴姿态传感器,由三个陀螺仪和三个加速度传感器组成。可以测量芯片自身X、Y、Z轴的加速度、角速度参数。通过数据融合,可进一步得到姿态角,常应用于平衡车、飞控等。

SCL时钟线,SDA数据线不必多说。
【问】XDA和XCL是什么??
辅助I2C连接其他器件,比如说电磁传感器,成为一个九轴传感器。
【AD0】地址管脚:连接GND时为0,此时从机地址068。连VCC时为1,从机地址0x69。
【INT】中断引脚。
平常MPU6050作为从机,只需要四个引脚VCC、GND、SCL和SDA就够了。
然后我们再过一遍STM32软件模拟IIC代码:
- //I2C写SCL引脚电平
- void MyI2C_W_SCL(uint8_t BitValue)
- {
- GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
- Delay_us(10);
- }
-
- //I2C写SDA引脚电平
- void MyI2C_W_SDA(uint8_t BitValue)
- {
- GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue); //根据BitValue,设置SDA引脚的电平,BitValue要实现非0即1的特性
- Delay_us(10); //延时10us,防止时序频率超过要求
- }
-
- //I2C读SDA引脚电平
- uint8_t MyI2C_R_SDA(void)
- {
- uint8_t BitValue;
- BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11); //读取SDA电平
- Delay_us(10); //延时10us,防止时序频率超过要求
- return BitValue; //返回SDA电平
- }
-
- //I2C初始化
- void MyI2C_Init(void)
- {
- /*开启时钟*/
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
-
- /*GPIO初始化*/
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB10和PB11引脚初始化为开漏输出
-
- /*设置默认电平*/
- GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11); //设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
- }
-
- //I2C起始
- void MyI2C_Start(void)
- {
- MyI2C_W_SDA(1); //释放SDA,确保SDA为高电平
- MyI2C_W_SCL(1); //释放SCL,确保SCL为高电平
- MyI2C_W_SDA(0); //在SCL高电平期间,拉低SDA,产生起始信号
- MyI2C_W_SCL(0); //起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
- }
-
- //I2C终止
- void MyI2C_Stop(void)
- {
- MyI2C_W_SDA(0); //拉低SDA,确保SDA为低电平
- MyI2C_W_SCL(1); //释放SCL,使SCL呈现高电平
- MyI2C_W_SDA(1); //在SCL高电平期间,释放SDA,产生终止信号
- }
-
- //I2C发送一个字节
- void MyI2C_SendByte(uint8_t Byte)
- {
- uint8_t i;
- for (i = 0; i < 8; i ++) //循环8次,主机依次发送数据的每一位
- {
- MyI2C_W_SDA(Byte & (0x80 >> i)); //使用掩码的方式取出Byte的指定一位数据并写入到SDA线
- MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间读取SDA
- MyI2C_W_SCL(0); //拉低SCL,主机开始发送下一位数据
- }
- }
-
- //I2C接收一个字节
- uint8_t MyI2C_ReceiveByte(void)
- {
- uint8_t i, Byte = 0x00; //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
- MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送
- for (i = 0; i < 8; i ++) //循环8次,主机依次接收数据的每一位
- {
- MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA
- if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);} //读取SDA数据,并存储到Byte变量
- //当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0
- MyI2C_W_SCL(0); //拉低SCL,从机在SCL低电平期间写入SDA
- }
- return Byte; //返回接收到的一个字节数据
- }
-
- //I2C发送应答位
- void MyI2C_SendAck(uint8_t AckBit)
- {
- MyI2C_W_SDA(AckBit); //主机把应答位数据放到SDA线
- MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间,读取应答位
- MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块
- }
-
- //I2C接收应答位
- uint8_t MyI2C_ReceiveAck(void)
- {
- uint8_t AckBit; //定义应答位变量
- MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送
- MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA
- AckBit = MyI2C_R_SDA(); //将应答位存储到变量里
- MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块
- return AckBit; //返回定义应答位变量
- }
PB10 - SDA
PB11 - SCL
- void MyI2C_Init(void)
- {
- /*开启时钟*/
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
-
- /*GPIO初始化*/
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure); //PB10和PB11引脚初始化为开漏输出
-
- GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11); //设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
- }
- void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
- {
- MyI2C_Start(); //I2C起始
- MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入
- MyI2C_ReceiveAck(); //接收应答
- MyI2C_SendByte(RegAddress); //发送寄存器地址
- MyI2C_ReceiveAck(); //接收应答
- MyI2C_SendByte(Data); //发送要写入寄存器的数据
- MyI2C_ReceiveAck(); //接收应答
- MyI2C_Stop(); //I2C终止
- }
- uint8_t MPU6050_ReadReg(uint8_t RegAddress)
- {
- uint8_t Data;
-
- MyI2C_Start(); //I2C起始
- MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入
- MyI2C_ReceiveAck(); //接收应答
- MyI2C_SendByte(RegAddress); //发送寄存器地址
- MyI2C_ReceiveAck(); //接收应答
-
- MyI2C_Start(); //I2C重复起始
- MyI2C_SendByte(MPU6050_ADDRESS | 0x01); //发送从机地址,读写位为1,表示即将读取
- MyI2C_ReceiveAck(); //接收应答
- Data = MyI2C_ReceiveByte(); //接收指定寄存器的数据
- MyI2C_SendAck(1); //发送应答,给从机非应答,终止从机的数据输出
- MyI2C_Stop(); //I2C终止
-
- return Data;
- }
- #define MPU6050_SMPLRT_DIV 0x19
- #define MPU6050_CONFIG 0x1A
- #define MPU6050_GYRO_CONFIG 0x1B
- #define MPU6050_ACCEL_CONFIG 0x1C
-
- #define MPU6050_ACCEL_XOUT_H 0x3B
- #define MPU6050_ACCEL_XOUT_L 0x3C
- #define MPU6050_ACCEL_YOUT_H 0x3D
- #define MPU6050_ACCEL_YOUT_L 0x3E
- #define MPU6050_ACCEL_ZOUT_H 0x3F
- #define MPU6050_ACCEL_ZOUT_L 0x40
- #define MPU6050_TEMP_OUT_H 0x41
- #define MPU6050_TEMP_OUT_L 0x42
- #define MPU6050_GYRO_XOUT_H 0x43
- #define MPU6050_GYRO_XOUT_L 0x44
- #define MPU6050_GYRO_YOUT_H 0x45
- #define MPU6050_GYRO_YOUT_L 0x46
- #define MPU6050_GYRO_ZOUT_H 0x47
- #define MPU6050_GYRO_ZOUT_L 0x48
-
- #define MPU6050_PWR_MGMT_1 0x6B
- #define MPU6050_PWR_MGMT_2 0x6C
- #define MPU6050_WHO_AM_I 0x75
-
- void MPU6050_Init(void)
- {
- MyI2C_Init(); //先初始化底层的I2C
-
- /*MPU6050寄存器初始化,需要对照MPU6050手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/
- MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); //电源管理寄存器1,取消睡眠模式,选择时钟源为X轴陀螺仪
- MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00); //电源管理寄存器2,保持默认值0,所有轴均不待机
- MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); //采样率分频寄存器,配置采样率
- MPU6050_WriteReg(MPU6050_CONFIG, 0x06); //配置寄存器,配置DLPF
- MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); //陀螺仪配置寄存器,选择满量程为±2000°/s
- MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); //加速度计配置寄存器,选择满量程为±16g
- }
- 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; //定义数据高8位和低8位的变量
-
- DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H); //读取加速度计X轴的高8位数据
- DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L); //读取加速度计X轴的低8位数据
- *AccX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
-
- DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H); //读取加速度计Y轴的高8位数据
- DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L); //读取加速度计Y轴的低8位数据
- *AccY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
-
- DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H); //读取加速度计Z轴的高8位数据
- DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L); //读取加速度计Z轴的低8位数据
- *AccZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
-
- DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //读取陀螺仪X轴的高8位数据
- DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L); //读取陀螺仪X轴的低8位数据
- *GyroX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
-
- DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //读取陀螺仪Y轴的高8位数据
- DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L); //读取陀螺仪Y轴的低8位数据
- *GyroY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
-
- DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //读取陀螺仪Z轴的高8位数据
- DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L); //读取陀螺仪Z轴的低8位数据
- *GyroZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
- }
MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ); //获取MPU6050的数据