Funpack5-4 基于FRDM-MCXN236采集BMP280环境数据采集与显示
该项目使用了FRDM-MCXN236,实现了BMP280的设计,它的主要功能为:FRDM-MCXN236采集BMP280环境数据采集与显示。
标签
I2C
BMP280
FRDM-MCXN236
冲向天空的猪
更新2026-10-16
14

FRDM-MCXN236 环境监测系统 - 活动报告

一、项目介绍

本项目基于 NXP FRDM-MCXN236 开发板,实现了一个完整的环境数据采集与监测系统。系统通过 I2C 总线连接 BME280/BMP280 环境传感器,实时采集温度、湿度和气压数据,并通过串口输出监测结果。系统具备数据滤波、历史记录、统计分析和阈值报警等功能,满足工业级环境监测需求。

项目特点:

  • 基于 Zephyr RTOS 实时操作系统,具备良好的可移植性和扩展性
  • 支持双传感器自动检测(I2C 地址 0x76 和 0x77)
  • 实现滑动平均滤波算法,提高数据稳定性
  • 提供多级数据处理:原始数据、滤波数据、统计数据、历史数据
  • LED 状态指示:绿灯闪烁表示正常运行,红灯常亮表示故障或阈值报警
  • 数据刷新周期 1 秒,满足实时监测要求

二、硬件介绍

2.1 FRDM-MCXN236 开发板

2.2 BME280/BMP280 环境传感器

2.3 硬件连接

image.png

I2C 连接(通过 Arduino 接口):

  • SDA(数据线): Arduino D14 → PIO1_16 → flexcomm5_lpi2c5
  • SCL(时钟线): Arduino D15 → PIO1_17 → flexcomm5_lpi2c5
  • VDD: 3.3V 电源
  • GND: 地线

串口连接(板载 MCU-Link):

  • UART4: flexcomm4_lpuart4,波特率 115200 8N1
  • 调试接口: USB 连接到 PC,通过 J10 接口

LED 状态指示:

  • 绿色 LED(led1): 正常运行时周期性闪烁
  • 红色 LED(led0): 故障或阈值报警时常亮

三、方案框图与设计思路

3.1 系统架构框图

image.png

3.2 数据流处理流程

image.png

3.3 设计思路

1. 模块化设计

  • 采用功能分层架构:硬件抽象层 → 驱动层 → 应用层
  • 每个功能封装为独立函数,便于测试和维护
  • 使用 Zephyr 设备树管理硬件配置,无需硬编码地址

2. 数据处理策略

  • 滑动平均滤波: 减少传感器瞬时噪声,提高数据稳定性
  • 环形缓冲存储: 固定内存占用,适合长时间运行
  • 统计分析: 提供最小/最大/平均值,便于趋势分析
  • 阈值报警: 六个独立阈值(温度高/低、湿度高/低、气压高/低)

3. 实时性保证

  • 采用固定周期起点调度算法,避免采集时间累积漂移
  • 周期为 1000ms,满足 ≤1 秒的刷新要求
  • 检测周期超限情况,输出警告信息

4. 兼容性设计

  • 自动检测传感器类型(BME280 或 BMP280)
  • 支持双地址传感器(0x76 和 0x77)
  • BMP280 无湿度通道时自动降级,不影响温度和气压监测

5. 诊断功能

  • 启动时执行 I2C 总线扫描,检测所有设备
  • 读取传感器芯片 ID,验证通信正常
  • 对于 BMP280,输出校准数据和原始 ADC 值,便于故障排查

四、调试软件介绍

4.1 开发工具链

构建系统:

  • Zephyr RTOS: v3.x,提供 RTOS 内核、驱动和构建系统
  • CMake: 跨平台构建工具
  • West: Zephyr 的元构建工具,管理依赖和构建流程
  • GCC Arm: arm-none-eabi-gcc 14.2,C99 标准

调试工具:

  • pyOCD: 开源调试器,支持 MCU-Link
  • CMSIS-Pack: NXP.MCXN236_DFP v26.06.00
  • 串口终端: PuTTY / Tera Term / minicom,115200 8N1

4.2 构建与烧录

构建命令:

west build -b frdm_mcxn236/mcxn236 -p auto

烧录命令:

west flash -d build -r pyocd

串口监控:

# Windows
# 连接到 COM 端口,波特率 115200

