STM32 UART传输数据乱序求助:复位后数据循环错位
问题分析与解决方案
核心原因
你遇到的乱序问题,本质是接收端的缓冲区管理逻辑错误,导致新接收的数据没有覆盖旧缓冲区,而是从上次接收结束的位置继续写入,甚至出现循环覆盖,最终显示时新旧数据混杂。
具体来说,大概率是这两种情况:
- 每次在接收完成回调中调用
HAL_UART_Receive_IT时,传入的不是缓冲区的起始地址,而是偏移后的地址(比如rx_buf + len),导致新数据写入缓冲区后半段,旧数据留在前半段; - 没有在接收完成后复位接收状态或缓冲区索引,新数据写入时覆盖了部分旧数据,形成错位的混合结果。
解决步骤
1. 修正接收中断的启动逻辑
确保每次启动UART接收中断时,都从缓冲区的起始地址接收完整的13字节:
// 全局变量定义 uint8_t rx_buf[13]; uint8_t rx_complete = 0; // 接收完成标志 // 主循环前首次启动中断 HAL_UART_Receive_IT(&huartX, rx_buf, 13); // 接收完成回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USARTx) { rx_complete = 1; // 标记本次接收完成 // 重新启动中断,必须从缓冲区起始地址接收13字节 HAL_UART_Receive_IT(&huartX, rx_buf, 13); } }
2. 主循环中安全处理接收数据
为了避免中断写入和主循环读取的冲突,需要在读取缓冲区时做临界区保护,同时只在接收完成后更新显示数据:
uint32_t last_update = 0; uint8_t display_buf[13]; // 用于显示的缓冲区,避免直接操作接收缓冲区 while (1) { // 处理接收完成的数据 if (rx_complete) { // 关闭UART接收中断,避免复制时被打断 __HAL_UART_DISABLE_IT(&huartX, UART_IT_RXNE); // 复制接收数据到显示缓冲区 memcpy(display_buf, rx_buf, 13); rx_complete = 0; // 重新开启中断 __HAL_UART_ENABLE_IT(&huartX, UART_IT_RXNE); } // 每1秒更新LCD显示 if (HAL_GetTick() - last_update >= 1000) { // 调用你的LCD更新函数,传入display_buf TFT_Update_Display(display_buf, 13); last_update = HAL_GetTick(); } }
3. 排查其他潜在问题
- 发送端初始化验证:确保发送端的5秒延迟是在串口初始化完成后执行的,避免串口配置未就绪就发送数据;
- 中断优先级检查:确认UART接收中断的优先级高于其他非关键中断,防止接收过程被长时间阻塞导致字节错位;
- 缓冲区清零:可以在每次接收完成后,用
memset(rx_buf, 0, 13)清空缓冲区,避免残留旧数据干扰。
内容的提问来源于stack exchange,提问作者choco holic
相关产品推荐
相关产品推荐

