一:MPU6050简介
输出一个随姿态变化而变化的电压,想要量化电压,就得使用ADC转化
欧拉角
偏航角(Yaw):也叫航向角,通常是绕 z 轴旋转的角度,以 x 轴正向为起始边,旋转后 x 轴在 xOy 平面上的投影与起始边的夹角就是偏航角,范围一般是 [-π, π] 。例如,在飞机飞行中,偏航角表示飞机机头相对于初始航向的左右偏转角度。
俯仰角(Pitch):是绕 y 轴旋转的角度,以 x 轴正向为起始边,旋转后 x 轴与 xOz 平面的夹角就是俯仰角,范围一般是 [-π/2, π/2] 。对于飞机来说,俯仰角反映飞机机头的上下仰俯程度。
滚转角(Roll):绕 x 轴旋转的角度,以 y 轴正向为起始边,旋转后 y 轴与 yOz 平面的夹角就是滚转角,范围一般是 [-π, π] 。比如飞机飞行时,机翼的倾斜状态就由滚转角体现。
加速度计具有静态稳定性,不具备动态稳定性
陀螺仪具有动态稳定性,不具有静态稳定性
两组数据相互融合,就可以得到姿态角
参数
0X68为从机地址,左移一位 再 按位或上读写位(1/0)
把0X68左移一位后的数据作为,从机地址0XD0
读0XD0 或上0X01记0XD1为读
写 0XD0 或上 0x00 记0XD0 为写,就是把读写位融入从机地址
硬件电路图
通信引脚(SDA/SCL、XDA/XCL)
SDA/SCL:主 I2C 总线,直连主机(如 STM32),支持挂载多设备(如磁场传感器),简化拓扑。
XDA/XCL:从 I2C 总线,用于级联从设备,因控制复杂、效率低,实际少用,优先选 “多设备共 SDA/SCL” 方案。
XCL 和XDA通常用于外接磁力计,或气压计,主机能直接读取数据
地址配置(AD0)
7 位从机地址由 AD0
电平决定:
AD0=0
(默认下拉)→ 地址0x68
(二进制1101000
);AD0=1
(接 VCC)→ 地址0x69
(二进制1101001
)。- 可通过改
AD0
电平,实现同一总线挂多个 MPU6050(需硬件改引脚)。
中断引脚(INT)
- 功能丰富:支持 “数据就绪、I2C 错误、自由落体、零运动检测” 等事件触发。
- 价值:主机无需轮询寄存器,靠中断快速响应,适合低功耗 / 高实时性场景(如运动控制、传感器融合)。
供电逻辑(VDD、VCC-5V、LDO)
- VDD:核心供电(2.375 - 3.46V),需精准稳压,不可直连 5V。
- VCC-5V:宽压输入(3.3 - 5V),经板载 LDO 转 3.3V 供内部电路,适配不同电源环境。
内部框图
陀螺仪内部是需要高电压支持的所以,用了电荷泵进行升压
时钟源一般选择内置时钟源,或者陀螺仪内部晶振时钟
由于电容的电荷量少,所以需要充电和放电的过程来回转化,就可以持续稳定升压,再经过滤波器,就得到稳定的10v电压
使用
写字节时,要先解除睡眠模式
寄存器
运动传感器
SMPLRT_DIV:采样率分频器 ,用于设置传感器数据输出的采样率分频系数,SMPLRT_DIV[7:0]表示该寄存器是 8 位可读写(RW)的,通过设置不同数值调整采样率。
CONFIG:配置 ,EXT_SYNC_SET[2:0]用于设置外部同步输入的配置,DLPF_CFG[2:0]是数字低通滤波器(Digital Low Pass Filter )配置,可设定滤波特性来处理信号噪声等。
GYRO_CONFIG:陀螺仪配置 ,FS_SEL[1:0]用于选择陀螺仪的满量程范围(Full Scale Select ),决定陀螺仪可测量的角速度范围。
ACCEL_CONFIG:加速度计配置 ,XA_ST、YA_ST、ZA_ST分别是 X、Y、Z 轴的自测试(Self - Test )使能位;AFS_SEL[1:0]选择加速度计的满量程范围(Accelerometer Full Scale Select );ACCEL_HPF[2:0]是加速度计高通滤波器(High Pass Filter )配置,用于过滤低频信号。
惯性测量单元(如 MPU6050 等传感器)的寄存器映射表
加速度计数据寄存器:ACCEL_XOUT_H/L、ACCEL_YOUT_H/L、ACCEL_ZOUT_H/L ,分别存储 X、Y、Z 轴加速度测量值的高 8 位和低 8 位,拼接成 16 位数据反映加速度大小 。
温度传感器寄存器:TEMP_OUT_H/L ,存储温度测量值的高、低 8 位,组合为 16 位数据表示芯片温度 .
陀螺仪数据寄存器:GYRO_XOUT_H/L、GYRO_YOUT_H/L、GYRO_ZOUT_H/L ,分别存储 X、Y、Z 轴角速度测量值的高、低 8 位,拼接成 16 位数据体现角速度情况 ,这些寄存器用于读取传感器采集的运动、温度数据 。
电源管理寄存器
PWR_MGMT_1(电源管理 1):可读写(RW),DEVICE_RESET用于设备复位;SLEEP控制睡眠模式;CYCLE使能循环模式;TEMP_DIS用于关闭温度传感器;CLKSEL[2:0]选择系统时钟源 。
PWR_MGMT_2(电源管理 2):可读写(RW),LP_WAKE_CTRL[1:0]配置低功耗唤醒控制;STBY_XA、STBY_YA、STBY_ZA分别使能加速度计 X、Y、Z 轴待机;STBY_XG、STBY_YG、STBY_ZG分别使能陀螺仪 X、Y、Z 轴待机 ,用于灵活控制传感器各轴的功耗状态 。
设备 ID 寄存器
WHO_AM_I:只读(R)寄存器,WHO_AM_[6:1]存储设备自身的标识 ID ,用于主机通过 I2C 等总线读取,识别设备型号、判断设备是否正常连接,是传感器通信初始化时常用的 “设备身份确认” 寄存器 。
二:I2C
物理层特性
I2C 协议仅需要两根线即可实现通信:
- SDA(Serial Data Line):串行数据线
- SCL(Serial Clock Line):串行时钟线
这两根线都需要通过上拉电阻连接到电源,因此当总线上的所有设备都不驱动总线时,总线会保持高电平状态。这种设计使得多个设备可以共享同一总线,实现多主多从的通信架构。
数据传输格式
I2C 通信以字节(8 位)为基本单位进行数据传输,每个字节后面会跟随一个应答位(ACK/NACK)。数据传输时,最高位(MSB)先发送。
通信流程通常包括:
- 起始信号(Start Condition)
- 从设备地址(7 位或 10 位)+ 读写位
- 应答位(ACK/NACK)
- 数据传输
- 停止信号(Stop Condition)
硬件
时序图
起始信号的核心是 “当 SCL 为高电平时,SDA 出现下降沿(从高到低的跳变)”。要产生这个下降沿,必须先让 SDA 处于高电平状态,再在 SCL 保持高电平期间将 SDA 拉低。
停止信号(Stop):当 SCL 为高电平时,SDA 由低电平变为高电平(上升沿),表示通信结束。
void MyI2C_Start(void)
{MyI2C_W_SDA(1);MyI2C_W_SCL(1);MyI2C_W_SDA(0);MyI2C_W_SCL(0);
}
void MyI2C_Stop(void)
{MyI2C_W_SDA(0);MyI2C_W_SCL(1);MyI2C_W_SDA(1);
}
该函数通过循环逐位发送 8 位数据:先通过位运算将当前位输出到 SDA 线,再拉高 SCL 让从机读取,最后拉低 SCL 准备下一位,按 I2C 时序完成 1 字节传输。
void MyI2C_SendByte(uint8_t Byte)
{uint8_t i;for(i=0;i<8;i++){//传递8位数据,这样写方便MyI2C_W_SDA(Byte & (0x80>>i));MyI2C_W_SCL(1);MyI2C_W_SCL(0);}
}
整个过程遵循 I2C 时序:SCL 高电平时读取 SDA 数据,低电平时准备下一位,确保数据按位(高位优先)正确接收。
uint8_t MyI2C_ReceiveByte(void)
{uint8_t i,Byte=0x00;MyI2C_W_SDA(1);//先释放for(i=0;i<8;i++){MyI2C_W_SCL(1);if(MyI2C_R_SDA()==1) {Byte |=(0x80 >>i);}MyI2C_W_SCL(0);}return Byte;
}
MyI2C_SendAck(uint8_t AckByte)
:发送应答信号:每传输 1 字节数据后,接收方必须发送应答信号。若发送 “非应答”(1),通常表示数据传输结束或接收失败。
MyI2C_ReceiveAck(void)
:接收应答信号AckByte
为 0 时表示接收成功,为 1 时表示接收失败或需终止传输。
void MyI2C_SendAck(uint8_t AckByte)
{MyI2C_W_SDA(AckByte);MyI2C_W_SCL(1);MyI2C_W_SCL(0);
}
uint8_t MyI2C_ReceiveAck(void)
{uint8_t i,AckByte=0x00;MyI2C_W_SDA(1);//先释放MyI2C_W_SCL(1);AckByte=MyI2C_R_SDA();MyI2C_W_SCL(0);return AckByte;
}
三:MPU6050的逻辑
整个过程遵循 I2C “主设备写从设备” 的标准流程:起始信号→设备地址(写)→应答→寄存器地址→应答→数据→应答→停止信号,确保数据准确写入 MPU6050 的目标寄存器
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS);MyI2C_ReceiveAck();MyI2C_SendByte(RegAddress);MyI2C_ReceiveAck();MyI2C_SendByte(Data);MyI2C_ReceiveAck();MyI2C_Stop();
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS);MyI2C_ReceiveAck();MyI2C_SendByte(RegAddress);MyI2C_ReceiveAck();MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS | 0x01);MyI2C_ReceiveAck();Data = MyI2C_ReceiveByte();MyI2C_SendAck(1);MyI2C_Stop();return Data;
}
初始化
配置完后的检测的数据都放到了相应的寄存器中
最后直接调用寄存器
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;
}