475 lines
16 KiB
C
475 lines
16 KiB
C
#include "uart.h"
|
||
#include "network.h"
|
||
#include "log.h"
|
||
#include "hlw8032.h"
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
|
||
UART_HandleTypeDef huart1;
|
||
UART_HandleTypeDef huart2;
|
||
UART_HandleTypeDef huart3;
|
||
UART_HandleTypeDef huart4;
|
||
UART_HandleTypeDef huart5;
|
||
DMA_HandleTypeDef hdma_usart2_rx;
|
||
|
||
uint16_t Rx_Len = 0;
|
||
uint8_t Rx_Buf[Rx_Max] = {0};
|
||
|
||
volatile uint8_t uart1_rx_ready = 0;
|
||
uint8_t uart1_rx_buf[UART1_RX_BUF_SIZE] = {0};
|
||
|
||
/* 诊断计数:UART4 高吞吐接收健康状况(OTA 排障用) */
|
||
volatile uint32_t g_uart4_rxcplt_cnt = 0; /* DMA 填满重启次数 */
|
||
volatile uint32_t g_uart4_ore_cnt = 0; /* 溢出错误次数 */
|
||
|
||
volatile uint8_t uart2_rx_ready = 0;
|
||
uint8_t uart2_rx_buf[UART2_RX_BUF_SIZE] = {0};
|
||
|
||
static uint8_t uart1_rx_byte = 0;
|
||
static uint8_t uart1_cmd_buf[UART1_RX_BUF_SIZE] = {0};
|
||
static uint8_t uart1_cmd_index = 0;
|
||
static uint32_t uart1_last_rx_tick = 0;
|
||
|
||
static uint8_t uart5_rx_byte = 0;
|
||
static uint8_t uart2_cmd_buf[UART2_RX_BUF_SIZE] = {0};
|
||
static uint8_t uart2_cmd_index = 0;
|
||
static uint32_t uart2_last_rx_tick = 0;
|
||
|
||
/* USART2 DMA 接收(485 秤):DMA 填 dma_buf,线路静默产生 IDLE 中断即为一帧 */
|
||
uint8_t uart2_dma_buf[64];
|
||
uint8_t uart2_frame_buf[64];
|
||
volatile uint16_t uart2_frame_len = 0;
|
||
volatile uint8_t uart2_frame_ready = 0;
|
||
|
||
#define UART1_CMD_TIMEOUT_MS 100u /* 无换行时,字符间隔超过该时间视为命令结束 */
|
||
#define UART2_CMD_TIMEOUT_MS 20u /* 485 返回帧较短,20ms 视为帧结束 */
|
||
|
||
|
||
|
||
|
||
void MX_USART1_UART_Init(void)
|
||
{
|
||
huart1.Instance = USART1;
|
||
huart1.Init.BaudRate = 115200;
|
||
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
||
huart1.Init.StopBits = UART_STOPBITS_1;
|
||
huart1.Init.Parity = UART_PARITY_NONE;
|
||
huart1.Init.Mode = UART_MODE_TX_RX;
|
||
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
|
||
if (HAL_UART_Init(&huart1) != HAL_OK) Error_Handler();
|
||
}
|
||
|
||
void MX_USART2_UART_Init(void)
|
||
{
|
||
huart2.Instance = USART2;
|
||
huart2.Init.BaudRate = 9600;
|
||
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
||
huart2.Init.StopBits = UART_STOPBITS_1;
|
||
huart2.Init.Parity = UART_PARITY_NONE;
|
||
huart2.Init.Mode = UART_MODE_TX_RX;
|
||
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
|
||
if (HAL_UART_Init(&huart2) != HAL_OK) Error_Handler();
|
||
}
|
||
|
||
void MX_USART3_UART_Init(void)
|
||
{
|
||
huart3.Instance = USART3;
|
||
huart3.Init.BaudRate = 115200; /* 上电默认 115200(安全档),cat_connect_network 里再自适应切 921600 */
|
||
huart3.Init.WordLength = UART_WORDLENGTH_8B;
|
||
huart3.Init.StopBits = UART_STOPBITS_1;
|
||
huart3.Init.Parity = UART_PARITY_NONE;
|
||
huart3.Init.Mode = UART_MODE_TX_RX;
|
||
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
|
||
if (HAL_UART_Init(&huart3) != HAL_OK) Error_Handler();
|
||
}
|
||
|
||
/* UART4: WiFi ESP-01S 模块 (PC10=TX -> ESP_RXD, PC11=RX <- ESP_TXD)
|
||
* 上电初始 115200(ESP-01S AT 固件出厂默认),
|
||
* esp_reset 里探测成功后会用 AT+UART_DEF 固定为 WIFI_BAUD_TARGET */
|
||
void MX_UART4_UART_Init(void)
|
||
{
|
||
huart4.Instance = UART4;
|
||
huart4.Init.BaudRate = 115200;
|
||
huart4.Init.WordLength = UART_WORDLENGTH_8B;
|
||
huart4.Init.StopBits = UART_STOPBITS_1;
|
||
huart4.Init.Parity = UART_PARITY_NONE;
|
||
huart4.Init.Mode = UART_MODE_TX_RX;
|
||
huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||
huart4.Init.OverSampling = UART_OVERSAMPLING_16;
|
||
if (HAL_UART_Init(&huart4) != HAL_OK) Error_Handler();
|
||
}
|
||
|
||
/* UART5: HLW8032 计量芯片 (PD2=RX <- 芯片 TXD),4800 8E1。
|
||
* 芯片只发不收,TX(PC12) 不配置;8 数据位+偶校验在 F1 上要按 9 位帧长配置 */
|
||
void MX_UART5_UART_Init(void)
|
||
{
|
||
huart5.Instance = UART5;
|
||
huart5.Init.BaudRate = 4800;
|
||
huart5.Init.WordLength = UART_WORDLENGTH_9B;
|
||
huart5.Init.StopBits = UART_STOPBITS_1;
|
||
huart5.Init.Parity = UART_PARITY_EVEN;
|
||
huart5.Init.Mode = UART_MODE_RX;
|
||
huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||
huart5.Init.OverSampling = UART_OVERSAMPLING_16;
|
||
if (HAL_UART_Init(&huart5) != HAL_OK) Error_Handler();
|
||
}
|
||
|
||
void UART5_StartRx(void)
|
||
{
|
||
HAL_UART_Receive_IT(&huart5, &uart5_rx_byte, 1);
|
||
}
|
||
|
||
void USART3_StartRx(void)
|
||
{
|
||
/* 避免重复启动 DMA: 若已在接收则先停止再启动 */
|
||
if (huart3.RxState != HAL_UART_STATE_READY) {
|
||
HAL_UART_DMAStop(&huart3);
|
||
}
|
||
HAL_UART_Receive_DMA(&huart3, Rx_Buf, Rx_Max);
|
||
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
|
||
}
|
||
|
||
/* 停止 USART3 DMA 接收:WiFi/4G 互斥复用 Rx_Buf,切 WiFi 通道时必须先停 4G 接收 */
|
||
void USART3_StopRx(void)
|
||
{
|
||
__HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE);
|
||
HAL_UART_DMAStop(&huart3);
|
||
}
|
||
|
||
/* 启动 UART4 DMA+IDLE 接收:与 USART3 复用同一块 Rx_Buf(两通道互斥,靠 StartRx/StopRx 保证) */
|
||
void UART4_StartRx(void)
|
||
{
|
||
if (huart4.RxState != HAL_UART_STATE_READY) {
|
||
HAL_UART_DMAStop(&huart4);
|
||
}
|
||
HAL_UART_Receive_DMA(&huart4, Rx_Buf, Rx_Max);
|
||
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
|
||
}
|
||
|
||
void UART4_StopRx(void)
|
||
{
|
||
__HAL_UART_DISABLE_IT(&huart4, UART_IT_IDLE);
|
||
HAL_UART_DMAStop(&huart4);
|
||
}
|
||
|
||
/* 运行中切换 UART4 波特率:只重写 BRR 寄存器,不动 GPIO/NVIC/DMA 配置。
|
||
* UART4 挂在 APB1(36MHz) 上 */
|
||
void UART4_SetBaudRate(uint32_t baud)
|
||
{
|
||
if (huart4.RxState != HAL_UART_STATE_READY) {
|
||
HAL_UART_DMAStop(&huart4);
|
||
}
|
||
huart4.Init.BaudRate = baud;
|
||
UART4->BRR = UART_BRR_SAMPLING16(36000000u, baud);
|
||
__HAL_UART_CLEAR_PEFLAG(&huart4);
|
||
__HAL_UART_CLEAR_FEFLAG(&huart4);
|
||
__HAL_UART_CLEAR_NEFLAG(&huart4);
|
||
__HAL_UART_CLEAR_OREFLAG(&huart4);
|
||
__HAL_UART_CLEAR_IDLEFLAG(&huart4);
|
||
HAL_UART_Receive_DMA(&huart4, Rx_Buf, Rx_Max);
|
||
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
|
||
}
|
||
|
||
/* UART 错误回调:ORE(溢出) 等错误会让 HAL 中止整个 DMA 接收
|
||
* (stm32f1xx_hal_uart.c: UART_EndRxTransfer + HAL_DMA_Abort_IT),
|
||
* 此后模块应答全丢,必须立即重新武装接收。
|
||
* 921600 高波特率下,模块连续突发数据撞上 IDLE 处理的 DMA 重启窗口
|
||
* 时容易触发 ORE,这里按当前激活的网络通道自愈。 */
|
||
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
|
||
{
|
||
if (huart->Instance == UART4) {
|
||
g_uart4_ore_cnt++;
|
||
__HAL_UART_CLEAR_OREFLAG(huart);
|
||
__HAL_UART_CLEAR_PEFLAG(huart);
|
||
__HAL_UART_CLEAR_FEFLAG(huart);
|
||
__HAL_UART_CLEAR_NEFLAG(huart);
|
||
__HAL_UART_CLEAR_IDLEFLAG(huart);
|
||
huart->ErrorCode = HAL_UART_ERROR_NONE;
|
||
if (NET_GetActiveBackend() == NET_BACKEND_WIFI) {
|
||
HAL_UART_Receive_DMA(&huart4, Rx_Buf, Rx_Max);
|
||
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
|
||
}
|
||
}
|
||
else if (huart->Instance == USART1) {
|
||
__HAL_UART_CLEAR_OREFLAG(huart);
|
||
__HAL_UART_CLEAR_PEFLAG(huart);
|
||
__HAL_UART_CLEAR_FEFLAG(huart);
|
||
__HAL_UART_CLEAR_NEFLAG(huart);
|
||
__HAL_UART_CLEAR_IDLEFLAG(huart);
|
||
huart->ErrorCode = HAL_UART_ERROR_NONE;
|
||
huart1.RxState = HAL_UART_STATE_READY; /* 关键:HAL 错误处理后 RxState 常卡 BUSY_RX,Receive_IT 会静默失败,接收永久停摆 */
|
||
HAL_UART_Receive_IT(&huart1, &uart1_rx_byte, 1); /* 蓝牙/调试口被 ORE 弄挂后立即恢复接收 */
|
||
}
|
||
else if (huart->Instance == USART2) {
|
||
__HAL_UART_CLEAR_OREFLAG(huart);
|
||
__HAL_UART_CLEAR_PEFLAG(huart);
|
||
__HAL_UART_CLEAR_FEFLAG(huart);
|
||
__HAL_UART_CLEAR_NEFLAG(huart);
|
||
__HAL_UART_CLEAR_IDLEFLAG(huart);
|
||
huart->ErrorCode = HAL_UART_ERROR_NONE;
|
||
huart2.RxState = HAL_UART_STATE_READY;
|
||
HAL_UART_Receive_DMA(&huart2, uart2_dma_buf, sizeof(uart2_dma_buf)); /* RS485 秤口 DMA 自愈 */
|
||
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
|
||
}
|
||
else if (huart->Instance == UART5) {
|
||
__HAL_UART_CLEAR_OREFLAG(huart);
|
||
__HAL_UART_CLEAR_PEFLAG(huart);
|
||
__HAL_UART_CLEAR_FEFLAG(huart);
|
||
__HAL_UART_CLEAR_NEFLAG(huart);
|
||
__HAL_UART_CLEAR_IDLEFLAG(huart);
|
||
huart->ErrorCode = HAL_UART_ERROR_NONE;
|
||
huart5.RxState = HAL_UART_STATE_READY; /* 关键:HAL 错误处理后 RxState 常卡 BUSY_RX,Receive_IT 会静默失败,接收永久停摆 */
|
||
HAL_UART_Receive_IT(&huart5, &uart5_rx_byte, 1); /* HLW8032 口同样自愈 */
|
||
}
|
||
else if (huart->Instance == USART3) {
|
||
__HAL_UART_CLEAR_OREFLAG(huart);
|
||
__HAL_UART_CLEAR_PEFLAG(huart);
|
||
__HAL_UART_CLEAR_FEFLAG(huart);
|
||
__HAL_UART_CLEAR_NEFLAG(huart);
|
||
__HAL_UART_CLEAR_IDLEFLAG(huart);
|
||
huart->ErrorCode = HAL_UART_ERROR_NONE;
|
||
if (NET_GetActiveBackend() == NET_BACKEND_4G) {
|
||
HAL_UART_Receive_DMA(&huart3, Rx_Buf, Rx_Max);
|
||
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 运行中切换 USART3 波特率:只重写 BRR 寄存器,不动 GPIO/NVIC/DMA 配置。
|
||
* USART3 挂在 APB1(36MHz) 上 */
|
||
void USART3_SetBaudRate(uint32_t baud)
|
||
{
|
||
if (huart3.RxState != HAL_UART_STATE_READY) {
|
||
HAL_UART_DMAStop(&huart3);
|
||
}
|
||
huart3.Init.BaudRate = baud;
|
||
USART3->BRR = UART_BRR_SAMPLING16(36000000u, baud);
|
||
__HAL_UART_CLEAR_PEFLAG(&huart3);
|
||
__HAL_UART_CLEAR_FEFLAG(&huart3);
|
||
__HAL_UART_CLEAR_NEFLAG(&huart3);
|
||
__HAL_UART_CLEAR_OREFLAG(&huart3);
|
||
__HAL_UART_CLEAR_IDLEFLAG(&huart3);
|
||
HAL_UART_Receive_DMA(&huart3, Rx_Buf, Rx_Max);
|
||
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
|
||
}
|
||
|
||
void USART1_StartRx(void)
|
||
{
|
||
uart1_rx_ready = 0;
|
||
uart1_cmd_index = 0;
|
||
uart1_last_rx_tick = 0;
|
||
memset(uart1_cmd_buf, 0, sizeof(uart1_cmd_buf));
|
||
memset(uart1_rx_buf, 0, sizeof(uart1_rx_buf));
|
||
HAL_UART_Receive_IT(&huart1, &uart1_rx_byte, 1);
|
||
}
|
||
|
||
void USART2_StartRx(void)
|
||
{
|
||
uart2_rx_ready = 0;
|
||
uart2_cmd_index = 0;
|
||
uart2_last_rx_tick = 0;
|
||
memset(uart2_cmd_buf, 0, sizeof(uart2_cmd_buf));
|
||
memset(uart2_rx_buf, 0, sizeof(uart2_rx_buf));
|
||
uart2_frame_ready = 0;
|
||
uart2_frame_len = 0;
|
||
HAL_UART_Receive_DMA(&huart2, uart2_dma_buf, sizeof(uart2_dma_buf));
|
||
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
|
||
}
|
||
|
||
/* 清 USART2 软件接收缓冲(不动硬件)。
|
||
* 485 查询前调用,丢弃缓冲里残留的回声/垃圾,让应答帧从干净状态开始。
|
||
* 注意:不要在这里 AbortReceive/重挂中断——实测会把接收搞死,
|
||
* 硬件接收从开机起常开(ISR 逐字节重挂 + ORE 自愈),不需要动 */
|
||
uint16_t USART2_GetRxIndex(void) { return uart2_cmd_index; } /* 排障用 */
|
||
|
||
void USART2_FlushRxBuf(void)
|
||
{
|
||
if (uart2_cmd_index > 0) {
|
||
char hex[3 * 24 + 1] = {0};
|
||
uint16_t n = uart2_cmd_index < 24 ? uart2_cmd_index : 24;
|
||
for (uint16_t i = 0; i < n; i++) snprintf(hex + i * 3, 4, "%02X ", uart2_cmd_buf[i]);
|
||
log_warn("> UART2: 清缓冲丢弃 %d 字节: %s", (int)uart2_cmd_index, hex);
|
||
}
|
||
uart2_rx_ready = 0;
|
||
uart2_cmd_index = 0;
|
||
/* 兜底:接收中断意外停摆时(ORE 后状态卡 BUSY_RX)拉起来。不 Abort,不动正常状态 */
|
||
if (!(USART2->CR1 & USART_CR1_RXNEIE)) {
|
||
__HAL_UART_CLEAR_OREFLAG(&huart2);
|
||
huart2.ErrorCode = HAL_UART_ERROR_NONE;
|
||
huart2.RxState = HAL_UART_STATE_READY;
|
||
HAL_UART_Receive_DMA(&huart2, uart2_dma_buf, sizeof(uart2_dma_buf));
|
||
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
|
||
}
|
||
}
|
||
|
||
/* 从 USART2 接收缓冲区取出一帧(20ms 无新字节结束),返回帧长度,0 表示暂无完整帧 */
|
||
uint16_t USART2_GetFrame(uint8_t *out, uint16_t out_size)
|
||
{
|
||
if (uart2_rx_ready) {
|
||
uart2_rx_ready = 0;
|
||
uint16_t len = uart2_cmd_index < out_size ? uart2_cmd_index : out_size - 1;
|
||
memcpy(out, uart2_cmd_buf, len);
|
||
out[len] = '\0';
|
||
uart2_cmd_index = 0;
|
||
return len;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 中断接收回调:把单个字符追加到命令缓冲区,回车换行结束;
|
||
* 无换行时,字符间隔超过 UART1_CMD_TIMEOUT_MS 自动提交 */
|
||
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
|
||
{
|
||
if (huart->Instance == USART1) {
|
||
uint8_t ch = uart1_rx_byte;
|
||
if (ch == '\r' || ch == '\n') {
|
||
if (uart1_cmd_index > 0) {
|
||
uart1_cmd_buf[uart1_cmd_index] = '\0';
|
||
memcpy(uart1_rx_buf, uart1_cmd_buf, uart1_cmd_index + 1);
|
||
uart1_rx_ready = 1;
|
||
uart1_cmd_index = 0;
|
||
}
|
||
} else if (uart1_cmd_index < UART1_RX_BUF_SIZE - 1) {
|
||
uart1_cmd_buf[uart1_cmd_index++] = ch;
|
||
uart1_last_rx_tick = HAL_GetTick();
|
||
}
|
||
HAL_UART_Receive_IT(&huart1, &uart1_rx_byte, 1);
|
||
}
|
||
else if (huart->Instance == USART2) {
|
||
/* DMA(NORMAL) 填满 64B:垃圾洪泛场景,把内容当一帧提交并重启接收 */
|
||
HAL_UART_DMAStop(&huart2);
|
||
if (!uart2_frame_ready) {
|
||
memcpy(uart2_frame_buf, uart2_dma_buf, sizeof(uart2_dma_buf));
|
||
uart2_frame_len = sizeof(uart2_dma_buf);
|
||
uart2_frame_ready = 1;
|
||
}
|
||
HAL_UART_Receive_DMA(&huart2, uart2_dma_buf, sizeof(uart2_dma_buf));
|
||
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
|
||
}
|
||
else if (huart->Instance == UART5) {
|
||
hlw8032_rx_byte(uart5_rx_byte);
|
||
HAL_UART_Receive_IT(&huart5, &uart5_rx_byte, 1);
|
||
}
|
||
else if (huart->Instance == UART4) {
|
||
/* DMA(NORMAL) 填满 Rx_Buf:连续数据流没有空闲间隙、IDLE 不触发,
|
||
* 若不在这里搬运并重启,接收将永久停摆(WiFi OTA 大流量下载必现) */
|
||
g_uart4_rxcplt_cnt++;
|
||
if (NET_GetActiveBackend() == NET_BACKEND_WIFI &&
|
||
(U2_CopyIndex + Rx_Max) < (U2_COPY_SIZE - 1)) {
|
||
memcpy(U2_CopyBuff + U2_CopyIndex, Rx_Buf, Rx_Max);
|
||
U2_CopyIndex += Rx_Max;
|
||
U2_CopyBuff[U2_CopyIndex] = '\0';
|
||
U2_CopyFlag = 1;
|
||
}
|
||
__HAL_UART_CLEAR_IDLEFLAG(&huart4);
|
||
HAL_UART_Receive_DMA(&huart4, Rx_Buf, Rx_Max);
|
||
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
|
||
}
|
||
else if (huart->Instance == USART3) {
|
||
/* 同理:4G 侧理论上也可能遇到连续无间隙数据流 */
|
||
if (NET_GetActiveBackend() == NET_BACKEND_4G &&
|
||
(U2_CopyIndex + Rx_Max) < (U2_COPY_SIZE - 1)) {
|
||
memcpy(U2_CopyBuff + U2_CopyIndex, Rx_Buf, Rx_Max);
|
||
U2_CopyIndex += Rx_Max;
|
||
U2_CopyBuff[U2_CopyIndex] = '\0';
|
||
U2_CopyFlag = 1;
|
||
}
|
||
__HAL_UART_CLEAR_IDLEFLAG(&huart3);
|
||
HAL_UART_Receive_DMA(&huart3, Rx_Buf, Rx_Max);
|
||
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
|
||
}
|
||
}
|
||
|
||
/* 原子取帧:20ms 静默判帧完整 → 直接拷出并清缓冲,一步完成。
|
||
* 替代旧的 Tick(置标志)+GetFrame(取帧) 两步交接——两步之间被查询/补发的
|
||
* 清缓冲打断时会丢帧(485 丢帧根因) */
|
||
uint16_t USART2_PollFrame(uint8_t *out, uint16_t out_size)
|
||
{
|
||
if (uart2_frame_ready) {
|
||
/* 排障:帧提交时打印内容 */
|
||
char hex[3 * 24 + 1] = {0};
|
||
uint16_t n0 = uart2_frame_len < 24 ? uart2_frame_len : 24;
|
||
for (uint16_t k = 0; k < n0; k++) snprintf(hex + k * 3, 4, "%02X ", uart2_frame_buf[k]);
|
||
log_info("> UART2: 帧提交 %d 字节: %s", (int)uart2_frame_len, hex);
|
||
uint16_t len = uart2_frame_len < out_size ? uart2_frame_len : out_size - 1;
|
||
memcpy(out, uart2_frame_buf, len);
|
||
out[len] = 0;
|
||
uart2_frame_ready = 0;
|
||
return len;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 在 USART2_GetFrame 被轮询前,20ms 无新字节自动提交帧 */
|
||
void USART2_Tick(void)
|
||
{
|
||
if (uart2_cmd_index > 0 &&
|
||
(HAL_GetTick() - uart2_last_rx_tick) > UART2_CMD_TIMEOUT_MS) {
|
||
/* 排障:帧提交时打印内容(485 丢帧定位) */
|
||
char hex[3 * 24 + 1] = {0};
|
||
uint16_t n = uart2_cmd_index < 24 ? uart2_cmd_index : 24;
|
||
for (uint16_t i = 0; i < n; i++) snprintf(hex + i * 3, 4, "%02X ", uart2_cmd_buf[i]);
|
||
log_info("> UART2: 帧提交 %d 字节: %s", (int)uart2_cmd_index, hex);
|
||
uart2_rx_ready = 1;
|
||
}
|
||
}
|
||
|
||
/* 不区分大小写的字符串比较 */
|
||
static int uart_strcasecmp(const char *a, const char *b)
|
||
{
|
||
while (*a && *b) {
|
||
char ca = (char)toupper((unsigned char)*a);
|
||
char cb = (char)toupper((unsigned char)*b);
|
||
if (ca != cb) return ca - cb;
|
||
a++;
|
||
b++;
|
||
}
|
||
return (char)toupper((unsigned char)*a) - (char)toupper((unsigned char)*b);
|
||
}
|
||
|
||
/* 检查 USART1 是否收到指定命令(不区分大小写),检查后清除 ready */
|
||
int USART1_CheckCommand(const char *cmd)
|
||
{
|
||
const char *got = USART1_GetCommand();
|
||
if (!got) return 0;
|
||
return (uart_strcasecmp(got, cmd) == 0);
|
||
}
|
||
|
||
/* 获取当前接收到的命令字符串(用于自定义解析)。
|
||
* 支持两种结束方式:收到 \r/\n 立即结束;无换行时字符间隔超过 100ms 自动结束。 */
|
||
const char *USART1_GetCommand(void)
|
||
{
|
||
if (uart1_rx_ready) {
|
||
uart1_rx_ready = 0;
|
||
return (const char *)uart1_rx_buf;
|
||
}
|
||
|
||
if (uart1_cmd_index > 0 &&
|
||
(HAL_GetTick() - uart1_last_rx_tick) > UART1_CMD_TIMEOUT_MS) {
|
||
uart1_cmd_buf[uart1_cmd_index] = '\0';
|
||
memcpy(uart1_rx_buf, uart1_cmd_buf, uart1_cmd_index + 1);
|
||
uart1_cmd_index = 0;
|
||
return (const char *)uart1_rx_buf;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
/*==== RS485 总线活动时间戳(秤与扩展继电器板共用 USART2) ====
|
||
* 任何一帧收发都 touch 一次; 发送方等总线静默 >=50ms 再发,
|
||
* 防止从机 485 释放/回声沉降期内撞帧(采集终端实测踩坑) */
|
||
static volatile uint32_t s_rs485_bus_tick = 0;
|
||
|
||
void rs485_bus_touch(void)
|
||
{
|
||
s_rs485_bus_tick = HAL_GetTick();
|
||
}
|
||
|
||
uint32_t rs485_bus_last_tick(void)
|
||
{
|
||
return s_rs485_bus_tick;
|
||
}
|