shuichan_old/V1.5/STM32F103_App1/HardWare/UART/uart.c

447 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
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 uart2_rx_byte = 0;
volatile uint32_t g_uart2_rx_byte_cnt = 0; /* USART2 累计收到的字节数485 排障用) */
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;
#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)
* 上电初始 115200ESP-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_RXReceive_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 错误处理后 RxState 常卡 BUSY_RXReceive_IT 会静默失败,接收永久停摆 */
HAL_UART_Receive_IT(&huart2, &uart2_rx_byte, 1); /* RS485 秤口同样自愈 */
}
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_RXReceive_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));
HAL_UART_Receive_IT(&huart2, &uart2_rx_byte, 1);
}
/* 清 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_IT(&huart2, &uart2_rx_byte, 1);
}
}
/* 从 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) {
uint8_t ch = uart2_rx_byte;
g_uart2_rx_byte_cnt++;
if (uart2_cmd_index < UART2_RX_BUF_SIZE - 1) {
uart2_cmd_buf[uart2_cmd_index++] = ch;
uart2_last_rx_tick = HAL_GetTick();
}
HAL_UART_Receive_IT(&huart2, &uart2_rx_byte, 1);
}
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_cmd_index > 0 &&
(HAL_GetTick() - uart2_last_rx_tick) > UART2_CMD_TIMEOUT_MS) {
/* 排障帧提交时打印内容485 丢帧定位) */
char hex[3 * 24 + 1] = {0};
uint16_t n0 = uart2_cmd_index < 24 ? uart2_cmd_index : 24;
for (uint16_t i = 0; i < n0; i++) snprintf(hex + i * 3, 4, "%02X ", uart2_cmd_buf[i]);
log_info("> UART2: 帧提交 %d 字节: %s", (int)uart2_cmd_index, hex);
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;
uart2_rx_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;
}