2026 ADI CodeFusion 竞赛 - 基于 MAX32655 的多传感器环境监测站
该项目使用了MAX32655,实现了多传感器环境监测站的设计,它的主要功能为:环境参数数据采集。
标签
MAX32655
ADI CodeFusion
多传感器环境监测站
Bymyself
更新2026-09-29
9

1. 所选主题和项目介绍

1.1 项目简介

本次设计选择以多传感器环境监测站为主题,这个是任务是任务2下的入门级题目1:多传感器环境监测站,基于 Analog Devices MAX32655 微控制器,整合 Bosch BME688 四合一环境传感器和 SSD1306 OLED 显示屏,实现对温度、湿度、气压和空气质量(IAQ)的实时采集、本地显示与超限报警。整套系统通过 I2C 总线挂载传感器和显示屏,主循环周期 250 ms,结构简洁、成本低、可扩展性强,适用于智能家居、办公环境监测、小型机房等多种室内场景。

1.2 项目目标

本项目设定了以下具体目标:

(1)多参数实时采集

通过单条 I2C2 总线同时采集温度、湿度、气压和气体电阻四项环境参数,采样周期 250 ms(4 Hz),覆盖 BME688 SEQUENTIAL 模式下三个 heater profile 的完整循环。

(2)OLED 本地实时显示

通过 SSD1306 0.96 寸 OLED(128×64)显示所有传感器数据、IAQ 估算指数与报警状态,刷新采用按行局部更新策略,避免全屏刷新造成的视觉闪烁。

(3)空气质量估算

基于开源 G6EJD 算法将 BME688 原始气体电阻转换为 0-500 的 IAQ 索引,结合湿度补偿输出六级分类(Excellent / Good / Moderate / Poor / Severe / Hazardous),实现无外部库的纯 C 空气质量估算。

(4)超限报警

当任意环境参数超出设定阈值(温度上下限、湿度上下限、IAQ 高限、气体电阻低限)时,通过板载 GPIO 驱动红色 LED 常亮、绿色 LED 持续闪烁指示运行状态;UART 实时打印报警触发/解除事件。

(5)串口调试输出

通过 LPUART0(IBRO 时钟源,0% 波特率误差)以 115200 8N1 输出每帧传感器数据、报警状态切换和周期诊断信息,便于上位机记录与现场调试。

2. 硬件介绍

2.1 主控板 - MAX32655
0

本系统采用 Analog Devices MAX32655 微控制器作为核心处理器。MAX32655 是一款面向 IoT 边缘节点的 32-bit 低功耗 Cortex-M4 处理器,主频 100 MHz,内置 FPU、1 MB Flash、256 KB SRAM,集成丰富的通信外设(UART、SPI、I²C、I²S、CAN、USB 等),同时具备低功耗模式与安全性扩展,非常适合传感器数据汇聚节点。

2.2 环境传感器 - Bosch BME688
0

BME688 是 Bosch Sensortec 推出的四合一环境传感器,集成了:

  • 高精度 温度传感器(精度 ±0.5°C @ 0-65°C)
  • 高精度 湿度传感器(精度 ±3 %RH @ 20-80 %RH)
  • 高精度 气压传感器(精度 ±0.6 hPa,范围 300-1100 hPa)
  • VOC 气体传感器(MOX 原理,对挥发有机物和还原性气体敏感)
  • 内置加热器和 3 个 heater profile,支持 SEQUENTIAL / PARALLEL 多模式扫描

BME688 主要参数:

参数

规格

接口

I²C(最快 3.4 MHz)/ SPI(最快 10 MHz)

I²C 地址

0x77(SDO=VDDIO)或 0x76(SDO=GND)

工作电压

1.71 V - 3.6 V(VDD),3.3 V(VDDIO)

温度范围

-40 °C ~ +85 °C

湿度范围

0 %RH ~ 100 %RH

气压范围

300 hPa ~ 1100 hPa

