嵌入式开发原创教程嵌入式入门 04
UART 串口实战:中断接收、环形缓冲和命令解析
从串口自发自收到中断接收、环形缓冲区、按行解析 LED 命令,完成一个可复用的调试通道。

实验目标
实现一个串口命令:
LED,ON
LED,OFF
STATUS每行以回车换行结束。串口接收通过中断完成,主循环负责解析,不在中断中执行耗时业务。
一、配置串口
USART2:
- 115200;
- 8 数据位;
- 无校验;
- 1 停止位;
- 开启 USART2 global interrupt。
二、环形缓冲区
/* USER CODE BEGIN PV */
#define UART_RX_SIZE 256U
static uint8_t rx_byte;
static uint8_t rx_buffer[UART_RX_SIZE];
static volatile uint16_t rx_head = 0U;
static volatile uint16_t rx_tail = 0U;
static void uart_start_receive(void)
{
HAL_UART_Receive_IT(&huart2, &rx_byte, 1U);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2)
{
uint16_t next = (uint16_t)((rx_head + 1U) % UART_RX_SIZE);
if (next != rx_tail)
{
rx_buffer[rx_head] = rx_byte;
rx_head = next;
}
HAL_UART_Receive_IT(&huart2, &rx_byte, 1U);
}
}
static int uart_pop(uint8_t *value)
{
if (rx_tail == rx_head)
{
return 0;
}
*value = rx_buffer[rx_tail];
rx_tail = (uint16_t)((rx_tail + 1U) % UART_RX_SIZE);
return 1;
}
/* USER CODE END PV */在 main 函数初始化后调用:
uart_start_receive();三、按行解析命令
/* USER CODE BEGIN PV */
static char command[64];
static uint8_t command_length = 0U;
static void handle_command(const char *cmd)
{
if (strcmp(cmd, "LED,ON") == 0)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_UART_Transmit(&huart2, (uint8_t *)"OK\r\n", 4, 100);
}
else if (strcmp(cmd, "LED,OFF") == 0)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
HAL_UART_Transmit(&huart2, (uint8_t *)"OK\r\n", 4, 100);
}
else if (strcmp(cmd, "STATUS") == 0)
{
HAL_UART_Transmit(&huart2, (uint8_t *)"RUNNING\r\n", 9, 100);
}
else
{
HAL_UART_Transmit(&huart2, (uint8_t *)"ERR\r\n", 5, 100);
}
}
static void uart_process(void)
{
uint8_t ch;
while (uart_pop(&ch))
{
if (ch == '\r')
{
continue;
}
if (ch == '\n')
{
command[command_length] = '\0';
if (command_length > 0U)
{
handle_command(command);
}
command_length = 0U;
}
else if (command_length < (sizeof(command) - 1U))
{
command[command_length++] = (char)ch;
}
else
{
command_length = 0U;
HAL_UART_Transmit(&huart2, (uint8_t *)"TOO_LONG\r\n", 10, 100);
}
}
}
/* USER CODE END PV */主循环:
while (1)
{
uart_process();
HAL_Delay(5);
}四、实验步骤
- 下载程序;
- 打开串口工具;
- 选择“发送新行”;
- 输入 LED,ON 并发送;
- 输入 LED,OFF 并发送;
- 输入 STATUS 并观察回复;
- 输入未知命令,确认返回 ERR。
五、排错
串口只收到乱码
检查波特率、时钟和串口工具设置。
只收到第一个字符
检查是否在回调末尾重新调用了 HAL_UART_Receive_IT。
命令始终 ERR
确认发送时带换行,确认命令没有多余空格,确认数组长度足够。
六、进阶
- 把命令处理改成函数表;
- 加入校验和;
- 支持二进制帧;
- 为缓冲区增加高水位告警。


