HAL库里,__HAL_TIM_CLEAR_IT和__HAL_TIM_CLEAR_FLAG的区别

文章分析了HAL库中关于TIM中断标志位清除的两个宏定义的区别,指出__HAL_TIM_CLEAR_IT可能的误用,并建议在清除中断标志位时优先使用__HAL_TIM_CLEAR_FLAG以避免潜在的bug。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在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。

        最后,如果本文有误,欢迎大家讨论和指正,有误的话我会第一时间改正。

### Keil中从HAL库切换到标准库的重新配置方法 在Keil环境中,当开发者决定从STM32 HAL库切换至标准外设库(Standard Peripheral Library, SPL)时,确实需要进行全面的重新配置。这是由于两者之间的设计哲学技术实现存在显著差异所致。 #### 头文件路径调整 首先,必须更改项目设置中的头文件包含路径。HAL标准库分别位于不同的目录结构之中,因此原先指向HAL库头文件的位置应当被替换为标准库的相关路径[^1]。 ```plaintext // 修改前(HAL库) ..\Drivers\STM32F1xx_HAL_Driver\Inc // 修改后(标准库) ..\Libraries\CMSIS_5\CMSIS\Device\ST\STM32F1xx\Include ..\Libraries\STM32_Firmware_Library_V3.5.0\inc ``` #### 启动代码与链接脚本更换 其次,启动代码(startup file)也需要相应地更改为匹配标准库版本的`.s`汇编文件。同样地,链接脚本(linker script)可能需要调整以适应新库带来的内存布局变化。 #### RCC与时钟初始化改编 系统时钟树的初始化方式会发生根本性转变。HAL库提供了一套高层API来进行此类复杂操作,而在标准库环境下则需直接操控寄存器来达成相同目的。例如: ```c // HAL库下的RCC初始化示例 void MX_RCC_Init(void){ __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); ... } // 转换为标准库后的等效实现 void RCC_Configuration(void){ RCC->CR |= RCC_CR_HSEON; // Enable HSE oscillator while (!(RCC->CR & RCC_CR_HSERDY)); // Wait until HSE is ready ... } ``` #### 中断服务程序自定义化 中断处理机制亦有所不同。使用HAL库时可通过简单的函数调用来管理各类外围设备产生的中断事件;然而,在标准库里往往需要自行编写具体的ISR(Interrupt Service Routine),并将它们绑定到相应的向量槽位上去。 #### 重写应用程序逻辑 最后但并非最不重要的一点是,几乎所有基于HAL API构建的应用层功能都得改写成遵循标准库风格的形式。比如下面这个例子展示了如何将一个定时器溢出中断的例子从HAL迁移到标准库之上: ```c // 原始HAL库版 static void MX_TIM3_Init(void){ htim3.Instance = TIM3; htim3.Init.Prescaler = 7199; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 999; if (HAL_TIM_Base_Init(&htim3) != HAL_OK){ Error_Handler(); } HAL_TIM_Base_Start_IT(&htim3); } __weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ if(htim->Instance==TIM3){ Toggle_LED(); // Assuming there's an LED toggle function defined elsewhere. } } // 迁移后的标准库版 void TIM3_Configuration(void){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /* Time base configuration */ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = 999; TIM_TimeBaseStructure.TIM_Prescaler = 7199; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); /* Enable interrupt and DMA request */ TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); /* Clear the Update Interrupt Flag */ TIM_ClearITPendingBit(TIM3,TIM_IT_Update); /* Enable TIM3 counter */ TIM_Cmd(TIM3, ENABLE); } void TIM3_IRQHandler(void){ if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET){ Toggle_LED(); // Same assumption as above regarding this function definition. /* Clear the update interrupt pending bit */ TIM_ClearITPendingBit(TIM3,TIM_IT_Update); } } ``` 通过以上几个方面的工作,便可以在Keil IDE内部成功完成从HAL库到标准库的整体迁移过程。值得注意的是整个过程中涉及到大量细致繁琐的操作环节,这就要求执行者具备扎实的基础理论知识以及丰富的实践经验才能顺利完成任务[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值