# Linux/macOS
minicom -D /dev/ttyACM0 -b 115200

4.3 配置选项 (Kconfig)

系统提供可配置参数,通过 menuconfig 或 prj.conf 修改:

配置项

默认值

说明

ENV_SAMPLE_PERIOD_MS

1000

采样周期(毫秒)

ENV_FILTER_WINDOW_SIZE

5

滤波窗口大小

ENV_HISTORY_SIZE

60

历史数据存储点数

ENV_STATS_INTERVAL_SAMPLES

60

统计输出间隔(样本数)

ENV_TEMP_MIN_MILLI_C

0

低温报警阈值(0°C)

ENV_TEMP_MAX_MILLI_C

40000

高温报警阈值(40°C)

ENV_HUMIDITY_MIN_MILLI_PERCENT

20000

低湿报警阈值(20%)

ENV_HUMIDITY_MAX_MILLI_PERCENT

80000

高湿报警阈值(80%)

ENV_PRESSURE_MIN_PA

90000

低压报警阈值(900hPa)

ENV_PRESSURE_MAX_PA

105000

高压报警阈值(1050hPa)

五、软件流程图

5.1 主程序流程

image.png

5.2 传感器数据处理流程

image.png

六、关键代码介绍

6.1 传感器数据读取

/**
* @brief Read all environmental channels from a sensor.
*/
static int read_environment_data(const struct device *device,
environment_data_t *data)
{
struct sensor_value temperature = {0};
struct sensor_value humidity = {0};
struct sensor_value pressure = {0};
bool humidity_available = false;
int result = 0;

// 触发传感器采集(强制模式下每次都需要触发)
result = sensor_sample_fetch(device);
if (0 != result)
{
return result;
}

// 读取温度通道
result = sensor_channel_get(device, SENSOR_CHAN_AMBIENT_TEMP, &temperature);
if (0 != result)
{
return result;
}

// 读取湿度通道(BMP280 会返回 -ENOTSUP)
result = sensor_channel_get(device, SENSOR_CHAN_HUMIDITY, &humidity);
if ((0 != result) && (-ENOTSUP != result))
{
return result;
}
humidity_available = (0 == result);

// 读取气压通道
result = sensor_channel_get(device, SENSOR_CHAN_PRESS, &pressure);
if (0 != result)
{
return result;
}

// 转换为 milli-units(便于整数运算)
data->temperature_milli_c = (int32_t)sensor_value_to_milli(&temperature);
data->humidity_valid = humidity_available;
if (data->humidity_valid)
{
data->humidity_milli_percent = (int32_t)sensor_value_to_milli(&humidity);
}

// Zephyr 的气压单位是 kPa,milli-kPa 数值上等于 Pa
data->pressure_pa = (int32_t)sensor_value_to_milli(&pressure);

return 0;
}

设计要点:

  • 使用 Zephyr 传感器 API,具备良好的可移植性
  • sensor_sample_fetch() 触发一次 ADC 转换(强制模式)
  • 对湿度通道返回 -ENOTSUP 进行特殊处理,兼容 BMP280
  • 使用 milli-units 避免浮点运算,提高效率

6.2 滑动平均滤波实现

/**
* @brief Add a sample to the moving-average filter.
*/
static int filter_environment_data(environment_filter_t *filter,
const environment_data_t *input,
environment_data_t *output)
{
size_t divisor = 0U;

// 如果窗口已满,移除最旧样本的贡献
if (CONFIG_ENV_FILTER_WINDOW_SIZE == filter->sample_count)
{
const environment_data_t *oldest = &filter->samples[filter->next_index];

filter->temperature_sum -= oldest->temperature_milli_c;
if (oldest->humidity_valid)
{
filter->humidity_sum -= oldest->humidity_milli_percent;
filter->humidity_sample_count--;
}
filter->pressure_sum -= oldest->pressure_pa;
}
else
{
filter->sample_count++;
}

// 添加新样本
filter->samples[filter->next_index] = *input;
filter->temperature_sum += input->temperature_milli_c;
if (input->humidity_valid)
{
filter->humidity_sum += input->humidity_milli_percent;
filter->humidity_sample_count++;
}
filter->pressure_sum += input->pressure_pa;
filter->next_index = (filter->next_index + 1U) % CONFIG_ENV_FILTER_WINDOW_SIZE;

// 计算平均值
divisor = filter->sample_count;
output->temperature_milli_c = (int32_t)(filter->temperature_sum / (int64_t)divisor);
output->humidity_valid = (0U < filter->humidity_sample_count);
if (output->humidity_valid)
{
output->humidity_milli_percent =
(int32_t)(filter->humidity_sum / (int64_t)filter->humidity_sample_count);
}
output->pressure_pa = (int32_t)(filter->pressure_sum / (int64_t)divisor);

return 0;
}