气体响应

对 VOC、酒精、CO、NH₃ 等还原性气体敏感

封装

LGA-8,3.0 × 3.0 × 0.93 mm

本设计采用 SEQUENTIAL 模式,3 个 heater profile 分别为 100°C / 200°C / 320°C,每个 150 ms 加热 + 250 ms 间隔,循环一次约 1.2 s,可同时获得气体电阻的多温度响应曲线,比单点测量更能反映 VOC 种类差异。

2.3 OLED 显示模块 - SSD1306
0

本系统采用基于 SSD1306 驱动芯片的 0.96 寸 OLED 显示屏作为人机交互界面。该屏幕具有 128×64 像素分辨率、单色(白色)显示、I2C 接口、低功耗(关闭像素电流 < 10 µA)等优点。

OLED 的 GDDRAM 采用页面(Page)组织方式:128 列 × 8 页,每页 8 行像素。本设计通过批量写(multi-byte write)将多字节数据合并到一次 I2C 事务中传输,相比单字节写入降低 I2C 开销约 5-12 倍。

3. 方案框图和项目设计思路

3.1 系统总体架构

本环境监测站采用"传感器-主控-输出"的经典三层架构。系统由以下几个主要部分组成:
0

3.2 总线共享设计思路

(1)单一 I2C2 总线挂载

BME688 和 SSD1306 OLED 共用 I2C2 总线(P0.30 SCL / P0.31 SDA),总线速率统一配置为 100 kHz(标准模式)。两条总线访问相互独立,不会因为 OLED 写屏阻塞 BME688 采集。

(2)MSDK I2C 外设抽象

直接调用 MSDK 的 MXC_I2C_MasterTransaction 接口,将 I²C 事务封装为静态请求结构体 mxc_i2c_req_t 单次复用,避免每次申请栈空间。E_BUSY 自动重试机制借鉴 Env-Sys 项目中验证过的模式(Shutdown + Init + SetFrequency 后重试)。

(3)BME688 平台无关驱动

复用 Bosch 官方 BME68x 纯 C 驱动(BSD-3-Clause 许可),通过 bme68x_dev.read / write / delay_us 三个回调函数对接 MSDK I2C2。该驱动与平台完全解耦,未来可无缝迁移到其他 MCU。

3.3 硬件设计思路

I2C 总线设计

信号

引脚

备注

SCL

P0.30

I2C2 时钟,ALT1 功能

SDA

P0.31

I2C2 数据,ALT1 功能

上拉

4.7 kΩ → 3.3 V

总线空闲为高电平

UART 输出设计

使用 LPUART0(UART3 模块)作为调试日志输出:

  • TX 引脚 P2.7(ALT2 功能)
  • 时钟源:IBRO 7.3728 MHz(内部低功耗振荡器)
  • 波特率 115200 8N1,分频比 64,误差 0%(远优于 APB 100 MHz 的 1.7% 误差)

报警 LED 设计

LED

引脚

指示语义

绿色

P0.18

每 500 ms 翻转 - 系统运行心跳

红色

P0.19

常亮 = 报警;熄灭 = 正常

LED 直接由 GPIO 驱动,无外部三极管,简化电路。

3.4 软件设计思路

(1)分层架构


┌─────────────────────────────────────────┐
│ 应用层(主循环) │
│ - 传感器读取 + 报警判断 + OLED 渲染 │
├─────────────────────────────────────────┤
│ 算法层 │
│ - IAQ 估算(开源 G6EJD) │
│ - 报警状态机(去抖 + 滞回) │
├─────────────────────────────────────────┤
│ 驱动适配层 │
│ - BME68x I2C 读写回调 │
│ - OLED 批量写 + 局部刷新 │
├─────────────────────────────────────────┤
│ 硬件抽象层(MSDK) │
│ - MXC_I2C / MXC_UART / MXC_GPIO │
└─────────────────────────────────────────┘

(2)主循环时序


