STM32 UART1 IDLE状态接收问题:发送操作触发IDLE标志异常解决方案问询
STM32 UART IDLE+DMA接收发送冲突解决方案
故障根因
UART的IDLE空闲检测是总线级的,无论是外部设备发送数据结束,还是你自己调用发送接口向外发数据结束,只要总线空闲达到设定阈值都会触发IDLE中断。你之前的逻辑没有区分IDLE的触发来源,把发送结束产生的IDLE误判为接收结束,才会导致接收逻辑异常。你尝试添加的TC标志判断逻辑存在逻辑错误,且单一TC标志无法覆盖所有发送场景,因此不生效。
修改方案
直接复用HAL库维护的串口状态字段gState判断当前发送状态,仅当串口未处于发送忙碌状态时才处理IDLE中断,同时补充DMA接收重启逻辑,修改后的中断代码如下:
void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* UART IDLE Interrupt */ if((__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)) { // 仅当串口空闲或仅接收忙碌时,才处理本次IDLE(过滤发送结束产生的IDLE) if(huart1.gState == HAL_UART_STATE_READY || huart1.gState == HAL_UART_STATE_BUSY_RX) { HAL_UART_DMAStop(&huart1); DMA_CounterCounted2 = __HAL_DMA_GET_COUNTER(huart1.hdmarx); if(((DMA_CounterCounted2) <= DMA_BUF_SIZE) && (DMA_CounterCounted2 != 0)) { uartIdleStateActive2 = (_Bool)ENABLE; } // 替换为你实际使用的接收缓冲区首地址,重启DMA接收 HAL_UART_Receive_DMA(&huart1, rx_buffer, DMA_BUF_SIZE); } // 所有IDLE触发都要清除标志位,避免重复进中断 __HAL_UART_CLEAR_IDLEFLAG(&huart1); } /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */ }
注意事项
- 如果你使用HAL库提供的
HAL_UART_Transmit/HAL_UART_Transmit_IT/HAL_UART_Transmit_DMA接口发送数据,不需要额外修改逻辑,gState状态会由HAL库自动更新 - 如果你是直接操作寄存器实现发送逻辑,没有调用HAL库发送API,可以自定义一个全局发送状态标志,发送前将标志置为忙碌,发送完成后置为空闲,在IDLE中断中判断该标志即可
- 代码中的
rx_buffer需要替换为你实际定义的DMA接收缓冲区首地址
内容的提问来源于stack exchange,提问作者gogogo
相关产品推荐
相关产品推荐

