diff --git a/Inc/command.h b/Inc/command.h index b42d8c9..105ee29 100644 --- a/Inc/command.h +++ b/Inc/command.h @@ -61,6 +61,12 @@ */ void command_process(void); +/** + * @brief M2 连续温度上报任务(在主循环中周期调用,主循环周期 10ms)。 + * @details M2 使能后按设定间隔向 RS485 发送温度帧(格式同 M1 响应)。 + */ +void command_report_task(void); + /** * @brief 解析并处理完整的命令帧。 * @param frame 指向完整命令帧的缓冲区(从包头0xD5开始)。 diff --git a/Inc/ntc.h b/Inc/ntc.h index c766fe3..89b1ade 100644 --- a/Inc/ntc.h +++ b/Inc/ntc.h @@ -4,17 +4,26 @@ #include "gd32f4xx.h" #include "board_config.h" +/* 后台采样周期(主循环 10ms 一圈的分频基准) */ +#define NTC_SAMPLE_PERIOD_MS 100U + /** * @brief 初始化 NTC 测温(PC5 模拟输入 + ADC0 常规通道,软件触发单次转换)。 */ void ntc_init(void); /** - * @brief 读取一次 NTC 温度(多次采样均值 + B 值公式换算)。 - * @details 分压关系:V = VREF * R_ntc / (R_PULL + R_ntc)(硬件上拉在 VREF 侧, - * NTC 接 GND 侧),再由 B 值公式换算温度,单位摄氏度。 - * @return 温度值(摄氏度,float) + * @brief NTC 后台采样任务:每 NTC_SAMPLE_PERIOD_MS 采样一次并更新全局最新温度。 + * @details 在主循环中周期调用(主循环周期 10ms),内部按分频触发采样。 + * 采样结果(含开路 -273.15 / 短路 -274.15 标记值)存入内部全局, + * 供 ntc_get_temperature() 读取——各消费者共享同一次采样,互不重复触发 ADC。 */ -float ntc_read_temperature(void); +void ntc_sample_task(void); + +/** + * @brief 获取最新的 NTC 温度(后台采样值,非现场采样)。 + * @return 温度值(摄氏度);-273.15 = 开路,-274.15 = 短路;上电未采样前初值为 -273.15。 + */ +float ntc_get_temperature(void); #endif // NTC_H diff --git a/Src/command.c b/Src/command.c index 4958772..cac955c 100644 --- a/Src/command.c +++ b/Src/command.c @@ -61,6 +61,13 @@ static const uint8_t s_report_status_ok[] = { 'o', 'k' }; /**< 成功响应数 static const uint8_t s_report_status_err[] = { 'e','r','r' }; /**< 错误响应数据 */ /** @} */ +/** @name M2 连续温度上报状态 + * @{ */ +static bool s_temp_report_enabled = false; /**< 连续上报使能(M2 切换) */ +static uint16_t s_temp_report_period_ms = 500; /**< 上报间隔(ms),M2S 设置,100~60000 */ +static uint16_t s_temp_report_counter = 0; /**< 主循环 10ms 圈计数 */ +/** @} */ + void system_software_reset(void) { // 确保所有待处理的内存访问完成 @@ -373,9 +380,9 @@ void handle_command(const uint8_t *frame, uint8_t len) { /* ========================================== * M1 单次查询温度值 * ========================================== */ - case 1u: // M1: 查询当前 NTC 温度,响应 payload 为 ASCII 摄氏度(如 "23.8") + case 1u: // M1: 查询最新 NTC 温度(后台 100ms 采样值),payload 为 ASCII 摄氏度(如 "23.8") { - float temp = ntc_read_temperature(); + float temp = ntc_get_temperature(); char temp_str[8]; uint8_t n; @@ -391,6 +398,37 @@ void handle_command(const uint8_t *frame, uint8_t len) { } return; + /* ========================================== + * M2 连续温度上报开关(画曲线用) + * M2 : 切换连续上报 使能/停止(默认间隔 500ms) + * M2S : 设置上报间隔(100~60000,10ms 步进)并开启上报 + * 上报帧格式与 M1 响应相同:B5 F0 LEN [ASCII 摄氏度] CRC + * ========================================== */ + case 2u: + { + uint32_t period = 0; + + if (find_parameter_value(&cmd[cmd_index], (uint8_t)(cmd_len - cmd_index), 'S', &period)) { + /* 带参数:设置间隔并开启 */ + if (period >= 100U && period <= 60000U) { + s_temp_report_period_ms = (uint16_t)period; + s_temp_report_enabled = true; + s_temp_report_counter = 0; + send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok)); + } else { + send_response(RESP_TYPE_PARAM_ERR, s_report_status_err, sizeof(s_report_status_err)); + } + } else { + /* 无参数:切换使能 */ + s_temp_report_enabled = !s_temp_report_enabled; + s_temp_report_counter = 0; + send_response(RESP_TYPE_OK, s_report_status_ok, sizeof(s_report_status_ok)); + } + COMMAND_DEBUG("M2 report %s, period=%ums", + s_temp_report_enabled ? "ON" : "OFF", s_temp_report_period_ms); + } + return; + /* ========================================== * M888 软件重启命令 * ========================================== */ @@ -561,6 +599,33 @@ void command_process(void) { } } +/** + * @brief M2 连续温度上报任务(在主循环中周期调用,主循环周期 10ms)。 + * @details 使能时按 s_temp_report_period_ms 间隔向 RS485 发送温度帧, + * 帧格式与 M1 响应相同(B5 F0 LEN [ASCII 摄氏度] CRC)。 + */ +void command_report_task(void) { + if (!s_temp_report_enabled) return; + + s_temp_report_counter++; + if (s_temp_report_counter >= (uint16_t)(s_temp_report_period_ms / 10U)) { + s_temp_report_counter = 0; + + float temp = ntc_get_temperature(); + char temp_str[8]; + uint8_t n; + + if (temp <= -274.0f) { + n = (uint8_t)sprintf(temp_str, "SHRT"); + } else if (temp <= -273.0f) { + n = (uint8_t)sprintf(temp_str, "OPEN"); + } else { + n = (uint8_t)sprintf(temp_str, "%.1f", temp); + } + send_response(RESP_TYPE_OK, (const uint8_t *)temp_str, n); + } +} + /** * @brief 执行命令(简化版) * @details 根据命令字符串直接构造协议帧并执行,无需手动构造协议帧 diff --git a/Src/main.c b/Src/main.c index d161247..a55591c 100644 --- a/Src/main.c +++ b/Src/main.c @@ -48,13 +48,17 @@ int main(void) /* RS485 数据口命令处理(D5 帧协议,具体业务命令在 command.c 扩展) */ command_process(); - /* debug 串口周期打印 NTC 温度(约 1s 一次) */ + /* NTC 后台采样(100ms 一次)+ M2 连续上报任务 */ + ntc_sample_task(); + command_report_task(); + + /* debug 串口周期打印 NTC 温度(约 1s 一次,读后台采样全局值) */ #if DEBUG_MODE == CFG_ENABLE { static uint16_t temp_report_counter = 0; if (++temp_report_counter >= 100U) { /* 主循环 10ms 一圈 → 1s */ temp_report_counter = 0; - float temp = ntc_read_temperature(); + float temp = ntc_get_temperature(); if (temp <= -274.0f) { printf("NTC SHORT (PC5 pulled low)\r\n"); } else if (temp <= -273.0f) { diff --git a/Src/ntc.c b/Src/ntc.c index a535c2b..445fb3e 100644 --- a/Src/ntc.c +++ b/Src/ntc.c @@ -89,3 +89,22 @@ float ntc_read_temperature(void) { float t_k = 1.0f / (1.0f / NTC_T25 + logf(r_ntc / NTC_R25) / (float)NTC_B_VALUE); return t_k - 273.15f; } + +/******************************************************************************/ +/* 后台采样 + 全局最新值:各消费者(debug 打印 / M1 / M2 上报)共享一次采样 */ +/******************************************************************************/ + +static float s_ntc_last_temp = -273.15f; /* 最新温度(初值 = 开路标记) */ +static uint16_t s_ntc_sample_divider = 0; /* 主循环 10ms 圈分频计数 */ + +void ntc_sample_task(void) { + /* 主循环周期 10ms:按 NTC_SAMPLE_PERIOD_MS 分频触发一次采样 */ + if (++s_ntc_sample_divider >= (NTC_SAMPLE_PERIOD_MS / 10U)) { + s_ntc_sample_divider = 0; + s_ntc_last_temp = ntc_read_temperature(); + } +} + +float ntc_get_temperature(void) { + return s_ntc_last_temp; +}