0x00摘要 本文主要講解ucos如何實現(xiàn)任務的調(diào)度,調(diào)度過程中主要涉及到的函數(shù)和知識點。 0x01引言 ucos是一種嵌入式實時多任務操作系統(tǒng),其高度可靠性、魯棒性和安全性,得到美國宇航局的認證。已經(jīng)廣泛使用在從照相機到航空電子產(chǎn)品的各種應用中。為了更好的了解UCOS的任務調(diào)度原理,本文從代碼進行分析。 0x02原理 0x02-1 UCOS能實現(xiàn)任務調(diào)度是采用中斷來實現(xiàn),對于STM32其使用了SysTick定時器,用它來產(chǎn)生系統(tǒng)的時基,維持系統(tǒng)的“心跳”。對于SysTick定時器的初始化是在main函數(shù)中OS_CPU_SysTickInit()完成,它的代碼如下: void OS_CPU_SysTickInit (void) { INT32U cnts; cnts =OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC; OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1); OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC |OS_CPU_CM3_NVIC_ST_CTRL_ENABLE; OS_CPU_CM3_NVIC_ST_CTRL |=OS_CPU_CM3_NVIC_ST_CTRL_INTEN; } 這個函數(shù)主要是完成了SysTick計時器的初始化,首先利用OS_CPU_SysTickClkFreq()獲取系統(tǒng)的頻率,根據(jù)OS_TICKS_PER_SEC,也就是每秒鐘的心跳數(shù)(中斷次數(shù)),得到定時器需要設定的每次中斷的計時數(shù),最后調(diào)用相關的寄存器設置宏來初始化定時器。這些宏的具體定義大家可以通過源碼直接查看(關注公眾號,回復ucos即可獲取,在keil下編譯后在指定變量上右擊查看定義即可)。 OS_CPU_SysTickClkFreq()函數(shù)主要獲取硬件頻率,代碼如下: INT32U OS_CPU_SysTickClkFreq (void) { INT32U freq; freq =BSP_CPU_ClkFreq(); return(freq); } 這里調(diào)用了BSP_CPU_ClkFreq()來獲取頻率,其代碼為: CPU_INT32U BSP_CPU_ClkFreq (void) { RCC_ClocksTypeDef rcc_clocks; RCC_GetClocksFreq(&rcc_clocks); return((CPU_INT32U)rcc_clocks.HCLK_Frequency); } RCC_GetClocksFreq(&rcc_clocks)這個函數(shù)是stm32固件庫中的函數(shù),具體代碼大家可以看一下,它可以返回系統(tǒng)的硬件頻率。 0x02-2 設定好定時器后,stm32便可以產(chǎn)生定時中斷了,中斷調(diào)用中斷函數(shù)OS_CPU_SysTickHandler ()來實現(xiàn)任務的調(diào)度。其在verter.s中設定,這部分涉及到stm32硬件相關知識暫不講解。代碼如下 void OS_CPU_SysTickHandler (void) { OS_CPU_SR cpu_sr; OS_ENTER_CRITICAL(); OSIntNesting++; OS_EXIT_CRITICAL(); OSTimeTick(); OSIntExit(); } 這里首先定義了一個OS_CPU_SR變量,用于接受PRIMASK中斷屏蔽寄存器的值。然后調(diào)用OS_ENTER_CRITICAL()進入臨界段,所謂臨界段就是系統(tǒng)不希望被其他中斷打擾(NMI和硬fault除外,具體功能大家查一下手冊),然后將OSIntNesting(表示中斷嵌套的層數(shù))加1,執(zhí)行完之后便退出臨界段,臨界段所處的時間越短越好,太長時間將會影響到其他中斷的響應,對實時性不利,同樣其他不希望被中斷打擾一切操作都可以用這兩個函數(shù)來進行控制。接著便調(diào)用OSTimeTick()和OSIntExit()完成這次任務調(diào)度,這兩個函數(shù)下次講解。 先看一下OS_ENTER_CRITICAL(),代碼如下 #define OS_ENTER_CRITICAL() {cpu_sr =OS_CPU_SR_Save();} 這是一個宏定義,調(diào)用了OS_CPU_SR_Save(),其是一個匯編程序,如下 OS_CPU_SR_Save MRS R0, PRIMASK CPSID I BX LR 這里將PRIMASK存入R0,然后關閉總中斷,跳回原來函數(shù),這樣就進入了臨界段,不會有其他中斷打擾。PRIMASK在手冊中解釋為這個寄存器只有一個位,置1后,將關閉所有可屏蔽中斷的異常,只剩NMI和硬fault,默認值為0。 R0是什么,就是調(diào)用函數(shù)傳進來的第一個參數(shù),也就是cpu_sr。在匯編中R0~R3會依次接受傳進來的不多于4個參數(shù),再多的話建議采用指針或者堆棧。 OS_EXIT_CRITICAL(),代碼如下 #define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);} 也是一個宏定義,和上述一樣,OS_CPU_SR_Restore(cpu_sr)是一個匯編程序: OS_CPU_SR_Restore MSR PRIMASK, R0 BX LR 將cpu_sr中的值恢復,然后返回。 0x03小結(jié) 為了大家更加清楚的了解ucos工作機制,這里對源碼進行了詳細分析,對于一些簡單的地方就沒有進行解釋,比如變量定義。還有些調(diào)用庫函數(shù)的語句也沒有解釋,這是stm32部分的相關知識,為了盡量把多的空間放在ucos上所以就不再進行詳細講解,大家可以到網(wǎng)上查看這些代碼的具體意思。
|