【已验证】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的分享

相关推荐
是翔仔呐2 小时前
第10章 串口通信USART全解:轮询/中断/DMA三种收发模式与上位机通信实战
c语言·开发语言·stm32·单片机·嵌入式硬件·学习·gitee
17(无规则自律)2 小时前
深度剖析Linux Input子系统(1):宏观架构与核心原理
linux·嵌入式硬件
lingzhilab3 小时前
零知IDE——STM32驱动ICM20948九轴姿态角解算(上位机演示+数据导出)
stm32·单片机·嵌入式硬件
SUNNYSPY00111 小时前
65R135 -ASEMI超结MOS管TO-220封装
单片机
jacklood12 小时前
基于STM32的车载振动曲线摆件创意设计
stm32·单片机·嵌入式硬件
jomoly12 小时前
星闪NL002开发板测评+匆匆
单片机·嵌入式硬件
17(无规则自律)14 小时前
【Linux驱动实战】:标准的按键控制LED驱动写法
linux·驱动开发·嵌入式硬件
森利威尔电子-15 小时前
森利威尔SL3180替换LM5013 100V降压3.3V 5V 12V恒压芯片
单片机·嵌入式硬件·集成电路·芯片·电源芯片
Net_Walke15 小时前
ESP32开发:5分钟之内添加ST7735驱动构建LVGL模板工程
单片机·物联网·iot