代码¶
Warning
以下代码应基于发布代码中的代码,可能已更新。
online_sensing.h¶
/**
* @file online_sensing.h
* @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
* @brief 在线传感模块 - 连续传感器数据采集和传输
* @version 1.0
* @date 2025-01-XX
* @copyright Copyright (c) 2025
*
* @details
* 该模块提供在线传感器数据采集,可配置:
* - 采样频率(默认:20 Hz)
* - MQTT传输(启用/禁用)
* - 串口输出(启用/禁用)
*
* 功能特性:
* - 使用FreeRTOS任务进行固定频率数据采集
* - 自动MQTT负载格式化(JSON)
* - 可配置输出通道
* - 线程安全操作
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "node_acc_adxl355.h"
#include "tiny_measurement_config.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* ============================================================================
* CONFIGURATION STRUCTURE
* ============================================================================ */
/**
* @brief 在线传感配置
*/
typedef struct
{
float sampling_frequency_hz; ///< 采样频率(Hz,默认:20.0)
bool enable_mqtt; ///< 启用MQTT传输(默认:true)
bool enable_serial; ///< 启用串口输出(默认:true)
#ifdef TINY_MEASUREMENT_ENABLE_LCD
bool enable_lcd; ///< 启用LCD显示输出(默认:false)
#endif
const char *mqtt_topic; ///< MQTT发布主题(默认:NULL)
} online_sensing_config_t;
/* ============================================================================
* FUNCTION DECLARATIONS
* ============================================================================ */
/**
* @brief 初始化在线传感模块
* @param config 配置结构(NULL使用默认配置)
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_init(const online_sensing_config_t *config);
/**
* @brief 启动在线传感任务
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_start(void);
/**
* @brief 停止在线传感任务
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_stop(void);
/**
* @brief 反初始化在线传感模块
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_deinit(void);
/**
* @brief 运行时更新采样频率
* @param frequency_hz 新的采样频率(Hz)
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_set_frequency(float frequency_hz);
/**
* @brief 启用或禁用MQTT传输
* @param enable true启用,false禁用
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_set_mqtt_enable(bool enable);
/**
* @brief 启用或禁用串口输出
* @param enable true启用,false禁用
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_set_serial_enable(bool enable);
/**
* @brief 获取当前配置
* @param config 输出参数,当前配置
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_get_config(online_sensing_config_t *config);
/**
* @brief 检查在线传感是否正在运行
* @param is_running 输出参数:true表示正在运行,false表示未运行
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_is_running(bool *is_running);
/**
* @brief 设置ADXL355传感器句柄(必须在启动前调用)
* @param handle ADXL355句柄指针
* @return 成功返回ESP_OK,失败返回错误码
*/
esp_err_t online_sensing_set_sensor_handle(adxl355_handle_t *handle);
#ifdef __cplusplus
}
#endif
online_sensing.c¶
关键实现细节¶
定时器回调¶
static void sampling_timer_callback(void *arg)
{
if (!s_is_running || s_adxl355_handle == NULL)
{
return;
}
adxl355_accelerations_t accel;
float temperature;
char mqtt_pub_buff[128];
// 读取传感器数据
esp_err_t accel_ret = adxl355_read_accelerations(s_adxl355_handle, &accel);
esp_err_t temp_ret = adxl355_read_temperature(s_adxl355_handle, &temperature);
if (accel_ret == ESP_OK && temp_ret == ESP_OK)
{
// MQTT传输 - 紧凑格式
if (s_config.enable_mqtt && s_is_mqtt_connected)
{
snprintf(mqtt_pub_buff, sizeof(mqtt_pub_buff), "%.6f,%.6f,%.6f,%.2f",
accel.x, accel.y, accel.z, temperature);
const char *topic = s_config.mqtt_topic ? s_config.mqtt_topic : MQTT_PUBLISH_TOPIC;
esp_mqtt_client_publish(s_mqtt_client, topic,
mqtt_pub_buff, strlen(mqtt_pub_buff), 1, 0);
}
// 串口输出
if (s_config.enable_serial)
{
printf("%.6f,%.6f,%.6f,%.2f\n", accel.x, accel.y, accel.z, temperature);
fflush(stdout);
}
#ifdef TINY_MEASUREMENT_ENABLE_LCD
// LCD显示
if (s_config.enable_lcd)
{
char lcd_str[48];
snprintf(lcd_str, sizeof(lcd_str), "X:%.6f", accel.x);
lcd_show_string(0, 0, lcd_self.width, 16, 16, lcd_str, BLACK);
// ... (Y, Z, 温度)
}
#endif
}
}
初始化¶
esp_err_t online_sensing_init(const online_sensing_config_t *config)
{
if (s_is_running)
{
ESP_LOGW(TAG, "在线传感已在运行,请先停止");
return ESP_ERR_INVALID_STATE;
}
// 应用配置
if (config != NULL)
{
memcpy(&s_config, config, sizeof(online_sensing_config_t));
}
else
{
// 使用默认配置
s_config.sampling_frequency_hz = ONLINE_SENSING_DEFAULT_FREQ_HZ;
s_config.enable_mqtt = ONLINE_SENSING_DEFAULT_ENABLE_MQTT;
s_config.enable_serial = ONLINE_SENSING_DEFAULT_ENABLE_SERIAL;
s_config.mqtt_topic = NULL;
}
// 验证配置
if (s_config.sampling_frequency_hz <= 0.0f || s_config.sampling_frequency_hz > 10000.0f)
{
ESP_LOGE(TAG, "无效的采样频率: %.2f Hz (有效范围: 0.1 - 10000 Hz)",
s_config.sampling_frequency_hz);
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
启动函数¶
esp_err_t online_sensing_start(void)
{
if (s_is_running)
{
ESP_LOGW(TAG, "在线传感已在运行");
return ESP_ERR_INVALID_STATE;
}
if (s_adxl355_handle == NULL)
{
ESP_LOGE(TAG, "ADXL355句柄未设置。请先调用 online_sensing_set_sensor_handle()");
return ESP_ERR_INVALID_STATE;
}
// 计算定时器周期(微秒)
uint64_t period_us = (uint64_t)(1000000.0f / s_config.sampling_frequency_hz);
// 验证周期
if (period_us < 100)
{
ESP_LOGE(TAG, "采样频率过高: %.2f Hz (最大: 10000 Hz)",
s_config.sampling_frequency_hz);
return ESP_ERR_INVALID_ARG;
}
// 创建定时器
esp_timer_create_args_t timer_args = {
.callback = sampling_timer_callback,
.arg = NULL,
.name = "online_sampling_timer"
};
esp_err_t ret = esp_timer_create(&timer_args, &s_sampling_timer);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "创建定时器失败: %s", esp_err_to_name(ret));
return ret;
}
// 在启动定时器前设置运行标志
s_is_running = true;
// 立即执行第一次采样(t=0)
sampling_timer_callback(NULL);
// 启动周期定时器
ret = esp_timer_start_periodic(s_sampling_timer, period_us);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "启动定时器失败: %s", esp_err_to_name(ret));
esp_timer_delete(s_sampling_timer);
s_sampling_timer = NULL;
s_is_running = false;
return ret;
}
ESP_LOGI(TAG, "在线传感已启动 (频率: %.2f Hz, 周期: %llu us)",
s_config.sampling_frequency_hz, period_us);
return ESP_OK;
}
停止函数¶
esp_err_t online_sensing_stop(void)
{
if (!s_is_running)
{
ESP_LOGW(TAG, "在线传感未运行");
return ESP_ERR_INVALID_STATE;
}
s_is_running = false;
// 停止并删除定时器
if (s_sampling_timer != NULL)
{
esp_timer_stop(s_sampling_timer);
esp_timer_delete(s_sampling_timer);
s_sampling_timer = NULL;
}
ESP_LOGI(TAG, "在线传感已停止");
return ESP_OK;
}
使用示例¶
#include "online_sensing.h"
#include "node_acc_adxl355.h"
// 初始化传感器
adxl355_handle_t adxl355_handle;
adxl355_init(&adxl355_handle, ADXL355_RANGE_2G, ADXL355_ODR_1000);
// 设置传感器句柄
online_sensing_set_sensor_handle(&adxl355_handle);
// 使用默认配置初始化
online_sensing_init(NULL);
// 启动在线传感
online_sensing_start();
// 运行时配置更新
online_sensing_set_frequency(50.0f); // 改为50 Hz
online_sensing_set_mqtt_enable(false); // 禁用MQTT
// 完成后停止
online_sensing_stop();
// 清理
online_sensing_deinit();