250 ms ┌─ bme688_app_fetch ──────────────┐

│ I2C 读 BME688 (连续 8 字节×3) │
├─ iaq_push ───────────────────────┤
│ EMA 基线更新 + IAQ 计算 │
├─ alarm_poll ─────────────────────┤
│ 3 样本去抖 + 双阈值滞回判定 │
├─ render_one ─────────────────────┤
│ 8 行 OLED 局部刷新 │
├─ LED 控制 ────────────────────────┤
│ 绿灯翻转 + 红灯按报警状态驱动 │
└─ delay_ms(250) ───────────────────┘

(3)增量刷新:OLED 只在数据变化时按行(page-by-page)刷新,避免 1 KB 全屏写入造成的 1.5 秒视觉闪烁。

(4)滞回防抖:报警触发阈值与解除阈值之间保留 2 单位的滞回宽度(温度 °C / 湿度 %),结合 3 样本连续确认,杜绝传感器噪声引发的 LED 抖动。

(5)开发工具-CodeFusion Studio
0

具体配置如下:

引脚配置,LED的输出控制:

image.png

I2C2的配置,控制器模式:

image.png

LPUART配置:

image.png

4. 软件设计

4.1 软件架构

本系统软件采用分层架构设计,从底层到高层包括:


┌─────────────────────────────────────────┐
│ 应用层(main 主循环) │
│ - 传感器调度 + 报警处理 + UI 渲染 │
├─────────────────────────────────────────┤
│ 算法层 │
│ - IAQ 估算(开源 G6EJD) │
│ - 报警状态机(6 路条件 + 滞回) │
├─────────────────────────────────────────┤
│ 驱动适配层 │
│ - bme688_app(MSDK I2C2 适配) │
│ - OLED(批量写 + 局部刷新) │
├─────────────────────────────────────────┤
│ 硬件抽象层(MSDK) │
│ - MXC_I2C / MXC_UART / MXC_GPIO / SysTick│
└─────────────────────────────────────────┘

4.2 主程序流程图
image.png

4.3 关键代码分析

BME688 I2C2 适配层(bme688_app.c)


static BME68X_INTF_RET_TYPE bme688_write(uint8_t reg_addr,
const uint8_t *data,
uint32_t length,
void *intf_ptr)
{
uint8_t buf[BME68X_LEN_INTERLEAVE_BUFF]; /* 32 bytes */
if (length + 1U > sizeof(buf)) return BME68X_E_COM_FAIL;
buf[0] = reg_addr;
for (uint32_t i = 0; i < length; i++) buf[1U + i] = data[i];
return (i2c_write(buf, length + 1U) == 0)
? BME68X_INTF_RET_SUCCESS : BME68X_E_COM_FAIL;
}

static BME68X_INTF_RET_TYPE bme688_read(uint8_t reg_addr,
uint8_t *data,
uint32_t length,
void *intf_ptr)
{
return (i2c_read(reg_addr, data, length) == 0)
? BME68X_INTF_RET_SUCCESS : BME68X_E_COM_FAIL;
}

I2C 事务封装(bme688_app.c)


static int i2c_xfer(uint8_t *tx, uint32_t tx_len,
uint8_t *rx, uint32_t rx_len)
{
g_req.i2c = MXC_I2C2;
g_req.addr = g_addr; /* 探测到的 0x77 或 0x76 */
g_req.tx_buf = tx;
g_req.tx_len = tx_len;
g_req.rx_buf = rx;
g_req.rx_len = rx_len;
g_req.restart = 0;
g_req.callback = NULL;
int rc = MXC_I2C_MasterTransaction(&g_req);
if (rc == E_BUSY) { /* MSDK 已知问题:连续读写偶发 */
(void)MXC_I2C_Shutdown(MXC_I2C2);
(void)MXC_I2C_Init(MXC_I2C2, 1, 0U);
(void)MXC_I2C_SetFrequency(MXC_I2C2, 100000U);
(void)MXC_I2C_SetClockStretching(MXC_I2C2, 1);
rc = MXC_I2C_MasterTransaction(&g_req);
}
return rc;
}

