From bae56ad6cb5a6dba7b36380ed5a7074e75719dea Mon Sep 17 00:00:00 2001 From: hulk Date: Fri, 9 Oct 2026 22:47:18 +0800 Subject: [PATCH] Add M1 single-shot temp query command; NTC trimmed-mean filter --- Inc/board_config.h | 5 +++-- Src/command.c | 25 ++++++++++++++++++++++++- Src/ntc.c | 23 ++++++++++++++++++++--- Src/rs485.c | 6 +++--- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/Inc/board_config.h b/Inc/board_config.h index 74f969d..b0017a8 100644 --- a/Inc/board_config.h +++ b/Inc/board_config.h @@ -27,7 +27,7 @@ /* >>>>>>>>>>>>>>>>>>>>[COMMAND DEBUG]<<<<<<<<<<<<<<<<<<<< */ -#define COM_DEBUG CFG_ENABLE // CFG_DISABLE: Command debug off; CFG_ENABLE: Command debug on(调试期开启) +#define COM_DEBUG CFG_DISABLE // CFG_DISABLE: Command debug off; CFG_ENABLE: Command debug on /* 命令协议框架已移植(Src/command.c,数据口 RS485),业务命令待定义 */ /* >>>>>>>>>>>>>>>>>>>>[DEBUG ASSERTIONS DEFINE]<<<<<<<<<<<<<<<<<<<< */ @@ -82,7 +82,8 @@ #define NTC_ADC ADC0 #define NTC_ADC_CHANNEL ADC_CHANNEL_15 #define NTC_SAMPLETIME ADC_SAMPLETIME_480 /* 长采样时间(高阻 NTC 分压源) */ -#define NTC_SAMPLE_COUNT 16U /* 单次测温的采样次数(均值降噪) */ +#define NTC_SAMPLE_COUNT 16U /* 单次测温的采样次数 */ +#define NTC_TRIM_COUNT 2U /* 修剪均值:每端去掉的最大/最小样本数(抗毛刺) */ #define NTC_VREF 3.3f /* ADC 参考电压 V */ #define NTC_ADC_MAX 4095.0f /* 12bit ADC 满量程 */ #define NTC_R_PULL 10000.0f /* 上拉电阻(硬件) */ diff --git a/Src/command.c b/Src/command.c index 74827d9..4958772 100644 --- a/Src/command.c +++ b/Src/command.c @@ -15,6 +15,7 @@ #include "rs485.h" #include "uart.h" #include "systick.h" +#include "ntc.h" #include "board_config.h" #include #include @@ -326,7 +327,8 @@ static bool __attribute__((unused)) find_parameter_value(const uint8_t *cmd, uin * - 无参数命令:M<数字>(如 M999、M888) * - 带参数命令:M<数字>S<参数>(如 M100S123,参数为十进制) * - * 支持的命令(FilmForge 通用骨架): + * 支持的命令(FilmForge): + * - M1: 单次查询温度值(payload 为 ASCII 摄氏度,如 "23.8";OPEN/SHRT=故障) * - M888: 软件复位 * - M999: 输出固件版本号(v<板卡码>.<主>.<次>.<修订>) * - M9999: 进入 OTA 模式(复位进 Bootloader) @@ -368,6 +370,27 @@ void handle_command(const uint8_t *frame, uint8_t len) { cmd_index = (uint8_t)(cmd_index + used_base_cmd); // 更新索引到命令后 switch (base_cmd) { + /* ========================================== + * M1 单次查询温度值 + * ========================================== */ + case 1u: // M1: 查询当前 NTC 温度,响应 payload 为 ASCII 摄氏度(如 "23.8") + { + float temp = ntc_read_temperature(); + char temp_str[8]; + uint8_t n; + + if (temp <= -274.0f) { + n = (uint8_t)sprintf(temp_str, "SHRT"); // PC5 被拉到 GND(短路) + } else if (temp <= -273.0f) { + n = (uint8_t)sprintf(temp_str, "OPEN"); // PC5 被拉到 VREF(NTC 未连通) + } else { + n = (uint8_t)sprintf(temp_str, "%.1f", temp); + } + send_response(RESP_TYPE_OK, (const uint8_t *)temp_str, n); + COMMAND_DEBUG("M1 temp query: %s", temp_str); + } + return; + /* ========================================== * M888 软件重启命令 * ========================================== */ diff --git a/Src/ntc.c b/Src/ntc.c index 79e6793..a535c2b 100644 --- a/Src/ntc.c +++ b/Src/ntc.c @@ -46,13 +46,30 @@ static uint16_t ntc_read_raw_once(void) { } float ntc_read_temperature(void) { + uint16_t samples[NTC_SAMPLE_COUNT]; uint32_t sum = 0U; - /* 多次采样均值降噪 */ + /* 采集 NTC_SAMPLE_COUNT 个样本 */ for (uint8_t i = 0; i < NTC_SAMPLE_COUNT; i++) { - sum += ntc_read_raw_once(); + samples[i] = ntc_read_raw_once(); } - float adc_val = (float)sum / (float)NTC_SAMPLE_COUNT; + + /* 插入排序(16 元素,开销可忽略),为修剪均值做准备 */ + for (uint8_t i = 1; i < NTC_SAMPLE_COUNT; i++) { + uint16_t key = samples[i]; + int8_t j = (int8_t)(i - 1); + while (j >= 0 && samples[j] > key) { + samples[j + 1] = samples[j]; + j--; + } + samples[j + 1] = key; + } + + /* 修剪均值:去掉每端 NTC_TRIM_COUNT 个极值(野值/毛刺)后取平均 */ + for (uint8_t i = NTC_TRIM_COUNT; i < (NTC_SAMPLE_COUNT - NTC_TRIM_COUNT); i++) { + sum += samples[i]; + } + float adc_val = (float)sum / (float)(NTC_SAMPLE_COUNT - 2U * NTC_TRIM_COUNT); /* 分压点电压:上拉 R_PULL 在 VREF 侧,NTC 接 GND 侧 */ float voltage = adc_val * NTC_VREF / NTC_ADC_MAX; diff --git a/Src/rs485.c b/Src/rs485.c index efe8d8d..005c84c 100644 --- a/Src/rs485.c +++ b/Src/rs485.c @@ -81,10 +81,10 @@ void rs485_send(const uint8_t *data, uint16_t len) { /* 回到接收态 */ gpio_bit_reset(RS485_DE_PORT, RS485_DE_PIN); - /* 丢弃发送期间挤入/回环进接收通道的残留字节(读 DATA 清 RBNE/ORE), - 并清空接收环形缓冲,避免垃圾字节污染后续协议帧 */ + /* 读一次 DATA 丢弃发送窗口内挤入接收通道的残留字节(清 RBNE/ORE)。 + 注意:不能清接收环形缓冲——缓冲里可能有"已收到待处理"的用户帧字节。 + 发送期间的回环/杂散字节由协议状态机按非包头丢弃。 */ (void)usart_data_receive(RS485_PHY); - rs485_rx_clear(); /* 恢复接收 */ usart_interrupt_enable(RS485_PHY, USART_INT_RBNE);