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

HAL_UART_Receive_DMA仅工作一次如何修复?STM32F103RB串口回环问题

问题分析与解决方案

核心问题原因

  1. UART溢出错误未处理:普通模式DMA接收完成后,若后续有新数据到来但DMA未及时重启,会触发UART的溢出错误(ORE),导致UART被锁死,无法继续接收数据,同时错误标志会引入异常字节(如0xFC)。
  2. 回调内阻塞操作风险:HAL_UART_Transmit是阻塞函数,在中断回调中调用可能占用中断上下文,影响后续DMA重启逻辑。
  3. DMA重启前未校验UART状态:直接调用HAL_UART_Receive_DMA前未清除UART错误标志,导致接收重启失败。

修复后的代码实现

#define BUF_SIZE 16

uint8_t RX_BUF[BUF_SIZE] = {0};
uint8_t TX_BUF[BUF_SIZE] = {0};

// UART接收完成回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart->Instance == USART2)
  {
    // 清除UART溢出错误标志(关键步骤)
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE))
    {
      __HAL_UART_CLEAR_OREFLAG(huart);
    }

    // 用DMA发送替代阻塞发送,避免中断上下文阻塞
    HAL_UART_Transmit_DMA(&huart2, RX_BUF, BUF_SIZE);
  }
}

// UART发送完成回调
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart->Instance == USART2)
  {
    // 发送完成后重启DMA接收
    HAL_UART_Receive_DMA(&huart2, RX_BUF, BUF_SIZE);
  }
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();

  // 启动首次DMA接收
  HAL_UART_Receive_DMA(&huart2, RX_BUF, BUF_SIZE);

  while (1)
  {
  }
}

额外优化与排查点

  • CubeMX配置检查:确保USART2的中断优先级高于DMA中断,避免中断抢占导致逻辑混乱;同时确认DMA通道的数据宽度与UART配置一致(8位数据位对应DMA字节传输)。
  • USB-C转接器排查:若代码修复后仍有问题,可更换转接器测试——部分廉价转接器存在信号不稳定或兼容性问题,可能导致串口丢包或错误帧。
  • 数据长度匹配:若测试时发送的字节数不等于BUF_SIZE,普通模式DMA会等待缓冲区填满才触发回调。若需支持任意长度数据,可改用DMA循环模式,配合UART空闲中断实现不定长接收。

内容的提问来源于stack exchange,提问作者Herman Shpryhau

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:15:37