设计要点:

  • 使用环形缓冲区,固定内存占用
  • 保存历史样本和累加和,O(1) 时间复杂度
  • 湿度通道单独计数,处理 BMP280 无湿度的情况
  • 使用 64 位累加和,避免溢出

6.3 阈值报警判定

/**
* @brief Calculate alarm flags for a filtered sample.
*/
static uint32_t get_environment_alarm_flags(const environment_data_t *data)
{
uint32_t alarm_flags = 0U;

if (NULL == data)
{
return ALARM_TEMPERATURE_LOW | ALARM_TEMPERATURE_HIGH |
ALARM_HUMIDITY_LOW | ALARM_HUMIDITY_HIGH |
ALARM_PRESSURE_LOW | ALARM_PRESSURE_HIGH;
}

// 温度阈值判定
if (CONFIG_ENV_TEMP_MIN_MILLI_C > data->temperature_milli_c)
{
alarm_flags |= ALARM_TEMPERATURE_LOW;
}
if (CONFIG_ENV_TEMP_MAX_MILLI_C < data->temperature_milli_c)
{
alarm_flags |= ALARM_TEMPERATURE_HIGH;
}

// 湿度阈值判定(仅在有效时)
if (data->humidity_valid &&
(CONFIG_ENV_HUMIDITY_MIN_MILLI_PERCENT > data->humidity_milli_percent))
{
alarm_flags |= ALARM_HUMIDITY_LOW;
}
if (data->humidity_valid &&
(CONFIG_ENV_HUMIDITY_MAX_MILLI_PERCENT < data->humidity_milli_percent))
{
alarm_flags |= ALARM_HUMIDITY_HIGH;
}

// 气压阈值判定
if (CONFIG_ENV_PRESSURE_MIN_PA > data->pressure_pa)
{
alarm_flags |= ALARM_PRESSURE_LOW;
}
if (CONFIG_ENV_PRESSURE_MAX_PA < data->pressure_pa)
{
alarm_flags |= ALARM_PRESSURE_HIGH;
}

return alarm_flags;
}

设计要点:

  • 使用位掩码表示多个报警状态
  • 阈值通过 Kconfig 配置,便于调整
  • 湿度报警仅在传感器支持时生效
  • 红灯点亮逻辑:alarm_active || acquisition_failed

6.4 固定周期调度

// 主循环中的调度逻辑
next_sample_ms = k_uptime_get(); // 初始化起点

while (true)
{
int64_t acquisition_time_ms = k_uptime_get();

// 处理所有传感器
for (sensor_index = 0U; sensor_index < ARRAY_SIZE(g_sensor_states); sensor_index++)
{
if (!g_sensor_states[sensor_index].active)
{
continue;
}

result = process_environment_sensor(&g_sensor_states[sensor_index],
acquisition_time_ms,
&alarm_active);
// 错误处理...
}

// 更新 LED 状态...

// 固定周期调度:下一周期 = 当前周期 + 周期时间
next_sample_ms += CONFIG_ENV_SAMPLE_PERIOD_MS;
remaining_ms = next_sample_ms - k_uptime_get();

if (0LL < remaining_ms)
{
k_msleep((int32_t)remaining_ms); // 休眠到下一周期
}
else
{
// 处理超限情况
printk("Warning: acquisition cycle overrun by %lld ms\n",
(long long)(-remaining_ms));
next_sample_ms = k_uptime_get(); // 重新同步
}
}

设计要点:

  • 使用固定周期起点,避免时间累积漂移
  • next_sample_ms += PERIOD 而非 next_sample_ms = current + PERIOD
  • 检测周期超限,输出警告并重新同步
  • 保证长时间运行时采集周期的精确性

6.5 I2C 总线诊断

