MPU6050 是一款非常经典的六轴惯性测量单元,集成了三轴加速度计和三轴陀螺仪。在嵌入式项目中,我们经常需要通过 I2C 接口读取其数据。本文基于 STM32F103 和 HAL 库,实现一个简洁、可靠的 MPU6050 驱动,并封装成独立的模块,方便后续项目复用。

今天先解决数据获取,后面实现步数记录,姿态判断,可用于老人健康检测系统,宠物防丢系统等
一、硬件连接
| MPU6050 引脚 | STM32F103 引脚 | 说明 |
|---|---|---|
| VCC | 3.3V | 必须 3.3V,不可接5V |
| GND | GND | |
| SCL | PB6 (I2C1_SCL) | 时钟线 |
| SDA | PB7 (I2C1_SDA) | 数据线 |
| AD0 | GND | 设置 I2C 地址为 0x68 |
二、软件设计思路
我们使用 STM32 的硬件 I2C 外设(I2C1),通过 HAL 库提供的 HAL_I2C_Mem_Write 和 HAL_I2C_Mem_Read 函数来访问 MPU6050 的寄存器。驱动模块主要完成以下功能:
-
I2C 引脚初始化
-
MPU6050 芯片初始化(解除休眠、设置采样率、量程、低通滤波等)
-
读取设备 ID(用于检测连接)
-
读取加速度、陀螺仪、温度数据
最后将所有这些功能封装在一个 .c 和 .h 文件中,上层应用只需调用几个简单函数即可获得传感器数据。
三、关键代码解析
1. I2C 引脚与句柄定义
在头文件中定义引脚和 I2C 句柄(静态内部使用),方便移植:
/* I2C 配置(可根据实际硬件修改) */
#define MPU6050_I2C I2C1
#define MPU6050_I2C_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
#define MPU6050_SCL_GPIO_PORT GPIOB
#define MPU6050_SCL_GPIO_PIN GPIO_PIN_6
#define MPU6050_SDA_GPIO_PORT GPIOB
#define MPU6050_SDA_GPIO_PIN GPIO_PIN_7
#define MPU6050_I2C_TIMEOUT 1000
static I2C_HandleTypeDef hi2c_mpu6050; // I2C 句柄
2. I2C 初始化函数
配置 GPIO 为复用开漏输出,然后初始化 I2C 外设:
static void I2C_MPU6050_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
MPU6050_I2C_CLK_ENABLE();
MPU6050_SCL_GPIO_CLK_ENABLE();
MPU6050_SDA_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = MPU6050_SCL_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(MPU6050_SCL_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = MPU6050_SDA_GPIO_PIN;
HAL_GPIO_Init(MPU6050_SDA_GPIO_PORT, &GPIO_InitStruct);
if (HAL_I2C_GetState(&hi2c_mpu6050) == HAL_I2C_STATE_RESET)
{
MPU6050_I2C_FORCE_RESET();
MPU6050_I2C_RELEASE_RESET();
hi2c_mpu6050.Instance = MPU6050_I2C;
hi2c_mpu6050.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c_mpu6050.Init.ClockSpeed = 400000; // 400kHz
hi2c_mpu6050.Init.DutyCycle = I2C_DUTYCYCLE_2;
HAL_I2C_Init(&hi2c_mpu6050);
}
}
3. MPU6050 寄存器读写封装
使用 HAL 库的 HAL_I2C_Mem_Write/Read 函数,并加入简单的错误恢复机制(读写失败时重新初始化 I2C):
static uint8_t MPU6050_WriteReg(uint8_t reg, uint8_t data)
{
HAL_StatusTypeDef status = HAL_I2C_Mem_Write(&hi2c_mpu6050, MPU6050_ADDR_WRITE,
reg, I2C_MEMADD_SIZE_8BIT,
&data, 1, MPU6050_I2C_TIMEOUT);
if (status != HAL_OK) {
HAL_I2C_DeInit(&hi2c_mpu6050);
I2C_MPU6050_Init();
return 1;
}
return 0;
}
static uint8_t MPU6050_ReadRegs(uint8_t reg, uint8_t *buf, uint8_t len)
{
HAL_StatusTypeDef status = HAL_I2C_Mem_Read(&hi2c_mpu6050, MPU6050_ADDR_READ,
reg, I2C_MEMADD_SIZE_8BIT,
buf, len, MPU6050_I2C_TIMEOUT);
if (status != HAL_OK) {
HAL_I2C_DeInit(&hi2c_mpu6050);
I2C_MPU6050_Init();
return 1;
}
return 0;
}
4. MPU6050 初始化
设置采样率、低通滤波、量程等,并解除休眠状态:
void MPU6050_Init(void)
{
I2C_MPU6050_Init();
HAL_Delay(100);
MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x00); // 解除休眠
HAL_Delay(50);
// 采样率 = 8000 / (1 + SMPLRT_DIV) = 125Hz
MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV, 0x07);
// 低通滤波 42Hz
MPU6050_WriteReg(MPU6050_RA_CONFIG, MPU6050_DLPF_BW_42);
// 陀螺仪量程 ±2000°/s
MPU6050_WriteReg(MPU6050_RA_GYRO_CONFIG, MPU6050_GYRO_FS_2000 << 3);
// 加速度计量程 ±8g
MPU6050_WriteReg(MPU6050_RA_ACCEL_CONFIG, MPU6050_ACCEL_FS_8 << 3);
}
5. 数据读取函数
以加速度读取为例,连续读取 6 个字节,合并成三个 16 位有符号数:
void MPU6050_ReadAccel(short *accData)
{
uint8_t buf[6];
MPU6050_ReadRegs(MPU6050_RA_ACCEL_XOUT_H, buf, 6);
accData[0] = (int16_t)((buf[0] << 8) | buf[1]);
accData[1] = (int16_t)((buf[2] << 8) | buf[3]);
accData[2] = (int16_t)((buf[4] << 8) | buf[5]);
}
陀螺仪和温度读取类似,温度转换公式为:Temp(°C) = (原始值 / 340.0) + 36.53。
四、使用示例
在主函数中调用:
#include "mpu6050_driver.h"
int main(void)
{
HAL_Init();
SystemClock_Config(); // 72MHz
MX_USART1_UART_Init(); // 用于打印
MPU6050_Init();
if (MPU6050_ReadID()) {
printf("MPU6050 found!\r\n");
} else {
printf("MPU6050 not found!\r\n");
while(1);
}
while (1) {
short acc[3], gyro[3];
float temp;
MPU6050_ReadAccel(acc);
MPU6050_ReadGyro(gyro);
MPU6050_ReturnTemp(&temp);
printf("Acc: %d, %d, %d Gyro: %d, %d, %d Temp: %.2f\r\n",
acc[0], acc[1], acc[2], gyro[0], gyro[1], gyro[2], temp);
HAL_Delay(100);
}
}
五、常见问题与注意事项
-
I2C 通信失败
-
检查电源是否为 3.3V
-
检查上拉电阻是否连接
-
降低 I2C 速度至 100kHz 再试
-
-
读取的加速度/陀螺仪数据异常
-
检查量程设置是否与实际转换公式匹配
-
原始值为有符号数,注意数据类型
-
-
芯片 ID 读取错误
-
确认 MPU6050 的 AD0 引脚接地(地址 0x68)
-
和卖家确认是否国产
-
六、总结
本文提供了一个完整、可复用的 MPU6050 驱动模块,基于 STM32F103 的硬件 I2C 和 HAL 库。该驱动封装了所有底层细节,对外提供简洁的接口,可以方便地集成到各种嵌入式项目中。

希望这篇博客能帮助你快速上手 MPU6050 的开发。如有任何疑问,欢迎在评论区交流讨论。
通过网盘分享的文件:MPU6050_STM32.zip
链接: https://pan.baidu.com/s/1dFjohR0LfL6ihE0rBkuuwQ?pwd=c6gi 提取码: c6gi
--来自百度网盘超级会员v8的分享