玩转 I2C 之驱动 MPU6050 及姿态解算

✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进

❤欢迎关注我的知乎:对error视而不见

代码获取、问题探讨及文章转载可私信。

☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。

🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇

点击领取更多详细资料

一、引言

在许多嵌入式系统和机器人项目中,姿态解算是非常重要的一环。MPU6050 是一款集成了三轴加速度计和三轴陀螺仪的传感器,能够提供设备的加速度和角速度信息。而 I2C(Inter - Integrated Circuit)是一种常用的串行通信协议,MPU6050 通过 I2C 接口与微控制器进行通信。本文将详细介绍如何使用 I2C 驱动 MPU6050 传感器,并进行姿态解算。

二、MPU6050 简介

2.1 功能概述

MPU6050 是 InvenSense 公司推出的一款 6 轴运动处理组件,内部集成了三轴 MEMS 陀螺仪、三轴 MEMS 加速度计,以及一个可扩展的数字运动处理器 DMP(Digital Motion Processor)。它可以提供高精度的运动数据,广泛应用于无人机、智能手环、机器人等领域。

2.2 通信接口

MPU6050 支持 I2C 通信协议,其默认的 I2C 地址为 0x68(不考虑 AD0 引脚的情况下)。通过 I2C 接口,微控制器可以向 MPU6050 发送命令并读取传感器数据。

三、I2C 通信原理

3.1 基本概念

I2C 是一种双线制的串行通信协议,使用两根线进行通信:SDA(Serial Data)用于数据传输,SCL(Serial Clock)用于时钟同步。I2C 总线上可以连接多个设备,每个设备都有一个唯一的地址。

3.2 通信过程

I2C 通信过程包括起始条件、设备地址传输、寄存器地址传输、数据传输和停止条件。具体步骤如下:

  1. 起始条件:SDA 线在 SCL 线为高电平时由高电平变为低电平,表示通信开始。
  2. 设备地址传输:发送设备的 7 位地址和 1 位读写位(0 表示写,1 表示读)。
  3. 寄存器地址传输:如果是写操作,需要指定要写入的寄存器地址;如果是读操作,也需要先指定要读取的寄存器地址。
  4. 数据传输:根据读写操作,进行数据的写入或读取。
  5. 停止条件:SDA 线在 SCL 线为高电平时由低电平变为高电平,表示通信结束。

四、硬件连接

将 MPU6050 与 STM32 开发板进行连接,连接方式如下:

MPU6050 引脚STM32 引脚
VCC3.3V
GNDGND
SDASTM32 的 I2C_SDA(例如 PB7)
SCLSTM32 的 I2C_SCL(例如 PB6)
AD0可接 GND 或 VCC,用于选择 I2C 地址

五、代码实现

5.1 初始化 I2C 接口

#include "stm32f1xx_hal.h"

I2C_HandleTypeDef hi2c1;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);

void MX_I2C1_Init(void) {
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000;
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
        Error_Handler();
    }
}

5.2 初始化 MPU6050

#define MPU6050_ADDR 0x68 << 1

void MPU6050_Init(void) {
    uint8_t data;

    // 唤醒 MPU6050
    data = 0x00;
    HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x6B, 1, &data, 1, HAL_MAX_DELAY);

    // 设置陀螺仪量程为 ±2000°/s
    data = 0x00;
    HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x1B, 1, &data, 1, HAL_MAX_DELAY);

    // 设置加速度计量程为 ±2g
    data = 0x00;
    HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x1C, 1, &data, 1, HAL_MAX_DELAY);
}

5.3 读取 MPU6050 数据

void MPU6050_ReadData(int16_t *ax, int16_t *ay, int16_t *az, int16_t *gx, int16_t *gy, int16_t *gz) {
    uint8_t buffer[14];

    HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, 0x3B, 1, buffer, 14, HAL_MAX_DELAY);

    *ax = (buffer[0] << 8) | buffer[1];
    *ay = (buffer[2] << 8) | buffer[3];
    *az = (buffer[4] << 8) | buffer[5];
    *gx = (buffer[8] << 8) | buffer[9];
    *gy = (buffer[10] << 8) | buffer[11];
    *gz = (buffer[12] << 8) | buffer[13];
}

5.4 主函数

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();

    MPU6050_Init();

    int16_t ax, ay, az, gx, gy, gz;

    while (1) {
        MPU6050_ReadData(&ax, &ay, &az, &gx, &gy, &gz);

        // 这里可以进行姿态解算,例如使用互补滤波算法
        // 简单示例:打印数据
        printf("Acc: %d %d %d, Gyro: %d %d %d\r\n", ax, ay, az, gx, gy, gz);

        HAL_Delay(100);
    }
}

