六轴传感器模块 · STM32F103C8T6 · HAL库开发
MPU6050 六轴运动追踪传感器工作原理与核心功能
MPU6050 是 InvenSense 公司推出的六轴运动追踪传感器,内部集成了三轴加速度计和三轴陀螺仪,并通过单一的 I2C 接口输出全部六轴数据。
加速度计原理:利用 MEMS(微机电系统)技术,内部为悬臂梁结构的质量块。当外部施加加速度时,质量块产生位移,导致差分电容值变化,通过检测电容变化量计算出三轴加速度。可测量重力加速度方向,用于姿态检测。
陀螺仪原理:利用科里奥利效应(Coriolis Effect),当旋转角速度作用于振动质量块时,会产生与角速度成正比的科里奥利力,导致横向位移,通过电容检测将该位移转换为角速度数据。
数据融合:加速度计在静态下精度高但动态响应差,陀螺仪在动态下精度高但存在漂移。两者互补,可实现对物体姿态的精准追踪。MPU6050 内部还含有 DMP(数字运动处理器),可进行硬件级数据融合。
三轴加速度计测量 X/Y/Z 方向的线性加速度,量程可选 ±2g/±4g/±8g/±16g,本程序设置为 ±16g。
三轴陀螺仪测量 X/Y/Z 轴的旋转角速度,量程可选 ±250/±500/±1000/±2000°/s,本程序设置为 ±2000°/s。
利用加速度计 Y 轴数据计算倾角,通过分段线性映射将 AY 原始值转换为 -90°~+90° 的角度值。
基于陀螺仪数据变化量判断最活跃轴,检测数据跨越中值的现象实现计步,支持 50ms 采样 + 300ms 汇总。
| 引脚号 | 名称 | 功能 | STM32连接 |
|---|---|---|---|
| 1 | VCC | 电源正极(3.3V~5V) | 5V |
| 2 | GND | 电源地 | GND |
| 3 | SCL | I2C 时钟线 | PB12 |
| 4 | SDA | I2C 数据线 | PB13 |
| 5 | XCL | 辅助 I2C 时钟(接扩展传感器) | 未连接 |
| 6 | XDA | 辅助 I2C 数据(接扩展传感器) | 未连接 |
| 7 | AD0 | I2C 地址选择(接GND=0xD0) | GND |
| 8 | INT | 中断输出(数据就绪触发) | 未连接 |
OLED 显示屏引脚连接:SCL → PB15,SDA → PB14(软件模拟 I2C)
GY-521 MPU6050 六轴传感器模块实物外观
电路原理图设计与PCB封装
STM32F103C8T6 HAL库源代码详解
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
OLED_Init(); // 显示屏初始化
MPU6050_Init(); // MPU6050初始化
while (1)
{
if(HAL_GetTick() - Time_Now >= 200) // 200ms更新一次
{
angle = angleGetLoop(); // 获取角度
OLED_Clear(); // 清屏
OLED_Printf(0, 0, OLED_8X16, "AX:%d", AX);
OLED_Printf(0, 16, OLED_8X16, "AY:%d", AY);
OLED_Printf(0, 32, OLED_8X16, "AZ:%d", AZ);
OLED_Printf(64, 0, OLED_8X16, "GX:%d", GX);
OLED_Printf(64, 16, OLED_8X16, "GY:%d", GY);
OLED_Printf(64, 32, OLED_8X16, "GZ:%d", GZ);
OLED_CenterPrintf(48, "%d°", angle);
OLED_Update(); // 更新显示
Time_Now = HAL_GetTick(); // 更新系统时间戳
}
}
}
| 寄存器 | 地址 | 写入值 | 说明 |
|---|---|---|---|
| PWR_MGMT_1 | 0x6B | 0x01 | 唤醒传感器,选择X轴陀螺作为时钟源 |
| PWR_MGMT_2 | 0x6C | 0x00 | 禁用待机,使能所有轴 |
| SMPLRT_DIV | 0x19 | 0x09 | 采样率=1000/(1+9)=100Hz |
| CONFIG | 0x1A | 0x06 | 低通滤波带宽5Hz |
| GYRO_CONFIG | 0x1B | 0x18 | 陀螺仪量程 ±2000°/s |
| ACCEL_CONFIG | 0x1C | 0x18 | 加速度计量程 ±16g |
void MPU6050_I2C_Init(void)
{
if(MPU6050_I2C_SCL_GPIO_PORT == GPIOB) __HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出模式(I2C标准)
GPIO_InitStructure.Pin = MPU6050_I2C_SCL_GPIO_PIN | MPU6050_I2C_SDA_GPIO_PIN;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(MPU6050_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
HAL_GPIO_WritePin(MPU6050_I2C_SCL_GPIO_PORT, MPU6050_I2C_SCL_GPIO_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(MPU6050_I2C_SDA_GPIO_PORT, MPU6050_I2C_SDA_GPIO_PIN, GPIO_PIN_SET);
}
void MPU6050_Init(void)
{
MPU6050_I2C_Init();
MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); // 唤醒,X轴陀螺时钟
MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00); // 禁用待机,使能所有轴
MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); // 采样率=100Hz
MPU6050_WriteReg(MPU6050_CONFIG, 0x06); // 低通滤波5Hz
MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); // 陀螺仪±2000°/s
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); // 加速度计±16g
}
MPU6050 采用软件模拟 I2C 通信,通过 GPIO 开漏输出模式控制 SCL(PB12)和 SDA(PB13)引脚电平。
设备地址为 0xD0(AD0 接 GND),每次读写操作包含:起始信号 → 设备地址 → 寄存器地址 → 数据 → 停止信号。
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
MPU6050_I2C_Start();
MPU6050_I2C_SendByte(MPU6050_ADDRESS); // 设备写地址 0xD0
MPU6050_I2C_ReceiveAck();
MPU6050_I2C_SendByte(RegAddress); // 寄存器地址
MPU6050_I2C_ReceiveAck();
MPU6050_I2C_SendByte(Data); // 写入数据
MPU6050_I2C_ReceiveAck();
MPU6050_I2C_Stop();
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
uint8_t Data;
MPU6050_I2C_Start();
MPU6050_I2C_SendByte(MPU6050_ADDRESS);
MPU6050_I2C_ReceiveAck();
MPU6050_I2C_SendByte(RegAddress);
MPU6050_I2C_ReceiveAck();
MPU6050_I2C_Start(); // 重复起始信号
MPU6050_I2C_SendByte(MPU6050_ADDRESS | 0x01); // 设备读地址
MPU6050_I2C_ReceiveAck();
Data = MPU6050_I2C_ReceiveByte();
MPU6050_I2C_SendAck(1); // 非应答
MPU6050_I2C_Stop();
return Data;
}
通过 I2C 依次读取 6 个寄存器对(高8位+低8位),拼接为 16 位有符号整数,分别对应加速度计 X/Y/Z 和陀螺仪 X/Y/Z 数据。
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;
// 加速度计X轴 (0x3B高 + 0x3C低)
DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
*AccX = (DataH << 8) | DataL;
// 加速度计Y/Z轴、陀螺仪X/Y/Z轴读取方式相同...
// 寄存器地址:AY(0x3D/0x3E) AZ(0x3F/0x40)
// GX(0x43/0x44) GY(0x45/0x46) GZ(0x47/0x48)
}
利用加速度计 Y 轴数据(AY)计算传感器倾角。AY 原始值范围为 [-2080, 2000],通过分段线性映射转换为角度值。
公式1(AY ≥ -65,正倾角方向):
angle = -90 × (AY - (-65)) / (2000 - (-65)) + 2
公式2(AY < -65,负倾角方向):
angle = 90 × (AY - (-65)) / (-2080 - (-65)) + 2
当 AY = -65 时为分界点(angle ≈ 2°),当 AY = 2000 时 angle ≈ -88°,当 AY = -2080 时 angle ≈ -88°。
int angleGetLoop(void)
{
int angle;
MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);
if(AY > 2000) AY = 2000; // 上限钳位
if(AY < -2080) AY = -2080; // 下限钳位
if (AY >= -65)
angle = (-90 * (AY - (-65))) / (2000 - (-65)) + 2;
else
angle = (90 * (AY - (-65))) / (-2080 - (-65)) + 2;
return angle;
}
| 数据项 | 高字节寄存器 | 低字节寄存器 | 分辨率 |
|---|---|---|---|
| 加速度计 X (AX) | 0x3B | 0x3C | ±16g → 4096 LSB/g |
| 加速度计 Y (AY) | 0x3D | 0x3E | ±16g → 4096 LSB/g |
| 加速度计 Z (AZ) | 0x3F | 0x40 | ±16g → 4096 LSB/g |
| 陀螺仪 X (GX) | 0x43 | 0x44 | ±2000°/s → 16.4 LSB/°/s |
| 陀螺仪 Y (GY) | 0x45 | 0x46 | ±2000°/s → 16.4 LSB/°/s |
| 陀螺仪 Z (GZ) | 0x47 | 0x48 | ±2000°/s → 16.4 LSB/°/s |
主程序执行流程
MPU6050 六轴传感器数据模拟与OLED显示
左侧为 MPU6050 传感器模块的 3D 姿态模拟,模块会随时间自动摆动,模拟实际运动中的姿态变化。X/Y/Z 轴标识对应加速度计和陀螺仪的三个测量轴。倾角根据 AY(加速度计Y轴)数据实时计算,采用与程序中相同的分段线性映射公式。
右侧上半部分模拟 0.96 寸 OLED 显示屏,以 200ms 间隔刷新六轴数据和角度值,与实际硬件显示效果一致。下半部分为六轴数据仪表,实时显示 AX/AY/AZ(加速度计)和 GX/GY/GZ(陀螺仪)的数值变化,进度条颜色对应不同轴。