/**
* @brief Scan the I2C bus for devices using all standard 7-bit addresses.
*/
static size_t scan_i2c_bus(const struct device *bus)
{
size_t found_count = 0U;
uint8_t address = I2C_SCAN_FIRST_ADDRESS;

printk("I2C scan start: 7-bit addresses 0x%02x..0x%02x\n",
I2C_SCAN_FIRST_ADDRESS, I2C_SCAN_LAST_ADDRESS);

// 扫描所有标准 7 位地址
for (address = I2C_SCAN_FIRST_ADDRESS;
address <= I2C_SCAN_LAST_ADDRESS;
address++)
{
// 发送零长度写事务,仅检测 ACK
int result = i2c_write(bus, NULL, 0U, address);

if (0 == result)
{
printk("I2C scan: found device at 0x%02x\n", address);
found_count++;
}
}

printk("I2C scan complete: %u device(s) found\n",
(unsigned int)found_count);

if (0U == found_count)
{
printk("I2C scan: no ACK; check VDD/GND, pull-ups, "
"SDA/SCL pins and sensor address\n");
}

return found_count;
}

设计要点:

  • 启动时自动扫描,便于诊断连接问题
  • 扫描范围 0x03..0x77(标准 7 位地址)
  • 使用零长度写事务,仅检测地址 ACK
  • 提供详细的故障排查提示

七、功能展示与说明

7.1 系统启动输出

I2C scan start: 7-bit addresses 0x03..0x77
I2C scan: found device at 0x76
I2C scan: found device at 0x77
I2C scan complete: 2 device(s) found

I2C diagnostic 0x77: ACK, chip ID=0x60
I2C diagnostic 0x76: ACK, chip ID=0x58

BMP280 calibration: 6e 6d a2 67 32 00 f3 8c ca d5 d0 0b 27 0e 1e ff ...
BMP280 raw: adc_P=524288 (0x80000) adc_T=524288 (0x80000)
BMP280 status: status=0x00 ctrl_meas=0x27

Environment sensor 0 ready: bme280@77
Environment sensor 1 ready: bme280@76

Environment monitor started: period=1000 ms filter=5 history=60

说明:

  • I2C 扫描发现两个设备(0x76 和 0x77)
  • 0x77 芯片 ID 为 0x60(BME280),0x76 芯片 ID 为 0x58(BMP280)
  • BMP280 的原始 ADC 值为 0x80000,表示传感器异常(需要检查硬件)
  • 两个传感器都已初始化成功

7.2 正常运行数据输出

[1023 ms] bme280@77 raw T=23.450 C RH=45.230 % P=1013.25 hPa | avg T=23.448 C RH=45.215 % P=1013.26 hPa
[2024 ms] bme280@77 raw T=23.455 C RH=45.240 % P=1013.24 hPa | avg T=23.451 C RH=45.225 % P=1013.25 hPa
[3025 ms] bme280@77 raw T=23.460 C RH=45.235 % P=1013.26 hPa | avg T=23.453 C RH=45.228 % P=1013.25 hPa


image.png
数据解读:

  • 时间戳: [1023 ms] 表示系统运行时间
  • 设备名称: bme280@77 表示 I2C 地址为 0x77 的传感器
  • 原始数据: raw T=23.450 C 温度 23.450°C
  • 原始湿度: RH=45.230 % 相对湿度 45.230%
  • 原始气压: P=1013.25 hPa 气压 1013.25 百帕
  • 滤波数据: avg T=23.448 C 滤波后温度(5点平均)
  • 精度: 温度 0.001°C,湿度 0.001%,气压 0.01 hPa

7.5 统计数据输出

STATS bme280@77 samples=60 stored=60 avg T=23.456 C RH=45.234 % P=1013.27 hPa
RANGE bme280@77 T=23.420..23.490 C RH=45.200..45.280 % P=1013.20..1013.35 hPa

说明:

  • 样本数: samples=60 表示已采集 60 个样本
  • 存储数: stored=60 表示历史缓冲区已满(可存储 60 点)
  • 平均值: 温度 23.456°C,湿度 45.234%,气压 1013.27 hPa
  • 范围: 温度 23.420..23.490°C,变化 0.07°C
  • 每 60 个样本(默认 60 秒)输出一次

7.6 LED 状态指示

正常运行:

  • 绿色 LED: 每秒闪烁一次(每次采集后翻转状态)
  • 红色 LED: 关闭
    image.png
  • 绿色 LED: 继续闪烁
  • 红色 LED: 常亮
    image.png

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