六、姿态解算

6.1 原理

姿态解算的目的是根据 MPU6050 提供的加速度和角速度数据,计算出设备的姿态(如欧拉角:俯仰角、横滚角、偏航角)。常用的姿态解算算法有互补滤波算法、卡尔曼滤波算法等。

6.2 互补滤波算法示例

#define PI 3.14159265358979323846

float pitch, roll;

void ComplementaryFilter(int16_t ax, int16_t ay, int16_t az, int16_t gx, int16_t gy, int16_t gz, float dt) {
    float accel_pitch, accel_roll;
    float gyro_pitch_rate = (float)gx / 131.0;
    float gyro_roll_rate = (float)gy / 131.0;

    // 计算加速度计的俯仰角和横滚角
    accel_pitch = atan2(ay, az) * 180 / PI;
    accel_roll = atan2(-ax, sqrt(ay * ay + az * az)) * 180 / PI;

    // 互补滤波
    pitch = 0.98 * (pitch + gyro_pitch_rate * dt) + 0.02 * accel_pitch;
    roll = 0.98 * (roll + gyro_roll_rate * dt) + 0.02 * accel_roll;
}

七、总结

通过以上步骤,我们实现了使用 I2C 驱动 MPU6050 传感器,并进行了简单的姿态解算。在实际应用中,可以根据具体需求对代码进行优化和扩展,例如使用更复杂的姿态解算算法、添加数据滤波等。同时,要注意 I2C 通信的稳定性和数据的准确性,确保系统的可靠性。

### 使用 HAL 库 实现软件 I2C驱动 MPU6050 并进行 DMP 姿态 为了使用 HAL 库实现软件 I2C 驱动 MPU6050 传感器并完成 DMP 姿态,需按照如下方法配置和编写代码。 #### 初始化项目环境 在 STM32CubeMX 中创建新工程,选择目标 MCU 型号(如 STM32F103RCT6),使能 GPIO 口作为软件 I2C 接口,并确保 UART1 已被激活以便于调试输出[^1]。 #### 定义宏定义 在 Keil IDE 的编译选项里加入特定宏定义 `STM32F103_DMP` 和 `MPL_LOG_NDEBUG=1`,这有助于优化程序性能以及支持 MPU6050 设备特性[^2]。 #### 编写初始化函数 下面是一个简单的初始化函数示例: ```c #include "stm32f1xx_hal.h" #include "mpu6050_dmp_driver.h" // 软件I2C引脚定义 #define SDA_PIN GPIO_PIN_7 #define SCL_PIN GPIO_PIN_6 #define I2C_PORT GPIOB void Soft_IIC_Init(void){ __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; // 设置SCL/SDA为开漏输出模式 GPIO_InitStruct.Pin = SDA_PIN | SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(I2C_PORT, &GPIO_InitStruct); } ``` 此段代码完成了对用于模拟 I2C 总线通信所需 GPIO 引脚的设置工作。注意这里选择了 PB6 和 PB7 分别作为 SCL 和 SDA 线路,在实际应用中可根据具体需求调整这些参数值。 #### 开发主循环逻辑 接下来展示一段包含启动 MPU6050、校准 DMP 单元并将获取到的姿态信息打印出来的主循环片段: ```c int main(void) { HAL_Init(); SystemClock_Config(); // 系统时钟配置 Soft_IIC_Init(); mpu_init(MPU_CLOCK_PLL_XGYRO); // 初始化 MPU6050 dmp_setup(4); // 启用DMP功能 while (true) { if(dmp_read_fifo()) { Quaternion q = get_quaternion(); printf("q.w=%lf,q.x=%lf,q.y=%lf,q.z=%lf\n", q.w, q.x, q.y, q.z); delay_ms(100); } } return 0; } static void delay_ms(uint32_t ms) { HAL_Delay(ms); } ``` 上述代码实现了基本的数据采集流程:先调用 `mpu_init()` 函数完成设备初始化操作;接着通过 `dmp_setup()` 方法开启内部数字运动处理器(DMP)服务;最后进入无限循环等待 FIFO 数据就绪事件发生后读取四元数形式表示的空间旋转角度并向终端显示出来。 #### 注意事项 - 上述代码仅为简化版演示用途,请根据实际情况修改和完善。 - 对于更复杂的场景可能还需要考虑错误处理机制等问题。 - 如果计划利用更高频率采样率,则建议采用硬件级联方式代替纯软件仿真以提高效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值