在HAL的学习过程中,我需要清除中断标志位以防止中断函数重复触发,此时我发现这两个宏定义很像,在仔细阅读了源码后,以下是我的看法。
1、宏定义解释
/** @brief Clear the TIM interrupt pending bits.
* @param __HANDLE__ TIM handle
* @param __INTERRUPT__ specifies the interrupt pending bit to clear.
* This parameter can be one of the following values:
* @arg TIM_IT_UPDATE: Update interrupt
* @arg TIM_IT_CC1: Capture/Compare 1 interrupt
* @arg TIM_IT_CC2: Capture/Compare 2 interrupt
* @arg TIM_IT_CC3: Capture/Compare 3 interrupt
* @arg TIM_IT_CC4: Capture/Compare 4 interrupt
* @arg TIM_IT_COM: Commutation interrupt
* @arg TIM_IT_TRIGGER: Trigger interrupt
* @arg TIM_IT_BREAK: Break interrupt
* @retval None
*/
#define __HAL_TIM_CLEAR_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->SR = ~(__INTERRUPT__))
/** @brief Clear the specified TIM interrupt flag.
* @param __HANDLE__ specifies the TIM Handle.
* @param __FLAG__ specifies the TIM interrupt flag to clear.
* This parameter can be one of the following values:
* @arg TIM_FLAG_UPDATE: Update interrupt flag
* @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag
* @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag
* @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag
* @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag
* @arg TIM_FLAG_COM: Commutation interrupt flag
* @arg TIM_FLAG_TRIGGER: Trigger interrupt flag
* @arg TIM_FLAG_BREAK: Break interrupt flag
* @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag
* @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag
* @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag
* @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag
* @retval The new state of __FLAG__ (TRUE or FALSE).
*/
#define __HAL_TIM_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->SR = ~(__FLAG__))
__HAL_TIM_CLEAR_IT 的官方解释是 Clear the TIM interrupt pending bits.清除TIM中断待定位。
__HAL_TIM_CLEAR_FLAG 的官方解释是 Clear the specified TIM interrupt flag.清除指定的TIM中断标志。
两个宏定义的参数都为定时器的句柄和所需的中断源。
我们从他们各自的宏定义可以看出来其实都是对定时器的状态寄存器SR进行操作。
((__HANDLE__)->Instance->SR = ~(__INTERRUPT__))
((__HANDLE__)->Instance->SR = ~(__FLAG__))
但比较奇怪的是,我们点开中断源的更详细的宏定义可以发现,__HAL_TIM_CLEAR_IT 貌似是想对中断使能寄存器DIER进行操作?
这是 __HAL_TIM_CLEAR_IT 的中断源的宏定义
/** @defgroup TIM_Interrupt_definition TIM interrupt Definition
* @{
*/
#define TIM_IT_UPDATE TIM_DIER_UIE /*!< Update interrupt */
#define TIM_IT_CC1 TIM_DIER_CC1IE /*!< Capture/Compare 1 interrupt */
#define TIM_IT_CC2 TIM_DIER_CC2IE /*!< Capture/Compare 2 interrupt */
#define TIM_IT_CC3 TIM_DIER_CC3IE /*!< Capture/Compare 3 interrupt */
#define TIM_IT_CC4 TIM_DIER_CC4IE /*!< Capture/Compare 4 interrupt */
#define TIM_IT_COM TIM_DIER_COMIE /*!< Commutation interrupt */
#define TIM_IT_TRIGGER TIM_DIER_TIE /*!< Trigger interrupt */
#define TIM_IT_BREAK TIM_DIER_BIE /*!< Break interrupt */
这是 __HAL_TIM_CLEAR_FLAG 的中断源的宏定义
/** @defgroup TIM_Flag_definition TIM Flag Definition
* @{
*/
#define TIM_FLAG_UPDATE TIM_SR_UIF /*!< Update interrupt flag */
#define TIM_FLAG_CC1 TIM_SR_CC1IF /*!< Capture/Compare 1 interrupt flag */
#define TIM_FLAG_CC2 TIM_SR_CC2IF /*!< Capture/Compare 2 interrupt flag */
#define TIM_FLAG_CC3 TIM_SR_CC3IF /*!< Capture/Compare 3 interrupt flag */
#define TIM_FLAG_CC4 TIM_SR_CC4IF /*!< Capture/Compare 4 interrupt flag */
#define TIM_FLAG_COM TIM_SR_COMIF /*!< Commutation interrupt flag */
#define TIM_FLAG_TRIGGER TIM_SR_TIF /*!< Trigger interrupt flag */
#define TIM_FLAG_BREAK TIM_SR_BIF /*!< Break interrupt flag */
#define TIM_FLAG_CC1OF TIM_SR_CC1OF /*!< Capture 1 overcapture flag */
#define TIM_FLAG_CC2OF TIM_SR_CC2OF /*!< Capture 2 overcapture flag */
#define TIM_FLAG_CC3OF TIM_SR_CC3OF /*!< Capture 3 overcapture flag */
#define TIM_FLAG_CC4OF TIM_SR_CC4OF /*!< Capture 4 overcapture flag */
我不确定这是不是HAL库的一个小bug,毕竟中断源的命名和实际操作的寄存器出现了偏差,我们接下来阅读一下芯片手册。
2、阅读芯片手册
这是中断使能寄存器DIER的详细位声明。我们可以看到位0是更新中断,位1-4是输入捕获中断,位8以上的都是与DMA有关的,详情可以看芯片手册。
这是状态寄存器SR的详细位声明。我们可以看到位0也是更新中断,位1-4也是输入捕获中断,位8以上的与重复捕获标记有关,详情可以看芯片手册。
如果对中断源的宏定义继续深入的查看,会发现实际上就是0x01进行左移,如左移一位就是输入捕获1的中断标记。因此对更新中断和输入捕获1-4的标记进行清0的话实际上用哪个函数都可以,因为实际上都是对SR寄存器进行赋1。
但如果跟重复捕获有关的话,需要用__HAL_TIM_CLEAR_FLAG去操作SR寄存器。
3、总结
__HAL_TIM_CLEAR_IT 也许是想对中断使能寄存器DIER进行操作,但源码写错了,变成了对状态寄存器SR进行操作。这只是我的一个猜想。我们从DIER的中文名也可以猜想出来,对这个寄存器进行操作的时候,是对中断的使能和失能,而并不是进行清除中断标志位,防止重复进入中断。
__HAL_TIM_CLEAR_FLAG 是对状态寄存器SR进行操作。是为了清除中断标志位的,如当发生输入捕获的时候,SR的位置被硬件置1,此时需要软件手动清0,防止重复进入中断函数。
所以,大家如果是想清除中断标志位就直接使用 __HAL_TIM_CLEAR_FLAG 函数即可,__HAL_TIM_CLEAR_IT 我建议少用或者不用,可能对因为寄存器的错误赋值而出现不希望出现的Bug。
最后,如果本文有误,欢迎大家讨论和指正,有误的话我会第一时间改正。