跳转至

说明

概述

在线传感模块提供连续的传感器数据采集和传输功能。它支持可配置的采样频率和多个输出通道(MQTT、串口,以及可选的LCD),实现传感器数据的实时监控。

功能特性

  • ✅ 可配置采样频率(默认:1.0 Hz,范围:0.1 - 300 Hz,实测上限:~200 Hz)
  • ✅ MQTT传输(开启/关闭)
  • ✅ 串口输出(开启/关闭)
  • ✅ 可选LCD显示(当定义 TINY_MEASUREMENT_ENABLE_LCD 时)
  • ✅ 使用ESP定时器进行固定频率数据采集
  • ✅ 自动数据格式化
  • ✅ 线程安全操作
  • ✅ 运行时配置更新

架构

基于定时器的采样

模块使用ESP定时器进行精确的周期性采样:

  1. 定时器创建:创建周期定时器,周期 = 1 / 采样频率
  2. 定时器回调:在每个定时器滴答时执行,读取传感器数据
  3. 数据输出:格式化数据并输出到配置的通道(MQTT、串口、LCD)

数据流

ESP定时器 → 定时器回调 → 传感器读取 → 数据格式化 → 输出通道
                                                          ├─ MQTT
                                                          ├─ 串口
                                                          └─ LCD(可选)

实现原理

架构概述

在线感知模块采用**基于定时器的事件驱动架构**,使用ESP-IDF的高精度定时器系统。设计优先考虑实时数据流传输,最小化延迟。

核心组件

  1. ESP定时器(esp_timer)

    • 高精度硬件定时器,微秒级精度
    • 周期定时器模式:以固定间隔触发回调
    • 定时器周期:period_us = 1,000,000 / 采样频率_hz
    • 定时器回调在定时器上下文中执行(高优先级,类似中断)
  2. 定时器回调函数

    • 在每个定时器滴答时同步执行
    • 执行传感器读取操作(非阻塞SPI)
    • 立即格式化数据(字符串格式化)
    • 发布到输出通道(MQTT、串口、LCD)
    • 最小化处理时间,避免错过定时器滴答
  3. 输出通道

    • MQTT:通过 esp_mqtt_client_publish() 非阻塞发布(QoS 0)
    • 串口:阻塞式 printf() 并立即 fflush()
    • LCD:同步显示更新(高频率时可能影响时序)

编程工具与API

  • ESP-IDF定时器APIesp_timer_create()esp_timer_start_periodic()

  • ESP-IDF MQTT客户端esp_mqtt_client_publish() 用于网络传输

  • 标准C I/Oprintf()snprintf() 用于数据格式化

  • FreeRTOS:状态管理和线程安全(无需显式任务)

执行流程

  1. 初始化:创建周期定时器,计算周期
  2. 启动:执行立即首次采样,然后启动周期定时器
  3. 运行时:定时器回调以固定间隔触发
    • 读取传感器(SPI通信)
    • 格式化数据(字符串转换)
    • 输出到启用的通道(尽可能非阻塞)
  4. 停止:删除定时器,清理资源

关键设计决策

  • 立即首次采样:确保数据采集从t=0开始
  • 非阻塞MQTT:防止定时器回调在网络操作上阻塞
  • 最小回调处理:保持回调执行时间短,以维持时序精度
  • 状态标志保护:使用 s_is_running 标志防止停止后回调执行

配置

默认配置

默认值在 tiny_measurement_config.h 中定义:

#define TINY_MEASUREMENT_ONLINE_SENSING_DEFAULT_FREQ_HZ 1.0f
#define TINY_MEASUREMENT_ONLINE_SENSING_DEFAULT_ENABLE_MQTT true
#define TINY_MEASUREMENT_ONLINE_SENSING_DEFAULT_ENABLE_SERIAL true

配置结构

typedef struct
{
    float sampling_frequency_hz;  // 采样频率(Hz)
    bool enable_mqtt;              // 启用MQTT传输
    bool enable_serial;            // 启用串口输出
    bool enable_lcd;               // 启用LCD显示(可选)
    const char *mqtt_topic;        // MQTT主题(NULL使用默认)
} online_sensing_config_t;

数据格式

MQTT格式

紧凑格式,6位小数精度,支持完整的20位精度:

x,y,z,temp

示例:

0.012345,-0.045678,0.987654,25.50

串口格式

与MQTT格式相同,带换行符:

x,y,z,temp\n

LCD格式

每行一个轴:

  • 第1行:X:0.012345

  • 第2行:Y:-0.045678

  • 第3行:Z:0.987654

  • 第4行:T:25.50C

使用流程

  1. 初始化传感器:初始化ADXL355传感器
  2. 设置传感器句柄:调用 online_sensing_set_sensor_handle()
  3. 初始化模块:调用 online_sensing_init() 并传入配置(或NULL使用默认值)
  4. 启动传感:调用 online_sensing_start()
  5. 运行时更新:可选地更新频率或启用/禁用通道
  6. 停止传感:完成后调用 online_sensing_stop()
  7. 反初始化:调用 online_sensing_deinit() 清理资源

性能考虑

采样频率限制

  • 最小值:0.1 Hz(10秒周期)
  • 最大值:300 Hz(3333微秒周期)- 代码层面的限制
  • 实测上限:~200 Hz - 实际硬件测试中的稳定运行上限
  • 推荐值:大多数应用使用 1 - 200 Hz

实际限制

虽然代码接受高达300 Hz的频率,但实际硬件测试表明,稳定运行的上限约为200 Hz。此限制主要是由于MQTT传输的约束。 在更高频率下,MQTT发布无法跟上数据生成速率,导致缓冲区溢出、消息队列饱和和潜在的数据丢失。为确保可靠运行,特别是在启用MQTT传输时,请将采样频率保持在200 Hz或以下。

资源使用

  • CPU:定时器回调以采样频率执行
  • 内存:回调中最小栈使用
  • 网络:MQTT带宽取决于频率和负载大小。MQTT传输是限制实测最大采样率至~200 Hz的主要瓶颈。 在更高频率下,MQTT发布操作无法足够快地完成,导致消息队列堆积和潜在的数据丢失。
  • 串口:高频率可能导致串口缓冲区溢出

提高采样频率

要实现更高的采样频率,建议关闭不必要的输出通道:

  • 禁用串口输出:串口打印(printf())是阻塞式的,会显著减慢定时器回调的执行速度,特别是在高频率(>100 Hz)时
  • 禁用LCD显示:LCD更新是同步的且相对较慢,不适合用于10 Hz以上的频率
  • 仅保留MQTT:如果需要网络传输,仅保留MQTT启用,禁用串口/LCD输出

通过禁用串口和LCD输出,可以减少定时器回调的执行时间,从而可能实现更高的稳定采样率。

优化建议

  1. 禁用串口输出:对于高频率(>100 Hz),禁用串口输出
  2. MQTT QoS:对高频数据使用QoS 0(默认)
  3. LCD更新:LCD更新相对较慢,仅用于低频率(<10 Hz)
  4. 保持在实测限制内:为确保稳定运行,特别是在启用MQTT时,将采样频率保持在200 Hz或以下。200 Hz的限制主要是由于MQTT传输带宽约束。
  5. 代码层面限制:代码强制最大300 Hz,但实际测试表明~200 Hz是可靠的上限

错误处理

常见错误

  • ESP_ERR_INVALID_ARG:无效频率(超出范围:0.1 - 300 Hz)
  • ESP_ERR_INVALID_STATE:已在运行或未初始化
  • ESP_FAIL:定时器创建或启动失败

错误恢复

  • 在启动前检查传感器句柄是否已设置
  • 在初始化前验证频率范围
  • 使用新配置重启前先停止

线程安全

  • 定时器回调在定时器上下文中执行(高优先级)
  • 配置更改需要停止并重新启动
  • 状态检查防止并发操作

集成注意事项

MQTT集成

  • 需要MQTT客户端已连接
  • 发布前检查 s_is_mqtt_connected
  • 如果 mqtt_topic 为NULL,使用默认主题

传感器集成

  • 需要ADXL355传感器句柄
  • 必须在设置句柄前初始化
  • 传感器读取操作是非阻塞的

LCD集成

  • 仅在定义 TINY_MEASUREMENT_ENABLE_LCD 时可用
  • 启动时清除LCD屏幕
  • 更新是同步的(高频率时可能影响时序)