2026 ADI CodeFusion竞赛-基于MAX32690EVKIT的姿态监测终端
该项目使用了MAX32690 EVKIT,实现了姿态监测终端的设计,它的主要功能为:基于MAX32690主控与MPU6050传感器构建主从式姿态监测终端,通过实时解算俯仰、横滚及偏航角并在TFT屏幕上以三维旋转立方体直观呈现,同时利用蓝牙将数据透传至下位机进行阈值判定与越限硬件警报,实现了一套集姿态可视化与分布式预警于一体的综合系统。
标签
嵌入式系统
开发板
MAX32690
ADI CodeFusion Studio™
ershaoye
更新2026-09-28
黄河交通学院
5

一、所选任务:

【入门级题目2:姿态监测终端】

利用6轴IMU以50Hz以上采样率实时采集姿态数据,计算俯仰角、横滚角等姿态信息,并通过OLED或PC端实时显示设备姿态。当倾斜角超过设定阈值(如60°)或姿态变化异常时,1秒内触发报警。

推荐开发板:MAX32655FTHR、MAX32690EVKIT

二、项目简介

基于MAX32690主控与MPU6050传感器构建主从式姿态监测终端,通过实时解算俯仰、横滚及偏航角并在TFT屏幕上以三维旋转立方体直观呈现,同时利用蓝牙将数据透传至下位机进行阈值判定与越限硬件警报,实现了一套集姿态可视化与分布式预警于一体的综合系统

三、硬件部分

硬件包括两个部分: 1. MAX32690 EVKIT开发板+MPU6050姿态传感器+HC-04蓝牙模块

2. STM32F103C8T6开发板+0.96寸OLED单色显示屏+TW-TTS语音合成模块+扬声器+HC-04蓝牙模块

硬件部分组成如下图所示。

image.png

第一部分:

MAX32690EVKIT主控板:搭载Arm‑Cortex‑M4F 内核,120MHz 主频,带有硬件 FPU 浮点运算单元,承担上位机逻辑,负责 IMU 原始数据读取、姿态解算算法运算、蓝牙数据收发处理;

MPU‑6050 六轴 IMU 姿态传感器:用于产生三轴加速度与三轴陀螺仪原始运动数据,为姿态解算提供数据源;

HC‑04 蓝牙透传模块:是支持SPP经典蓝牙和BLE低功耗蓝牙的双模蓝牙且是主从一体,用于主从机之间的相互通信,在这里充当发送端,负责接收串口信息透传至下位机蓝牙。


第二部分:

STM32F103C8T6:作为项目下位机,接收上位机蓝牙下发的数据与指令,完成业务逻辑响应、外设驱动控制;

0.96寸OLED显示屏:用于显示stm32的交互内容;

tw-tts语音合成模块:可通过串口合成语音音频信号,用于合成警报声音;

扬声器:对接 TW‑TTS 音频输出引脚,播放模块生成的警报语音;

HC‑04 蓝牙透传模块:这里充当接收端,负责接收上位机蓝牙信息信息发送至串口。


四、软件部分

image.png

软件方案框图


4.1 初始化代码配置

本项目采用 CodeFusion Studio(CFS)完成工程初始化代码搭建,项目不启用 RISC‑V 内核,全部代码均在 Cortex‑M4 内核上运行,借助软件图形化配置界面,即可快速完成所需硬件外设的配置。点击生成代码后所有的初始化代码将放置在soc_init.c文件中。

image.png

4.2 读取六轴数据

在MPU6050.c文件中,调用WriteReg函数完成 MPU6050 传感器的寄存器配置。采样率分频系数配置为0x09,即10分频,计算可得实际采样率约 100 Hz,高于题目要求的 50 Hz。若需要进一步提升采样率,可减小分频系数,但分频系数过小会容易造成输出数据不稳定。

