STM32F303:RS485 总线冲突后反复触发 USART 中断的问题

STM32F303: Issue with USART interrupt triggering repeatedly after RS485 bus clash

我对 USART 行为有疑问,想知道你们是否可以提供帮助!我使用的是 STM32F303,它的三个 USART 正在使用中,其中 USART1 配置为异步 RS485 端口,其 DE 线自动控制。微控制器的 TX、RX 和 DE 引脚连接到 TI SN65HVD1792 RS485 收发器,该收发器提供四条线(TX+、TX-、RX+、RX-)给用户进行通信。

我正在使用中断驱动的 USART 通信,在大多数情况下它工作得很好。但是,我在处理 RS485 link 配置为双线(TX+/RX+ 和 TX-/RX- 连接在一起,形成 +ve/-ve 的错误情况时遇到问题用于传输和接收的一对电线)和总线上的多个设备同时尝试传输。发生这种情况时,STM32 将停止响应所有串行通信,直到循环上电。

仔细观察正在发生的事情,我看到 stm32f3xx_it.c 中的 USART1_IRQHandler 被反复调用 - 一遍又一遍,直到我重新启动电路板。这里调用了stm32f3xx_hal_uart.c中的HAL_UART_IRQHandler(&huart1),其作用是检查发生了哪个中断(奇偶校验错误、帧错误、噪声错误、溢出、从stop唤醒、rx寄存器不为空、tx ready, tx complete),适当处理,然后清除中断状态。但是,这些特定中断中的 none 被识别为已触发 - 执行仅通过所有 "if" 语句,函数退出,然后再次运行 - 无休止。

我找不到任何方法来识别这种情况已经发生,因为它不会抛出任何可识别的错误条件。我知道 RS485 总线冲突应该通过良好的系统设计来避免,但我们不能排除它在客户安装系统时发生的可能性 - 它需要能够识别错误,请忽略 "clashed" 消息并继续 - 需要重启它是不可接受的。

有没有人知道如何识别这种情况/阻止系统进入中断循环?

提前致谢

中断例程如下(HAL文件版本1.2.0,日期15-11-13)

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  /* UART parity error interrupt occurred -------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_PE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_PEF);

    huart->ErrorCode |= HAL_UART_ERROR_PE;
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
  }

  /* UART frame error interrupt occurred --------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_FE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_FEF);

    huart->ErrorCode |= HAL_UART_ERROR_FE;
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
  }

  /* UART noise error interrupt occurred --------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_NE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_NEF);

    huart->ErrorCode |= HAL_UART_ERROR_NE;
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
  }

  /* UART Over-Run interrupt occurred -----------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_ORE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_OREF);

    huart->ErrorCode |= HAL_UART_ERROR_ORE;
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
  }

   /* Call UART Error Call back function if need be --------------------------*/
  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    HAL_UART_ErrorCallback(huart);
  }

  /* UART wakeup from Stop mode interrupt occurred -------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_WUF) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_WUF) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_WUF);
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
    HAL_UARTEx_WakeupCallback(huart);
  }

  /* UART in mode Receiver ---------------------------------------------------*/
  if((__HAL_UART_GET_IT(huart, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE) != RESET))
  {
    UART_Receive_IT(huart);
    /* Clear RXNE interrupt flag */
    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
  }


  /* UART in mode Transmitter ------------------------------------------------*/
 if((__HAL_UART_GET_IT(huart, UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE) != RESET))
  {
    UART_Transmit_IT(huart);
  }

  /* UART in mode Transmitter (transmission end) -----------------------------*/
 if((__HAL_UART_GET_IT(huart, UART_IT_TC) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC) != RESET))
  {
    UART_EndTransmit_IT(huart);
  }

}

我要做的第一件事是禁用所有您没有明确使用的中断。至少,这应该有助于确定罪魁祸首。通过传入要禁用的中断,使用宏 __HAL_UART_DISABLE_IT() 执行此操作。

如果这不起作用,请尝试确认 TXE 中断被 IRQ 调用的 UART_Transmit_IT() 函数禁用。一种快速确定这是否是问题的方法可能是手动禁用中断(当您的问题发生时)并查看 IRQ 是否停止触发。否则,您可以尝试中断 UART_Transmit_IT() 函数并查看是否执行了 __HAL_UART_DISABLE_IT(huart, UART_IT_TXE); 行。如果 TXE 中断在完成后没有被正确禁用,它将继续触发 - 导致类似于您所看到的情况。