3.27_433:添加UART2调试打印、IO监控、指令解析和继电器控制模块。

能够接收UART2指令控制继电器开关,或向UART2发送四路IO输入状态,并使用轮询方式检测IO状态进行及时反馈。
This commit is contained in:
2026-03-27 10:09:13 +08:00
parent f548593c59
commit 71027ebc46
76 changed files with 6789 additions and 1803 deletions

158
Core/Src/io_monitor.c Normal file
View File

@ -0,0 +1,158 @@
/**
******************************************************************************
* @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;
}