WriteReg(addr, MPU6050_REG_PWR_MGMT_1, 0x01);     /* 唤醒 + PLL X 陀螺 */
WriteReg(addr, MPU6050_REG_PWR_MGMT_2, 0x00);     /* 全部轴使能 */
/*
    MPU6050采样率计算公式(DLPF开启时陀螺内部输出基准1kHz):
    SampleRate = GyroOutputRate / (1 + SMPLRT_DIV)
    SampleRate = 1000 / (1 + div)
    实际采样率(Hz): 1000/(1+9)=100Hz, div=9(0x09), 采样时间dt = 1.0f / 100.0f = 0.01s
*/
WriteReg(addr, MPU6050_REG_SMPLRT_DIV, 0x09);     /* 采样率 */
WriteReg(addr, MPU6050_REG_CONFIG, 0x06);          /* DLPF */
WriteReg(addr, MPU6050_REG_GYRO_CONFIG, 0x18);     /* ±2000°/s */
WriteReg(addr, MPU6050_REG_ACCEL_CONFIG, 0x18);    /* ±16g */

在cube3d.c中,集成了 MPU6050 姿态解算(俯仰/横滚/偏航),实现 3D 立方体的旋转投影、画家算法深度排序,以及基于 RGB565 帧缓冲和局部脏矩形刷新的高效 TFT 显示。同时,根据角度阈值触发 LED 闪烁与立方体面色变换的声光报警,并在屏幕上实时输出姿态、加速度、陀螺仪、帧率及蓝牙透传指令等数据。

4.3 姿态解算、屏幕显示和阈值响应

4.3.1 三维旋转投影

将立方体 8 个顶点按欧拉角进行三轴旋转,并正交投影到屏幕坐标,同时存储旋转后的 Z 值供深度排序。以下包含完整的旋转矩阵计算与顶点处理循环。

static void Cube3D_Project(void)
{
float cx = cosf(ang_x), sx = sinf(ang_x);
float cy = cosf(ang_y), sy = sinf(ang_y);
float cz = cosf(ang_z), sz = sinf(ang_z);

for (int i = 0; i < 8; i++) {
float x = orig_verts[i][0];
float y = orig_verts[i][1];
float z = orig_verts[i][2];

/* Y 旋转 */
float x1 = x * cy - z * sy;
float z1 = x * sy + z * cy;

/* X 旋转 */
float y2 = y * cx - z1 * sx;
float z2 = y * sx + z1 * cx;

/* Z 旋转 */
float x3 = x1 * cz - y2 * sz;
float y3 = x1 * sz + y2 * cz;

rotated_z[i] = z2;

screen_pts[i][0] = (int16_t)(CUBE_CENTER_X + x3 * CUBE_SCALE);
screen_pts[i][1] = (int16_t)(CUBE_CENTER_Y + y3 * CUBE_SCALE);
}
}

4.3.2 画家算法(面深度排序)

计算每个面的平均深度,使用插入排序将 6 个面按从远到近排列,后续按此顺序绘制,以实现正确的遮挡。这里包含深度计算、排序循环及后续绘制调用。

float face_depths[NUM_FACES];
int face_order[NUM_FACES];
for (int f = 0; f < NUM_FACES; f++) {
face_depths[f] = (rotated_z[faces[f][0]] + rotated_z[faces[f][1]]
+ rotated_z[faces[f][2]] + rotated_z[faces[f][3]]) * 0.25f;
face_order[f] = f;
}
for (int i = 1; i < NUM_FACES; i++) {
int key = face_order[i];
float kd = face_depths[key];
int j = i - 1;
while (j >= 0 && face_depths[face_order[j]] > kd) {
face_order[j + 1] = face_order[j];
j--;
}
face_order[j + 1] = key;
}
// 后续按排序绘制每个面
for (int fi = 0; fi < NUM_FACES; fi++) {
int f = face_order[fi];
int v0 = faces[f][0], v1 = faces[f][1], v2 = faces[f][2], v3 = faces[f][3];
uint16_t fc = alert_color ? alert_color : face_colors[f];
fb_fill_triangle(screen_pts[v0][0], screen_pts[v0][1],
screen_pts[v1][0], screen_pts[v1][1],
screen_pts[v2][0], screen_pts[v2][1], fc);
fb_fill_triangle(screen_pts[v2][0], screen_pts[v2][1],
screen_pts[v3][0], screen_pts[v3][1],
screen_pts[v0][0], screen_pts[v0][1], fc);
}

4.3.3 脏矩形局部刷新(包围盒计算与刷新调用)

