目錄
- 中斷流程分析
- 我的解決辦法
- 優缺點
大家都在說STM32 HAL 庫中斷效率低下。具體哪里不行?如何優化?
我手里的項目要用到多個定時器TIM6、TIM7、TIM9、TIM10、TIM11、TIM12、TIM13,在處理這些定時器中斷的時候,也發現了這個問題。
下面給出我的分析和解決辦法。
中斷流程分析
以TIM7 中斷流程分析,中斷條件滿足之后,單片機從中斷向量表中找中斷服務函數TIM7_IRQHandler,然后跳轉進去
; Vector Table Mapped to Address 0 at ResetAREA RESET, DATA, READONLYEXPORT __VectorsEXPORT __Vectors_EndEXPORT __Vectors_Size__Vectors DCD __initial_sp ; Top of StackDCD Reset_Handler ; Reset HandlerDCD NMI_Handler ; NMI HandlerDCD 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);代碼不可到達,會報