IAQ 估算(iaq.c)


static uint16_t compute_iaq_index(float g_ohm, float h_pct)
{
float gas_ratio = (g_gas_reference > 0.0f)
? g_ohm / g_gas_reference : 1.0f;
float gas_contrib = clampf(1.0f - gas_ratio, 0.0f, 1.0f);

float hum_dev = my_fabsf(h_pct - IAQ_HUM_CENTER_PCT) / 60.0f;
float hum_contrib = clampf(hum_dev, 0.0f, 1.0f);

float iaq_percent = 0.75f * gas_contrib + 0.25f * hum_contrib;
float iaq_f = iaq_percent * (float)IAQ_MAX;
if (iaq_f > IAQ_MAX) iaq_f = (float)IAQ_MAX;
return (uint16_t)(iaq_f + 0.5f);
}

报警状态机(alarm.c)


static const struct {
float trig; /* 触发阈值 */
float rel; /* 解除阈值 - 滞回 */
} thresholds[NUM_FLAGS] = {
/* T_HIGH */ {32.0f, 30.0f},
/* T_LOW */ {10.0f, 12.0f},
/* H_LOW */ {30.0f, 33.0f},
/* H_HIGH */ {65.0f, 62.0f},
/* IAQ */ {150.0f, 130.0f},
/* GAS */ {5.0f, 8.0f},
};

#define DEBOUNCE_IN 3U /* 连续 3 样本触发 */
#define DEBOUNCE_OUT 3U /* 连续 3 样本解除 */

OLED 局部刷新(oled.c)


static int oled_write_multi(uint8_t ctrl_byte, const uint8_t *data,
uint32_t len)
{
/* 一次 I2C 事务写 len 个 GDDRAM 字节 */
static uint8_t buf[129];
buf[0] = ctrl_byte;
for (uint32_t i = 0; i < len; i++) buf[1u + i] = data[i];
s_req.tx_buf = buf;
s_req.tx_len = len + 1u;
/* ... MXC_I2C_MasterTransaction + E_BUSY retry ... */
}

void OLED_FillRegion(uint8_t x, uint8_t y, uint8_t len)
{
oled_cmd3_then_erase(x, y, len); /* 1 事务清空 len 字节 */
}

4.4 数据流时序


0

5. 硬件功能展示

整体硬件连接
0

OLED 显示布局

本系统 OLED 采用 6×8 小字体(OLED_FONT_6x8 = 12),每行 21 字符 × 8 像素高,共 8 行:
0

UART 输出格式
0

报警阈值表

条件

触发阈值

解除阈值

含义

T_HIGH

> 32 °C

< 30 °C

室内过热

T_LOW

< 10 °C

> 12 °C

过冷

H_LOW

< 30 %RH

> 33 %RH

干燥

H_HIGH

> 65 %RH

< 62 %RH

潮湿

IAQ_HIGH

> 150

< 130

空气质量 Moderate 或更差

GAS_LOW

< 5 kΩ

> 8 kΩ

极强还原性气体(污染)

6. 设计中遇到的难题和解决方法

串口发送乱码问题

问题描述:

实际运行时,PC 端串口助手一直收到星号 *(ASCII 0x2A = 00101010),而非预期的诊断字符串。

这个问题到现在还没有解决,只能换另一个串口进行打印了。

7. 心得体会

本次设计成功实现了一个基于 MAX32655 + BME688 的多传感器环境监测站。从最初的硬件选型、软件架构设计,到 I2C 总线适配、OLED 显示优化、报警算法实现,整个过程让我对嵌入式系统开发有了更深入的理解和实践经验。体验了CFS的配置,建议功能可以在升级,SDK关联上CFS的配置文件。

附件下载
32655.zip
团队介绍
无
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号