计算旧顶点(old_pts)和新顶点(screen_pts)的包围盒,求并集得到“脏矩形”,仅清除和刷新该区域,避免全屏重绘,大幅提升性能。以下包含包围盒计算、合并及刷新调用。

int16_t box1_x, box1_y, box1_w, box1_h;
pts_bbox(old_pts, &box1_x, &box1_y, &box1_w, &box1_h);
int16_t box2_x, box2_y, box2_w, box2_h;
pts_bbox(screen_pts, &box2_x, &box2_y, &box2_w, &box2_h);

int ux, uy, uw, uh;
union_bbox(box1_x, box1_y, box1_w, box1_h,
box2_x, box2_y, box2_w, box2_h,
&ux, &uy, &uw, &uh);

fb_clear_rect(ux, uy, uw, uh, BLACK);
// ... 绘制所有内容 ...
fb_flush_rect(ux, uy, uw, uh);

4.3.4 角度阈值报警和透传警报指令(LED + 面颜色切换+蓝牙串口透传)

根据俯仰/横滚绝对值最大值触发不同级别警报(≥60° 红色闪烁,≥45° 绿色闪烁),控制 GPIO 驱动 LED 并改变立方体面颜色。设有两级透传指令,当对应阈值判断条件达成后通过串口连接蓝牙透传对应的警报指令。以下包含完整的阈值判断、GPIO 操作和 alert_color 设置。

int ap = (pitch_deg > 0) ? pitch_deg : -pitch_deg;
int ar = (roll_deg > 0) ? roll_deg : -roll_deg;
int max_a = (ap > ar) ? ap : ar;
uint16_t alert_color = 0;
if (max_a >= 60) {
alert_color = ((ms / ALERT_FLASH_MS) & 1) ? WHITE : RED;
printf("1\n");
if ((ms / (ALERT_FLASH_MS / 1)) & 1){
MXC_GPIO_OutSet(MXC_GPIO2, MXC_GPIO_PIN_12);
MXC_GPIO_OutSet(MXC_GPIO0, MXC_GPIO_PIN_14);
}else
MXC_GPIO_OutClr(MXC_GPIO0, MXC_GPIO_PIN_14);
} else if (max_a >= 45) {
alert_color = ((ms / ALERT_FLASH_MS) & 1) ? WHITE : GREEN;
printf("2\n");
if ((ms / ALERT_FLASH_MS) & 1){
MXC_GPIO_OutSet(MXC_GPIO0, MXC_GPIO_PIN_14);
MXC_GPIO_OutSet(MXC_GPIO2, MXC_GPIO_PIN_12);
}else
MXC_GPIO_OutClr(MXC_GPIO2, MXC_GPIO_PIN_12);
} else {
MXC_GPIO_OutSet(MXC_GPIO0, MXC_GPIO_PIN_14);
MXC_GPIO_OutSet(MXC_GPIO2, MXC_GPIO_PIN_12);
}

4.3.5 数据显示(加速度、陀螺仪、帧率等)

在屏幕固定位置实时显示姿态角(俯仰/横滚/偏航)、加速度计(AX/AY/AZ)、陀螺仪(GX/GY/GZ)以及帧率(FPS),便于调试和状态监控。以下为所有TFT显示各类名称缩写和对应数据的代码。

fb_string(2, 2, "P:", GREEN);
fb_signed_number(18, 2, pitch_deg, GREEN);
fb_string(2, 14, "R:", CYAN);
fb_signed_number(18, 14, roll_deg, CYAN);
fb_string(2, 26, "Y:", YELLOW);
fb_signed_number(18, 26, yaw_deg, YELLOW);
fb_string(2, 38, "AX:", WHITE); fb_signed_number(25, 38, ax, WHITE);
fb_string(2, 50, "AY:", WHITE); fb_signed_number(25, 50, ay, WHITE);
fb_string(2, 62, "AZ:", WHITE); fb_signed_number(25, 62, az, WHITE);
fb_string(2, 74, "GX:", WHITE); fb_signed_number(25, 74, gx+5, WHITE);
fb_string(2, 86, "GY:", WHITE); fb_signed_number(25, 86, gy-2, WHITE);
fb_string(2, 98, "GZ:", WHITE); fb_signed_number(25, 98, gz+2, WHITE);
frame++;
uint32_t fps = (ms > 0) ? (frame * 1000 / ms) : 0;
fb_string(65, 100, "FPS:", YELLOW);

