Files
mcu-codegen-template/App/Core/jb_uart.c
T

281 lines
7.2 KiB
C

/******************************************************************************
* @file jb_uart.c
* @brief USART3 协议串口驱动实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.10
* @version V1.0.0
* @history
* - V1.0.0, 2026.08.10, cyWu, 首次发布
******************************************************************************/
#include "jb_uart.h"
#include "log.h"
#include <string.h>
/*============================================================================*/
/* 私有宏 */
/*============================================================================*/
#define UART_DBG_BUF_SIZE (256U)
#define UART_DBG_IDLE_MS (30U)
/* 协议 MAX_PACKAGE_LEN(128) + 前置 0x00 */
#define JB_UART_TX_MAX_LEN (129U)
/*============================================================================*/
/* 私有变量 */
/*============================================================================*/
UART_HandleTypeDef g_jb_uart_handle;
static uint8_t s_initialized;
static uint8_t s_uart_rx_byte;
static JbUartRxCallback_t s_rx_cb;
static uint8_t s_dbg_buf[UART_DBG_BUF_SIZE];
static volatile uint16_t s_dbg_head;
static volatile uint16_t s_dbg_tail;
static volatile uint32_t s_dbg_last_rx_ms;
static volatile uint32_t s_rx_total;
static volatile uint32_t s_err_code;
static volatile uint8_t s_err_pending;
/*============================================================================*/
/* 私有函数 */
/*============================================================================*/
/**
* @brief ISR 安全:调试缓冲写入 1 字节
* @param byte 数据
*/
static void uart_dbg_push(uint8_t byte)
{
uint16_t next = (uint16_t)((s_dbg_head + 1U) % UART_DBG_BUF_SIZE);
if (next == s_dbg_tail)
{
s_dbg_tail = (uint16_t)((s_dbg_tail + 1U) % UART_DBG_BUF_SIZE);
}
s_dbg_buf[s_dbg_head] = byte;
s_dbg_head = next;
s_dbg_last_rx_ms = HAL_GetTick();
s_rx_total++;
}
/**
* @brief 打印十六进制
* @param tag 标签
* @param buf 数据
* @param len 长度
*/
static void uart_dbg_print_hex(const char *tag, const uint8_t *buf, uint32_t len)
{
uint32_t i;
printf("UART %s %lu bytes:", tag, (unsigned long)len);
for (i = 0; i < len; i++)
{
printf(" %02X", buf[i]);
}
printf("\r\n");
}
/**
* @brief 刷出 RX 调试与错误日志
*/
static void uart_dbg_flush(void)
{
uint8_t dump[UART_DBG_BUF_SIZE];
uint16_t dump_len = 0;
uint16_t tail;
uint16_t head;
if (s_err_pending)
{
s_err_pending = 0;
printf("UART RX error: 0x%08lX, total_rx=%lu\r\n",
(unsigned long)s_err_code,
(unsigned long)s_rx_total);
}
head = s_dbg_head;
tail = s_dbg_tail;
if (head == tail)
{
return;
}
if ((HAL_GetTick() - s_dbg_last_rx_ms) < UART_DBG_IDLE_MS)
{
return;
}
while ((tail != head) && (dump_len < UART_DBG_BUF_SIZE))
{
dump[dump_len++] = s_dbg_buf[tail];
tail = (uint16_t)((tail + 1U) % UART_DBG_BUF_SIZE);
}
s_dbg_tail = tail;
uart_dbg_print_hex("RX", dump, dump_len);
printf("UART RX total=%lu\r\n", (unsigned long)s_rx_total);
}
/*============================================================================*/
/* 公有接口 */
/*============================================================================*/
/**
* @brief 注册 RX 回调
* @param cb 回调
*/
void jb_uart_set_rx_callback(JbUartRxCallback_t cb)
{
s_rx_cb = cb;
}
/**
* @brief 初始化 USART3
* @return JbUart_Ret_t
*/
JbUart_Ret_t jb_uart_init(void)
{
if (s_initialized)
{
return JB_UART_OK;
}
g_jb_uart_handle.Instance = JB_USART;
g_jb_uart_handle.Init.BaudRate = JB_UART_BAUDRATE;
g_jb_uart_handle.Init.WordLength = UART_WORDLENGTH_8B;
g_jb_uart_handle.Init.StopBits = UART_STOPBITS_1;
g_jb_uart_handle.Init.Parity = UART_PARITY_NONE;
g_jb_uart_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
g_jb_uart_handle.Init.Mode = UART_MODE_TX_RX;
g_jb_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16;
g_jb_uart_handle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&g_jb_uart_handle) != HAL_OK)
{
return JB_UART_ERR_HAL;
}
if (HAL_UART_Receive_IT(&g_jb_uart_handle, &s_uart_rx_byte, 1U) != HAL_OK)
{
return JB_UART_ERR_HAL;
}
s_initialized = 1U;
printf("USART3 ready: PB10=TX PB11=RX baud=%lu 8N1, waiting RX...\r\n",
(unsigned long)JB_UART_BAUDRATE);
return JB_UART_OK;
}
/**
* @brief 主循环周期处理
*/
void jb_uart_run(void)
{
if (!s_initialized)
{
return;
}
uart_dbg_flush();
}
/**
* @brief 阻塞发送
* @param buf 数据
* @param len 长度
* @return 成功返回 len,失败 -1
*/
int32_t jb_uart_write(uint8_t *buf, uint32_t len)
{
static uint8_t s_tx_buf[JB_UART_TX_MAX_LEN];
uint32_t tx_len;
if (!buf)
{
return -1;
}
if (len == 0U)
{
return 0;
}
if (!s_initialized)
{
return -1;
}
if ((len + 1U) > JB_UART_TX_MAX_LEN)
{
return -1;
}
/* 协议帧前加 0x00 后连续发送,避免越界读与帧间空隙 */
s_tx_buf[0] = 0x00U;
s_tx_buf[1] = 0x00U;
memcpy(&s_tx_buf[2], buf, len);
tx_len = len + 2U;
uart_dbg_print_hex("TX", s_tx_buf, tx_len);
if (HAL_UART_Transmit(&g_jb_uart_handle, s_tx_buf, (uint16_t)tx_len, 1000U) != HAL_OK)
{
printf("UART TX failed, len=%lu\r\n", (unsigned long)tx_len);
return -1;
}
return (int32_t)len;
}
/**
* @brief 获取初始化状态
* @return JbUart_Ret_t
*/
JbUart_Ret_t jb_uart_get_status(void)
{
if (!s_initialized)
{
return JB_UART_ERR_NOT_INIT;
}
return JB_UART_OK;
}
/*============================================================================*/
/* HAL 回调 */
/*============================================================================*/
/**
* @brief UART RX 完成回调
* @param huart 句柄
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == JB_USART)
{
uart_dbg_push(s_uart_rx_byte);
if (s_rx_cb != NULL)
{
s_rx_cb(s_uart_rx_byte);
}
(void)HAL_UART_Receive_IT(&g_jb_uart_handle, &s_uart_rx_byte, 1U);
}
}
/**
* @brief UART 错误回调
* @param huart 句柄
*/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == JB_USART)
{
s_err_code = HAL_UART_GetError(huart);
s_err_pending = 1U;
__HAL_UART_CLEAR_PEFLAG(huart);
__HAL_UART_CLEAR_FEFLAG(huart);
__HAL_UART_CLEAR_NEFLAG(huart);
__HAL_UART_CLEAR_OREFLAG(huart);
(void)HAL_UART_Receive_IT(&g_jb_uart_handle, &s_uart_rx_byte, 1U);
}
}