STM32 延時函式高階用法分析
一、使用場景
第一種情況,在使用普通 STM32 延遲函式,類似於 HAL_Delay(time)
,由於該函式是使用迴圈去判斷及延時的,所以在執行該函式時整個程式會在此處等待定時器的中斷服務函式修改參量使得迴圈判決條件不成立,從而繼續程式的執行,同時也達到延遲時間的效果。由於使用的是系統的定時器進行延遲,所以時間相對準確。
第二種情況,當需要週期性的執行一個任務時,將這個函式放在某個定時器的中斷服務函式裡,設定好定時器的時間,完成時產生中斷,從而進入中斷服務函式執行該函式。此時,MCU 執行中斷程式,只有更高優先順序的中斷才能打斷當前執行的中斷服務函式,進入更高優先順序的中斷服務函式去執行。需要等所有中斷服務函式都執行完成,才會退回到主函式。
第三鍾情況,而結合定時器以及相應的標誌位,直接在主函式中達到週期任務的效果。原理如下:
- 1、設定一個全域性的標誌位
flag
,初值為 0。 - 2、在
SysTick
定時器的中斷服務函式中,週期性地對改標誌位置 1。 - 3、主函式
while(1)
中,只要使用if(flag){}
去判斷條件是否滿足,滿足則執行,不滿足則跳過。
第三種情況和第二鍾情況的主要區別在於,第三種情況的週期任務函式是在主函式中執行的,而第二種則是在中斷服務函式裡執行的。使用第二種方式去執行週期任務,程式上可能會更好理解一些;使用第三種方式,則在編寫程式時更簡便一點。
這三種情況的使用場景不一樣,第一種是使用 CPU 空操作的方式來延遲固定時間,保證通訊時序正確;第二種使用中斷的方式適用於比較重要的週期任務,保證週期準確;第三種則適用於週期不那麼重要,只要在 while(1)
if(flag)
的判斷,滿足就執行。
二、程式碼演示
while (1)
{
BSP_LED_On(LED1);
#if 1 //演示1,普通延時函式 5s列印一次時間和follow on
printf_time();
HAL_Delay(1000); //延時1000ms
printf("follow on \n ");
#else //演示2,週期任務 1s列印一次時間,5s列印一次follow on
printf_time();
HAL_Delay(1000);
Sys_Delay(5000 );
if(flag)
{
flag = 0;
printf("follow on \n");
}
#endif
}
printf_time()
函式就是將 MCU RTC 中的時間通過串列埠打印出來,而HAL_Delay()
就是普通的延時函式,Sys_Delay()
是用於設定第三種方式中所提的定時任務的週期,程式碼如下:
void Sys_Delay(uint32_t time)
{
Cycle_Time = time;
}
而中斷服務函式的程式碼如下:
void SysTick_Handler(void)
{
HAL_IncTick();
T1msCount++;
if(T1msCount>Cycle_Time)
{
T1msCount = 0;
flag = 1;
}
}
該中斷每 1ms 產生一次,對計數值T1msCount
進行加 1,當大於週期時間時,清零,並對標誌位賦 1,此後主函式中if(flag)
成立,對標誌位清零,並執行其中的週期任務。
圖一對於主函式中演示 1,代表延遲一秒,列印時間及“follow on”,
圖二對應主函式在 #if 0
時的演示2,代表延遲一秒列印一次時間,列印”follow on”的週期為5秒。