天天看點

FreeRTOS 從入門到精通8--中斷管理

我們介紹了軟體定時器的應用,在這一講我們将介紹中斷在FreeRTOS中的應用和注意事項。

什麼是中斷

CPU在執行某一事件A時,發生另外一個更重要緊急的事件B請求CPU去處理(産生了中斷),于是CPU暫時中斷目前正在執行的事件A任務而對對事件B進行處理,CPU處理完事件B後再傳回之前中斷的位置繼續執行原來的事件A,這一過程統稱為中斷。

我在網上看到了一篇文章很形象地介紹了中斷。

​​單片機中斷系統_C語言中文網中斷的産生背景 請設想這樣一個場景:此刻我正在廚房用瓦斯燒一壺水,而燒開一壺水剛好需要 10 分鐘,我是一個主體,燒水是一個目的,而且我隻能時時刻刻在這裡燒水,因為一旦水開了,溢出來澆滅瓦斯的話,有可能引發一場災難。但就在這個時候呢,我又聽到了http://c.biancheng.net/cpp/html/1888.html​​

 請設想這樣一個場景:此刻我正在廚房用瓦斯燒一壺水,而燒開一壺水剛好需要 10 分鐘,我是一個主體,燒水是一個目的,而且我隻能時時刻刻在這裡燒水,因為一旦水開了,溢出來澆滅瓦斯的話,有可能引發一場災難。但就在這個時候呢,我又聽到了電視裡傳來《天龍八部》的主題歌,馬上就要開演了,我真想奪門而出,去看我最喜歡的電視劇。然而,聽到這個水壺發出的“咕嘟”的聲音,我清楚:除非等水燒開了,否則我是無法享受我喜歡的電視劇的。

這裡邊主體隻有一個我,而我要做的有兩件事情,一個是看電視,一個是燒水,而電視和燒水是兩個獨立的客體,它們是同時進行的。其中燒水需要 10 分鐘,但不需要了解燒水的過程,隻需要得到水燒開的這樣一個結果就行了,提下水壺和關閉瓦斯隻需要幾秒的時間而已。是以我們采取的辦法就是:燒水的時候,定上一個鬧鐘,定時 10 分鐘,然後我就可以安心看電視了。當 10 分鐘時間到了,鬧鐘響了,此刻水也燒開了,我就過去把瓦斯滅掉,然後繼續回來看電視就可以了。

這個場景和單片機有什麼關系呢?

在單片機的程式處理過程中也有很多類似的場景,當單片機正在專心緻志的做一件事情(看電視)的時候,總會有一件或者多件緊迫或者不緊迫的事情發生,需要我們去關注,有一些需要我們停下手頭的工作去馬上去處理(比如水開了),隻有處理完了,才能回頭繼續完成剛才的工作(看電視)。這種情況下單片機的中斷系統就該發揮它的強大作用了,合理巧妙的利用中斷,不僅可以使我們獲得處理突發狀況的能力,而且可以使單片機能夠“同時”完成多項任務。

單片機通常擁有豐富的片内外設和很多中斷源,中斷程式相比于在主程式中使用循環語句輪詢系統狀态(Polling)能有效提高CPU的利用效率,同時能都夠更加及時地響應外部事件。中斷系統雖然強大,但中斷系統的引進有時會産生一些意想不到的問題。在FreeRTOS中,任務程式由核心排程器統一排程和執行,程式的運作情況在一定程度上是穩定可預測的;中斷相對而言是由外部環境決定是不可預測的,會對系統引入不确定性,如果使用不當的話會導緻系統的失效和不穩定。是以在很多安全相關的程式中,通常為了穩定減少對中斷的使用。總而言之,對中斷的使用要根據實際需求和使用場景來決定,通過合理的配置和與FreeRTOS的中斷管理(Interrupt Management)配合可以達到系統的高效能和高穩定性。

在FreeRTOS中的中斷管理

FreeRTOS對于中斷沒有特别的處理程式,但提供一些特性和系統API函數友善使用者可以簡單地實作和維護中斷管理。首先我們要明白,在FreeRTOS中中斷的優先級和任務的優先級是有差別的。可以把任務類比是人間模式,而中斷是上帝模式,擁有更高的權限。

  • 任務的優先級是由使用者設定核心管理器管理的軟體特性(software feature),與作業系統所在的硬體平台無關
  • 中斷的優先級是由硬體平台相關的硬體特性(hardware feature),在中斷代碼運作的時候任務的代碼将無法運作。即使是擁有最小優先級的中斷也會打斷擁有最高優先級的任務。

FreeRTOS對于一些系統API函數提供兩種版本,一種是供任務調用的,一種是供中斷調用的(Interrupt Safe API)。由中斷調用的API函數字尾上會有“FromISR”。

在任務中系統API函數被調用後,如果有更高優先級的任務處于就緒狀态的話,核心排程器會自動執行有更高優先級的任務。(需要在FreeRTOSConfig.h頭檔案中設定configUSE_PREEMPTION為1)。在中斷處理代碼中系統API函數被調用後,核心排程器不會自動切換到有更高優先級的任務,會把系統API函數中指針參數pxHigherPriorityTaskWoken設定為pdTRUE,然後由使用者根據pxHigherPriorityTaskWoken的值自行決定是否切換任務。在中斷處理代碼中,切換任務的系統API函數如下

portYIELD_FROM_ISR( xHigherPriorityTaskWoken );      

如果xHigherPriorityTaskWoken的值是pdFALSE的話,任務切換不會發生;如果xHigherPriorityTaskWoken的值是pdTRUE的話,任務切換會發生。

中斷處理程式中代碼可以盡量簡短,并把進行中斷的代碼放在一個中斷任務裡。這種方法稱為延遲中斷處理(deferred interrupt processing)。通過延遲中斷處理使用者可以把中斷處理當成由排程器排程的一個任務并配置設定優先級,此時中斷的優先級和任務的優先級是一緻的。使用者可以把中斷任務的優先級設定為最進階,當中斷發生在中斷處理程式調用portYIELD_FROM_ISR()函數後中斷任務将會優先執行。當然如果程式簡單的話使用者可以直接在中斷處理程式中進行中斷。

void InterruptHandling()
//模拟中斷處理函數,中斷處理函數是硬體平台相關,不屬于FreeRTOS範疇
{
   RecordInterrupt();//記錄一下中斷的資訊友善中斷任務判斷中斷來源等
   ClearInterruptFlag();//清除中斷标記,使能中斷
   portYIELD_FROM_ISR(pdTRUE);//切換任務,如果中斷任務的優先級設定為最進階将會優先執行
}
void vInterruptHandling(void const * argument)
//FreeRTOS建立的中斷任務,進行中斷
{
   ProcessInterrupt();
   //因為中斷的來源有很多,需要通過對中斷的記錄判斷中斷來源并執行相應中斷處理代碼
}      

繼續閱讀