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

224
Core/Src/uart2_print.c Normal file
View File

@ -0,0 +1,224 @@
/**
******************************************************************************
* @file uart2_print.c
* @brief UART2调试打印模块实现
* @author Application Layer
* @version 1.1
******************************************************************************
* @attention
* 本模块实现基于环形缓冲区的非阻塞调试信息输出
* 关键特性:
* 1. 环形缓冲区避免数据丢失
* 2. 中断安全支持ISR中调用
* 3. 非阻塞发送,不影响实时性
*
* 修订历史:
* v1.1 - 修复审查报告高危-1/2/3中危-4
******************************************************************************
*/
#include "uart2_print.h"
#include "usart.h"
#include <string.h>
#include <stdio.h>
#define DEBUG_PRINT_ENABLED 1
#if DEBUG_PRINT_ENABLED
#define DEBUG_LOG(fmt, ...) UART2_Print_Printf("[UART2] " fmt "\r\n", ##__VA_ARGS__)
#else
#define DEBUG_LOG(fmt, ...)
#endif
typedef struct {
uint8_t buffer[UART2_TX_BUFFER_SIZE];
volatile uint16_t head;
volatile uint16_t tail;
volatile uint16_t count;
volatile bool is_sending;
volatile uint16_t overflow_count;
} ring_buffer_t;
static ring_buffer_t tx_ring = {0};
void UART2_Print_Init(void)
{
tx_ring.head = 0;
tx_ring.tail = 0;
tx_ring.count = 0;
tx_ring.is_sending = false;
tx_ring.overflow_count = 0;
DEBUG_LOG("Init OK, buffer size: %d", UART2_TX_BUFFER_SIZE);
}
void UART2_Print_Send(const uint8_t *data, uint16_t len)
{
if (len == 0 || data == NULL) {
return;
}
uint16_t written = 0;
bool needs_kickoff = false;
__disable_irq();
for (uint16_t i = 0; i < len; i++) {
if (tx_ring.count >= UART2_TX_BUFFER_SIZE) {
tx_ring.overflow_count++;
break;
}
tx_ring.buffer[tx_ring.head] = data[i];
tx_ring.head = (tx_ring.head + 1) % UART2_TX_BUFFER_SIZE;
tx_ring.count++;
written++;
}
if (written > 0 && !tx_ring.is_sending) {
tx_ring.is_sending = true;
needs_kickoff = true;
}
__enable_irq();
if (needs_kickoff) {
uint8_t byte;
__disable_irq();
byte = tx_ring.buffer[tx_ring.tail];
__enable_irq();
HAL_UART_Transmit_IT(&huart2, &byte, 1);
}
}
void UART2_Print_String(const char *str)
{
if (str == NULL) {
return;
}
UART2_Print_Send((const uint8_t *)str, strlen(str));
}
void UART2_Print_Printf(const char *fmt, ...)
{
if (fmt == NULL) {
return;
}
char buffer[128];
va_list args;
va_start(args, fmt);
int len = vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
if (len >= 0) {
if (len >= (int)sizeof(buffer)) {
len = sizeof(buffer) - 1;
}
UART2_Print_Send((const uint8_t *)buffer, len);
}
}
void UART2_Print_Task(void)
{
uint8_t byte;
uint16_t current_tail;
__disable_irq();
if (tx_ring.is_sending || tx_ring.count == 0) {
__enable_irq();
return;
}
current_tail = tx_ring.tail;
tx_ring.tail = (tx_ring.tail + 1) % UART2_TX_BUFFER_SIZE;
tx_ring.count--;
tx_ring.is_sending = true;
byte = tx_ring.buffer[current_tail];
__enable_irq();
HAL_UART_Transmit_IT(&huart2, &byte, 1);
}
void UART2_Print_TxCpltCallback(void)
{
uint8_t byte;
uint16_t current_tail;
bool has_more = false;
__disable_irq();
tx_ring.is_sending = false;
if (tx_ring.count > 0) {
current_tail = tx_ring.tail;
tx_ring.tail = (tx_ring.tail + 1) % UART2_TX_BUFFER_SIZE;
tx_ring.count--;
tx_ring.is_sending = true;
byte = tx_ring.buffer[current_tail];
has_more = true;
}
__enable_irq();
if (has_more) {
HAL_UART_Transmit_IT(&huart2, &byte, 1);
}
}
bool UART2_Print_IsBusy(void)
{
bool busy;
__disable_irq();
busy = tx_ring.is_sending || (tx_ring.count > 0);
__enable_irq();
return busy;
}
uint16_t UART2_Print_Available(void)
{
uint16_t available;
__disable_irq();
available = UART2_TX_BUFFER_SIZE - tx_ring.count;
__enable_irq();
return available;
}
uint16_t UART2_Print_GetOverflowCount(void)
{
return tx_ring.overflow_count;
}
/**
* @brief printf重定向函数 (Keil MDK)
* @note 重定向标准库printf到UART2
* @param ch: 待发送字符
* @param f: 文件指针(未使用)
* @retval 发送的字符
*/
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
int fputc(int ch, FILE *f)
{
(void)f;
UART2_Print_Send((uint8_t *)&ch, 1);
return ch;
}
#endif
/**
* @brief printf重定向函数 (GCC)
* @note 重定向标准库printf到UART2
* @param ch: 待发送字符
* @retval 发送的字符
*/
#if defined(__GNUC__)
int __io_putchar(int ch)
{
UART2_Print_Send((uint8_t *)&ch, 1);
return ch;
}
int _write(int file, char *ptr, int len)
{
(void)file;
UART2_Print_Send((uint8_t *)ptr, len);
return len;
}
#endif