如何重置 STM32 HAL UART 驱动程序 (HAL) 状态?

clm*_*mno 2 c hardware interrupt stm32

我知道可以使用启用 UART 接收中断

HAL_UART_Receive_IT(&huart2, (uint8_t *)rx_buffer, expectedNumberOfBytes)
Run Code Online (Sandbox Code Playgroud)
  • 但是一旦开始,如何“手动”停止它?

我们可以使用HAL_NVIC_DisableIRQ()(例如:)禁用 UART 中断HAL_NVIC_DisableIRQ(USART1_IRQn)。这将防止它抛出一个中断,但该函数的状态集HAL_UART_Receive_ITHAL_UART_STATE_BUSY_RX需要设置回HAL_UART_STATE_READY为UART手柄回到可以接受一个新的状态HAL_UART_Receive_IT()调用。

问题
如果我想在一段时间后禁用 Rx 中断,如何重置 UART 中断的状态?

堆栈溢出问题不涉及如何重置状态;我提到了这些问题:

  1. 在中断处理程序 STM32F407 中禁用中断
  2. https://electronics.stackexchange.com/questions/100073/stm32-usart-rx-interrupts

我可以使用USART_ClearITPendingBit()orUSART_ITConfig()但这些被 STM 的 HAL 库定义为私有函数。那么我应该使用它们吗?

Gab*_*les 6

如果[我]希望在一段时间后禁用 Rx 中断,我如何[如何]重置 UART 中断的状态[?]

(例如,参见“ stm32f4xx_hal_uart.c ”中的用法。)

huart->RxStateuart 句柄结构的成员实际上仅在执行HAL_UART_Receive(), HAL_UART_Receive_IT(), HAL_UART_Receive_DMA(), (以及许多其他类似的内部函数)等操作时由 HAL 库在内部使用。 如果您手动实现自己的基于中断和环形缓冲区-基于 UART Tx 和 Rx 调用,但是,这是执行此操作的首选方式,此成员完全没有意义,您用它做什么无关紧要,因为它仅在 HAL 库函数调用和 HAL ISR 处理程序中使用(两者都不必使用),并且与寄存器级中断和直接事物无关。

但是,通过在stm32f4xx_hal_uart.c 中挖掘源代码(例如),您可以使用以下几个有效选项:

1.如何重置huart->RxStateHAL_UART_STATE_READY

  1. 打电话HAL_UART_Init()。通过检查它的源代码,你会看到它huart->RxState= HAL_UART_STATE_READY;在返回之前调用。
  2. 只需手动设置huart->RxState = HAL_UART_STATE_READY;只要您知道在处理过程中正确停止了基于中断的接收,这是完全有效的。

然而,让我们更进一步。

假设您在 STM32F4 上使用 UART7。因此,在您的stm32f4xx_it.c中断处理程序文件中,您将看到 STM32CubeMX 自动生成的以下代码:

/**
* @brief This function handles UART7 global interrupt.
*/
void UART7_IRQHandler(void)
{
  /* USER CODE BEGIN UART7_IRQn 0 */

  /* USER CODE END UART7_IRQn 0 */
  HAL_UART_IRQHandler(&huart7);
  /* USER CODE BEGIN UART7_IRQn 1 */

  /* USER CODE END UART7_IRQn 1 */
}
Run Code Online (Sandbox Code Playgroud)

让我们回顾一下禁用/启用中断的一些层。

2. 从最宽到最窄的范围,这里有几种禁用/启用 USART Rx 中断的方法:

  1. 您可以UART7_IRQHandler()使用这些 ARM 核心 CMSIS 调用禁用/启用所有中断,包括 this :

    __disable_irq();
    __enable_irq();
    
    Run Code Online (Sandbox Code Playgroud)

    来源:https : //stm32f4-discovery.net/2015/06/how-to-properly-enabledisable-interrupts-in-arm-cortex-m/

    因此,您可以执行以下操作来禁用中断,重置RxState,然后在准备好后再次启动基于中断的接收:

    __disable_irq();
    huart7->RxState= HAL_UART_STATE_READY;
    
    __enable_irq();
    HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您只能禁用/启用UART7_IRQHandler()中断(连接到此中断向量的所有 10 种类型的 uart7 中断,包括 Tx 相关、Rx 相关、错误相关等),使用这些 STM32 HAL 调用:

    HAL_NVIC_DisableIRQ(UART7_IRQn);
    HAL_NVIC_EnableIRQ(UART7_IRQn);
    
    Run Code Online (Sandbox Code Playgroud)

    然后,除了使用这些调用来禁用/启用中断之外,执行与上面相同的操作。

  3. HAL_UART_IRQHandler()但是,如果您深入研究由 调用的 的实现UART7_IRQHandler(),您会发现它只调用基于中断的接收处理程序UART_Receive_IT(),如果USART_SR_RXNE位(“接收非空”,在 USART 状态寄存器中)和的USART_CR1_RXNEIE位(“接收非空中断使能”时,USART控制寄存器1的内部),有两个组。该RXNE每当一个字节进入时,位就会设置,并且在您读取数据寄存器或向其写入零时清除。中断启用位是您可以完全控制以禁用此 UART 接收中断的内容,如果您手动清除此位,您将禁用接收中断而不禁用与此 USART 相关的任何其他类型的中断。这是最好的方法,因为有 10 个与此 UART 相关的中断源。换句话说,清除该位不仅会导致内部检查HAL_UART_IRQHandler()失败,而且还可以防止接收中断发生!请参阅参考手册 RM0090 Rev 16,例如:

    p969: 在此处输入图片说明

    p1009: 在此处输入图片说明

    p1011: 在此处输入图片说明

    p1015: 在此处输入图片说明

    p1013: 在此处输入图片说明

    因此,要仅禁用/启用 USART 接收非空中断,请执行以下操作。请参阅 p1013 上的控制寄存器 (USART_CR1),如上所示。

    // Disable the USART Receive Not Empty interrupt
    CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
    
    // Enable the USART Receive Not Empty interrupt
    SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
    
    Run Code Online (Sandbox Code Playgroud)

    现在,您可以执行以下操作来禁用 USART 接收中断,重置 HAL RxState,然后在准备好后再次启动基于中断的接收:

    CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
    huart7->RxState= HAL_UART_STATE_READY;
    
    SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE); // This call isn't actually necessary, as this bit is set inside `HAL_UART_Receive_IT()` as well
    HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
    
    Run Code Online (Sandbox Code Playgroud)

3. 如何(尴尬地)HAL_UART_Receive_IT()用于基于中断的连续接收。

去做

4.为什么HAL_UART_Receive_IT()真的不是一个非常有用的功能。

去做

5. 如何手动配置您自己的基于中断的 UART Tx 和 Rx ISR 和功能。

去做

  • 我喜欢你思考的方式。IMO HAL 驱动程序是一个笨重的未记录层,包裹着记录良好的硬件。使用供应商库可能存在的任何可移植性和重用优势都被缺乏文档和与驱动程序应该用于的外围设备以外的隐藏交互完全否定。如果不彻底阅读寄存器级接口的手册,您就无法理解和使用 HAL 层,一旦阅读完,您就不再需要 HAL。 (2认同)