目录
- 中断流程分析
- 我的解决办法
- 优缺点
大家都在说STM32 HAL 库中断效率低下。具体哪里不行?如何优化?
我手里的项目要用到多个定时器TIM6、TIM7、TIM9、TIM10、TIM11、TIM12、TIM13,在处理这些定时器中断的时候,也发现了这个问题。
下面给出我的分析和解决办法。
中断流程分析
以TIM7 中断流程分析,中断条件满足之后,单片机从中断向量表中找中断服务函数TIM7_IRQHandler,然后跳转进去
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
......
DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors
DCD TIM7_IRQHandler ; TIM7
TIM7_IRQHandler内容如下,从这里HAL库开始接管
void TIM7_IRQHandler(void)
{
/* USER CODE BEGIN TIM7_IRQn 0 */
/* USER CODE END TIM7_IRQn 0 */
HAL_TIM_IRQHandler(&htim7);
/* USER CODE BEGIN TIM7_IRQn 1 */
/* USER CODE END TIM7_IRQn 1 */
}
HAL_TIM_IRQHandler内容如下,为了方便阅读做了删减
if ((itflag & (TIM_FLAG_CC1)) == (TIM_FLAG_CC1)){/* Capture compare 1 event Process */}
if ((itflag & (TIM_FLAG_CC2)) == (TIM_FLAG_CC2)){/* Capture compare 2 event Process */}
if ((itflag & (TIM_FLAG_CC3)) == (TIM_FLAG_CC3)){/* Capture compare 3 event Process */}
if ((itflag & (TIM_FLAG_CC4)) == (TIM_FLAG_CC4)){/* Capture compare 4 event Process */}
if ((itflag & (TIM_FLAG_UPDATE)) == (TIM_FLAG_UPDATE)){
/* TIM Update event Process */
//我的定时器只用来做定时中断,所以关注TIM_IT_UPDATE中断
if ((itsource & (TIM_IT_UPDATE)) == (TIM_IT_UPDATE))
{
//清除标志位
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
//如果启用了回调函数注册执行这里,实际上我们重写下面一条语句的函数效果类似。
htim->PeriodElapsedCallback(htim);
#else
//没有启用回调函数,执行这里。HAL_TIM_PeriodElapsedCallback是虚函数,用户自行重写
HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
}
if ((itflag & (TIM_FLAG_BREAK)) == (TIM_FLAG_BREAK)){/* TIM Break input event Process */}
if ((itflag & (TIM_FLAG_TRIGGER)) == (TIM_FLAG_TRIGGER)){/* TIM Trigger detection event Process */}
if ((itflag & (TIM_FLAG_COM)) == (TIM_FLAG_COM)){/* TIM commutation event Process */}
HAL_TIM_PeriodElapsedCallback的定义如下
/**
* @brief Period elapsed callback in non-blocking mode
* @param htim TIM handle
* @retval None
*/
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
}
可以看出来,不同中断公用一个最终的处理函数HAL_TIM_PeriodElapsedCallback,在该函数里用户自己靠传入的形参htim去区分是哪一个中断触发的。那么实际重写HAL_TIM_PeriodElapsedCallback的时候,应该是如下结构
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == htim6)
{
} else if(htim == htim7)
{
}else if(htim == htim9)
{
}else if(htim == htim10)
{
}
......
}
这样的处理方便倒是挺方便的,但是明显的效率低下。主要体现如下两部分:
- 我不需要判断那么多中断事件,我对自己项目中定时器的作用非常清晰,不会用于做捕获、从机等,也就不用判断这些中断事件。
- 不同定时器公用一个回调函数,在回调函数内再区分,效率低下。原本不同的定时器就有不同的中断服务函数的。
我的解决办法
在TIM7_IRQHandler里写应用,然后直接返回
void TIM7_IRQHandler(void)
{
/* USER CODE BEGIN TIM7_IRQn 0 */
if(TIMER_Group.callback[1])
TIMER_Group.callback[1]();
return;
/* USER CODE END TIM7_IRQn 0 */
HAL_TIM_IRQHandler(&htim7);
/* USER CODE BEGIN TIM7_IRQn 1 */
/* USER CODE END TIM7_IRQn 1 */
}
callback指向的函数内容如下
static void hwtimer2_callback(void)
{
/* some app*/
__HAL_TIM_CLEAR_FLAG(htim7, TIM_IT_UPDATE);//手动清除标志位
}
优缺点
优点:解决了中断效率低下的问题
缺点1:return后面HAL_TIM_IRQHandler(&htim7);任然参与编译,可能占用更多的Flash空间
缺点2:因为HAL_TIM_IRQHandler(&htim7);代码不可到达,会报