1.所选任务:赛道二:智能感知
【入门级题目2:姿态监测终端】
利用6轴IMU以50Hz以上采样率实时采集姿态数据,计算俯仰角、横滚角等姿态信息,并通过OLED或PC端实时显示设备姿态。当倾斜角超过设定阈值(如60°)或姿态变化异常时,1秒内触发报警。
2.项目描述
本项目使用ADI MAX32690EVKIT开发板+ MPU6050 6轴IMU模块(3轴加速度+3轴陀螺仪),通过I2C协议通信,实时采集姿态数据,对采集到的结果进行互补滤波融合运算,算出俯仰角(Pitch)、横滚角(Roll),并将温度(来自 MPU6050)、俯仰角、横滚角显示在LCD屏幕上,同时串口也同步输出。
另外加入了条件,俯仰角或横滚角的绝对值超过设定阈值(60°),板载LCD屏幕背景立即变红色。
特别说明的是,本项目使用了CodeFusion Studio来开发,他基于Visual Studio Code。
CodeFusion Studio™ (CFS)是一款嵌入式软件开发平台,可加速人工智能(AI)嵌入式系统的开发进程。AI助手通过模型上下文协议(MCP),直接连接实时调试会话,让调试工作更加智能。
当然本例没有使用这部分AI功能,仅使用了常规的项目管理、编译、下载、调试功能。
3.简短的硬件介绍


硬件部分,主要包括3部分
- 主控MCU:ADI MAX32690,120MHz Arm Cortex-M4处理器,支持蓝牙5.2低功耗(LE)射频。存储容量非常可观:3MB Flash + 1MB SRAM,而且还板载有一块8MB HyperRAM。
另外包括多个QSPI、UART、CAN 2.0B和I2C串行接口。
- LCD屏幕:128*128,主控ST7735,SPI协议。
- 6轴IMU模块,主控MPU6050,MPU6050是一个6轴姿态传感器(3轴 加速度计和3轴陀螺仪传感器),可以测量芯片自身X、Y、Z轴的加速度、角度参数,通过数据融合,可以得到姿态角。
俯仰角(Pitch):绕Y轴旋转的角度。
横滚角(Roll):绕X轴旋转的角度。
航向角(Yaw):绕Z轴旋转的角度,单靠 MPU6050 无法准确得到 Yaw 角,需要和地磁传感器结合使用。
因此本例只计算俯仰角(Pitch)和横滚角(Roll)。


4.方案框图 + 设计思路
整体思路,是结合MPU6050驱动和LCD屏幕显示,来实现全部功能。
- MPU6050驱动是本项目的重点,需用MAX32690 外设驱动库#include "i2c.h"中的函数驱动MPU6050,以进行数据读取、运算。
- LCD屏幕显示直接在TFT_Demo官方例程的基础上修改,本文不作赘述。

主要流程就是:MAX32690初始化——>TFT初始化——>I2C初始化——>MPU6050初始化——>陀螺仪静态校准——>循环读取6轴数据,进行预处理,采用互补滤波算法计算俯仰角(Pitch)和横滚角(Roll),一旦角度的绝对值大于60°,TFT屏幕背景变红。
5.原理图

MPU6050接线原理图如图,最重要的是JP11接口的2-3引脚要用短接帽短接,确保V_AUX引脚是3.3V,这样MPU6050模块的VCC就可以接到JH4的V_AUX,MPU6050模块的SDA、SCL分别接到JH4的第7、第8号端子,对应MAX32690的I2C0模块(SDA:P2_7
、SCL:P2_8),MPU6050模块的其他引脚悬空不接线即可。

另外需补充下,由于我的MPU6050模块本身已对SDA和SCL做了硬件上拉(见上图),上面原理图中的JP3、JP4(开发板上拉)悬空不接即可。
如果外接的器件没有上拉,就需要将JP3、JP4插上短接帽,以实现上拉。
6.软件流程图 + 调试软件说明 + 关键代码说明