五、项目演示

当 MPU6050 处于平稳静止状态时,三轴欧拉角均趋近于 0°,此时阈值判定条件不满足,系统无报警触发,LED 熄灭,立方体以预设的六面色正常渲染,TFT 数据显示当前接近零位的姿态数值。

lQDPKHsEYYjwdOfNAtDNBP-wj6ZJizjCJRoKbjCYqwLrAA_1279_720.jpg

正常状态


当 MPU6050 的俯仰或横滚角绝对值达到 45° 及以上但未超过 60° 时,系统判定为轻度倾斜,触发绿色级别报警。此时立方体各面颜色在原始色与绿色之间以 500ms 周期交替闪烁,同时板载双色 LED 呈现绿色闪烁提示。TFT 界面持续更新实时角度值,报警状态随角度回落至 45° 以下时自动解除,LED 熄灭并恢复原始面颜色。

lQDPJwMj13Wp1efNAtDNBP-wo74-aovNOoEKbjCZxFp7AA_1279_720.jpg

轻度倾斜(≥45° & <60°)


当俯仰或横滚角绝对值达到 60° 及以上时,系统判定为严重倾斜,触发红色级别报警。此时立方体各面颜色在白色与红色之间快速闪烁,同时板载双色 LED 切换为红色闪烁模式。报警期间 TFT 仍保持所有传感器数据的实时刷新,直至角度回落至 60° 以下时切换至绿色报警级别(若仍 ≥45°)或完全恢复(<45°)。

lQDPJxMFSHXFFufNAtDNBP-w1IFrCiqVqEEKbjCaWTKQAA_1279_720.jpg

重度倾斜(≥60°)


下面是工程的完整流程图:

image.png

工程整体流程图


遇到的问题

  1. 偏航角漂移与异常数据:陀螺仪积分累积误差导致偏航角无法归零,振动和噪声引发加速度计/陀螺仪数据跳变,影响姿态显示可靠性。
  2. TFT 渲染效率不足:软件 SPI 传输速率有限,且与姿态解算、屏幕绘制共享 CPU,算力瓶颈导致帧率波动,画面流畅度不完美。

未来解决方案:传感器层面采用滑动平均滤波、限幅去野值及动态零偏校准,并计划外接磁力计实现9轴融合,从根源抑制漂移;显示层面引入硬件 SPI 或 DMA 加速传输,优化渲染管线,释放 CPU 算力,提升整体运行流畅度。

另外在通信设备上,目前使用的是蓝牙发送与接收,未来可以引入 MQTT 协议,通过 Wi-Fi 或以太网接入物联网平台,可大幅提升系统通信的灵活性和可扩展性。

总结与感受

本次项目中,我第一次体验了通过CodeFusion Studio™来完成工程搭建,在工程搭建的过程中,ADI 提供的开源 SDK、硬件抽象层与项目创建向导,借助图形化编程页面完成引脚、外设的可视化配置,极大降低了底层配置难度,让我有了一个全新的代码体验。整个项目给我印象最为深刻的点是 CodeFusion Studio 图形化配置带来的开发体验,通过图形化就可以快速完成引脚与外设的配置。以往做嵌入式开发时,底层寄存器、外设初始化配置往往会耗费大量调试时间。因此,这套开发环境让我体会到现代化嵌入式工具链对开发效率的提升。在项目开发中,AI的使用也是必不可少的,现在在代码开发中,感觉AI的比重越来越不可估量了,合理的利用AI可以省去大量查阅资料和解决问题的时间,让我们可以更加专注于项目方案本身的开发中。

最后,感谢ADI和硬禾学堂举办此次比赛,也感谢工作人员和答疑解惑,使我学到了很多新知识,期待未来可以带来更多精彩的活动。


附件下载
基于MAX32690EVKIT的姿态监测终端.zip
上位机工程代码
固件.zip
可直接烧录的代码固件
STM32端代码文件.zip
下位机工程代码
团队介绍
黄河交通学院物联网工程专业本科生
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号