You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:30:22