STM32F407 UART3转RS-485通信异常:Rx状态持续忙碌问题求助
让我帮你分析一下你遇到的问题,从代码和逻辑来看,有几个关键的地方需要修正,这应该就是导致Rx状态异常和回调后触发Error_Handler()的原因:
问题分析与修正方案
1. RS485方向控制逻辑错误
你在HAL_UART_RxCpltCallback里把RS485的DE/RE引脚(PB9)设为SET(发送模式),这是核心错误之一。接收完成后,RS485应该保持接收模式(PB9置RESET),只有在准备发送数据时才切换到发送模式。现在接收完成就切回发送模式,不仅会导致外设后续的响应无法被接收,还可能干扰总线状态,间接影响UART的状态判断。
2. 主循环中多余且错误的RxState等待
在HAL_UART_Transmit_IT之后,你添加了while(huart3.RxState != HAL_UART_STATE_READY)的等待逻辑,但RxState是接收状态,和发送操作完全无关。发送完成后RxState本来就是READY状态(除非之前有未完成的接收任务),这个等待完全多余,一旦出现异常导致RxState非READY,就会直接触发错误处理。
3. UartReady标志位的重置时机遗漏
接收完成后UartReady被设为SET,但主循环处理完接收数据后没有重置这个标志,导致下一轮循环时UartReady已经是SET,会跳过接收等待环节直接进入发送,造成时序混乱。
修正后的代码示例
主循环代码修正
#include "main.h" #include "stm32f4xx_hal.h" UART_HandleTypeDef huart3; uint8_t Ocular_1_RxBuffer[4]; uint8_t Ocular_1_TxBuffer[2] = {0x01,0x86}; __IO ITStatus UartReady = RESET; // 初始化标志位 void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART3_UART_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART3_UART_Init(); while (1) { int Timeout = 1000000; // 等待UART全局状态就绪 while(huart3.gState != HAL_UART_STATE_READY) { Timeout--; if(Timeout == 0) Error_Handler(); } // 切换到发送模式,启动发送中断 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET); if(HAL_UART_Transmit_IT(&huart3, Ocular_1_TxBuffer, 2) != HAL_OK) { Error_Handler(); } // 等待发送完成(检查TxState而非RxState) Timeout = 1000000; while(huart3.TxState != HAL_UART_STATE_READY) { Timeout--; if(Timeout == 0) Error_Handler(); } // 启动接收中断(此时已经处于接收模式) Timeout = 1000000; if(HAL_UART_Receive_IT(&huart3, Ocular_1_RxBuffer, 4) != HAL_OK) { Error_Handler(); } // 等待接收完成 Timeout = 1000000; while(UartReady == RESET) { Timeout--; if(Timeout == 0) Error_Handler(); } // 这里可以添加你的接收数据处理逻辑 // ... // 重置接收标志,为下一轮循环做准备 UartReady = RESET; } }
回调函数修正
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) { // 发送完成后,立即切换到接收模式 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET); } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) { // 接收完成,设置标志位通知主循环 UartReady = SET; // 保持接收模式,无需切换到发送模式 }
额外检查项
- 确认RS485芯片的DE/RE引脚是否短接后连接到PB9,且电平逻辑正确(高电平发送,低电平接收);
- 检查
MX_USART3_UART_Init()中是否正确开启了USART3的NVIC中断(HAL_NVIC_EnableIRQ(USART3_IRQn);); - 确保UART的波特率、数据位、停止位、奇偶校验参数和外设完全一致;
- 不需要修改
HAL_UART_IRQHandler,HAL库默认实现已经正确处理了收发中断的状态切换逻辑。
内容的提问来源于stack exchange,提问作者V.CHR.
相关产品推荐
相关产品推荐

