/** ****************************************************************************** * @file io_monitor.c * @brief IO状态监控模块实现 * @author Application Layer * @version 1.1 ****************************************************************************** * @attention * 本模块实现四路数字输入的状态监控 * 关键特性: * 1. 10ms定时扫描,平衡响应速度和CPU占用 * 2. 软件去抖,连续3次相同状态才确认变化 * 3. 状态变化时自动上报ASCII格式消息 * * 修订历史: * v1.1 - 修复审查报告中危-5:去抖计数器初始化优化 ****************************************************************************** */ #include "io_monitor.h" #include "uart2_print.h" #include "main.h" #include #define DEBUG_IO_MONITOR 1 #if DEBUG_IO_MONITOR #define DEBUG_LOG(fmt, ...) UART2_Print_Printf("[IO] " fmt "\r\n", ##__VA_ARGS__) #else #define DEBUG_LOG(fmt, ...) #endif typedef struct { GPIO_TypeDef *port; uint16_t pin; uint8_t current_state; uint8_t debounce_counter; uint8_t last_raw_state; uint32_t change_count; } io_channel_t; static io_channel_t di_channels[IO_CHANNEL_COUNT] = { {GPIOB, GPIO_PIN_4, 0, 0, 0, 0}, {GPIOB, GPIO_PIN_5, 0, 0, 0, 0}, {GPIOB, GPIO_PIN_6, 0, 0, 0, 0}, {GPIOB, GPIO_PIN_7, 0, 0, 0, 0} }; static uint32_t last_scan_tick = 0; static bool report_enabled = true; static uint8_t calc_checksum(const char *data, uint8_t len) { uint8_t cs = 0; for (uint8_t i = 0; i < len; i++) { cs ^= (uint8_t)data[i]; } return cs; } static void send_di_event(uint8_t channel, uint8_t state) { char msg[32]; uint8_t cs; int len = snprintf(msg, sizeof(msg), "$DI_EVENT,%d,%d*", channel + 1, state); cs = calc_checksum(msg + 1, len - 1); snprintf(msg + len, sizeof(msg) - len, "%02X\r\n", cs); UART2_Print_String(msg); DEBUG_LOG("CH%d -> %s", channel + 1, state ? "HIGH" : "LOW"); } void IO_Monitor_Init(void) { for (int i = 0; i < IO_CHANNEL_COUNT; i++) { io_channel_t *ch = &di_channels[i]; ch->current_state = HAL_GPIO_ReadPin(ch->port, ch->pin) ? 1 : 0; ch->last_raw_state = ch->current_state; ch->debounce_counter = 1; ch->change_count = 0; } last_scan_tick = 0; report_enabled = true; DEBUG_LOG("Init OK, initial states: 0x%02X", IO_Monitor_GetAllStates()); } void IO_Monitor_Task(void) { uint32_t current_tick = HAL_GetTick(); if (current_tick - last_scan_tick < IO_SCAN_PERIOD_MS) { return; } last_scan_tick = current_tick; for (int i = 0; i < IO_CHANNEL_COUNT; i++) { io_channel_t *ch = &di_channels[i]; uint8_t raw_state = HAL_GPIO_ReadPin(ch->port, ch->pin) ? 1 : 0; if (raw_state != ch->last_raw_state) { ch->debounce_counter = 0; ch->last_raw_state = raw_state; } else { if (ch->debounce_counter < IO_DEBOUNCE_COUNT) { ch->debounce_counter++; } else if (ch->current_state != raw_state) { ch->current_state = raw_state; ch->change_count++; if (report_enabled) { send_di_event(i, raw_state); } } } } } uint8_t IO_Monitor_GetState(uint8_t channel) { if (channel >= IO_CHANNEL_COUNT) { return 0; } return di_channels[channel].current_state; } uint8_t IO_Monitor_GetAllStates(void) { uint8_t states = 0; for (int i = 0; i < IO_CHANNEL_COUNT; i++) { if (di_channels[i].current_state) { states |= (1 << i); } } return states; } void IO_Monitor_EnableReport(bool enable) { report_enabled = enable; DEBUG_LOG("Report %s", enable ? "enabled" : "disabled"); } uint32_t IO_Monitor_GetChangeCount(uint8_t channel) { if (channel >= IO_CHANNEL_COUNT) { return 0; } return di_channels[channel].change_count; }