【已验证】STM32F103的MPU6050应用一(驱动篇)

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_WriteHAL_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);
    }
}

五、常见问题与注意事项

  1. I2C 通信失败

    • 检查电源是否为 3.3V

    • 检查上拉电阻是否连接

    • 降低 I2C 速度至 100kHz 再试

  2. 读取的加速度/陀螺仪数据异常

    • 检查量程设置是否与实际转换公式匹配

    • 原始值为有符号数,注意数据类型

  3. 芯片 ID 读取错误

    • 确认 MPU6050 的 AD0 引脚接地(地址 0x68)

    • 和卖家确认是否国产


六、总结

本文提供了一个完整、可复用的 MPU6050 驱动模块,基于 STM32F103 的硬件 I2C 和 HAL 库。该驱动封装了所有底层细节,对外提供简洁的接口,可以方便地集成到各种嵌入式项目中。

希望这篇博客能帮助你快速上手 MPU6050 的开发。如有任何疑问,欢迎在评论区交流讨论。

通过网盘分享的文件:MPU6050_STM32.zip

链接: https://pan.baidu.com/s/1dFjohR0LfL6ihE0rBkuuwQ?pwd=c6gi 提取码: c6gi

--来自百度网盘超级会员v8的分享

相关推荐
悠哉悠哉愿意13 小时前
【物联网学习笔记】TIM
笔记·单片机·嵌入式硬件·物联网·学习
豆包公子13 小时前
AUTOSAR CP故障诊断协议栈DEM(DTC故障管理)裸机实现-实践篇
单片机·嵌入式硬件·车载系统
Wave84514 小时前
STM32+ESP8266 智能手表实战:天气获取与阿里云时钟同步
stm32·阿里云·智能手表
汽车芯猿15 小时前
嵌入式 SHA-256 完全实现(附原码)(无 uint64_t,减少栈使用)
c语言·单片机
进击的小头15 小时前
第12篇:嵌入式核心外设科普:ADC_DAC模拟前端接口原理与典型应用
单片机·嵌入式硬件
水云桐程序员15 小时前
嵌入式系统开发 需要的环境配置
嵌入式硬件·物联网·硬件工程
CHANG_THE_WORLD15 小时前
PE文件解析器详细文档
stm32·单片机·嵌入式硬件
Z文的博客16 小时前
SLCAN工程搭建与实现教程(下)
stm32·单片机·嵌入式·can
老师用之于民16 小时前
【DAY39】Linux 驱动开发关键技术研究:设备树、Input 子系统与 I2C 通信
单片机·嵌入式硬件
发发就是发16 小时前
触摸屏驱动调试手记:从I2C鬼点到坐标漂移的实战录
linux·服务器·驱动开发·单片机·嵌入式硬件