159 lines
4.0 KiB
C
159 lines
4.0 KiB
C
|
|
/**
|
|||
|
|
******************************************************************************
|
|||
|
|
* @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 <string.h>
|
|||
|
|
|
|||
|
|
#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;
|
|||
|
|
}
|