上述是Main函数的主要流程,除此之外,还有几个重要函数需介绍。
单字节读函数mpu_read_reg_single:写reg + STOP,再START读1字节,用于读取配置寄存器/WHO_AM_I,之所以要先STOP,再读,似乎是MPU6050的特性要求。
连续多字节读函数mpu_read_burst:restart=1,写reg,连续读采样(14字节传感器数据),每个字节读取后自动Restart
单字节写函数i2c_write_reg,主要用于配置MPU6050。
在读取原始的3轴加速度和3轴陀螺仪数据后,需进行静态偏移消除算法和一阶互补滤波算法,以计算俯仰角(Pitch)和横滚角(Roll)。
静态偏移消除算法:校准得到的静态漂移值,消除陀螺静止时的固有偏移。
一阶互补滤波算法:陀螺仪输出适合捕捉高频快速姿态变化,但存在低频漂移;加速度计可以给出无漂移的静态角度,但动态时高频噪声大。互补滤波就是用两个滤波器,一个低通、一个高通,把两路信号拼在一起,高低频互补。
// MPU6050 参数 ±2g,±250°/s
#define ACCEL_SENS 16384.0f
#define GYRO_SENS 131.0f
#define DT 0.2f
#define ALPHA 0.98f // 互补滤波系数
int ret = mpu_read_burst(I2C_MASTER, MPU6050_ADDR, ACCEL_OUT, buf, 14);
if(ret == E_NO_ERROR)
{
ax_raw = (int16_t)((buf[0] << 8) | buf[1]);
ay_raw = (int16_t)((buf[2] << 8) | buf[3]);
az_raw = (int16_t)((buf[4] << 8) | buf[5]);
temp_raw = (int16_t)((buf[6] << 8) | buf[7]);
gx_raw = (int16_t)((buf[8] << 8) | buf[9]);
gy_raw = (int16_t)((buf[10] << 8) | buf[11]);
gz_raw = (int16_t)((buf[12] << 8) | buf[13]);
// 转换成物理量
ax_g = ax_raw / ACCEL_SENS;
ay_g = ay_raw / ACCEL_SENS;
az_g = az_raw / ACCEL_SENS;
gx_dps = gx_raw / GYRO_SENS - gx_offset;
gy_dps = gy_raw / GYRO_SENS - gy_offset;
gz_dps = gz_raw / GYRO_SENS - gz_offset;
// ========== 【适配当前硬件方向】静态角度 ==========
float acc_pitch = atan2f(-ax_g, sqrtf(ay_g*ay_g + az_g*az_g)) * 57.2958f;
float acc_roll = atan2f(ay_g, az_g) * 57.2958f;
// ========== 互补滤波融合 ==========
pitch = ALPHA * (pitch + gy_dps * DT) + (1.0f - ALPHA) * acc_pitch;
roll = ALPHA * (roll + gx_dps * DT) + (1.0f - ALPHA) * acc_roll;
7.实物演示及说明
CodeFusion Studio界面:


实物运行结果:
MPU6050模块近乎水平放置:

俯仰角(Pitch)接近0°
横滚角(Roll)接近0°
MPU6050模块绕X轴旋转至垂直90:

俯仰角(Pitch)接近0°
横滚角(Roll)接近90°
MPU6050模块绕Y轴旋转至垂直90:

俯仰角(Pitch)接近90°
横滚角(Roll)接近0°
串口输出结果:

分别输出原始的3轴加速度和3轴陀螺仪,以及温度和俯仰角(Pitch)和横滚角(Roll)
8.遇到的难点及解决方法
难点:MPU6050 I2C 读取存在两种不同传输时序,最初尝试共用一套读取函数实现单寄存器读取与连续多字节采样,导致传感器读取异常。
单字节寄存器读取(如 WHO_AM_I、电源管理寄存器)采用独立两段 I2C 事务:写入寄存器地址后发送 I2C STOP,再重新 START 读取 1 字节;
而批量读取加速度 + 陀螺仪 14 字节传感器原始数据,需要采用 Repeated START 重复起始方式,写入起始寄存器地址后,不能发送 STOP,依靠 MPU6050 硬件自动递增寄存器地址连续输出多字节。
共用函数会错误在多字节传输中间插入 I2C STOP,MPU 内部寄存器指针复位,无法顺序读出连续传感器数据。最终将读取接口拆分为 mpu_read_reg_single 单字节读函数和 mpu_read_burst 突发多字节读函数,适配两套 I2C 时序,解决读取失败问题。
9.对本次活动的心得体会
本次活动不仅让我掌握了CodeFusion Studio的开发路径,同时对MAX32690和MPU6050都有了全新的认识和掌握,通过一个简单的姿态检测项目的开发,我对项目开发的流程、展示都有了很大的收获,非常感谢硬禾和ADI举办这样一场非常有意义的活动,后续我将再利用MAX32690EVKIT开发更对有创意的项目,比如微型蓝牙音乐播放器、LVGL图形化可视终端等等。