μC/OS-II的內核結構
程序清單 L3.18Motorola68HC11中的中斷服務子程序
本文引用地址:http://www.ex-cimer.com/article/201610/305744.htmM68HC11_ISR:/* 快中斷服務程序,必須禁止中斷*/
所有寄存器被CPU自動保存;
執(zhí)行用戶代碼以響應中斷;
執(zhí)行中斷返回指令;
3.10 時鐘節(jié)拍
μC/OS需要用戶提供周期性信號源,用于實現(xiàn)時間延時和確認超時。節(jié)拍率應在每秒
10次到100次之間,或者說10到100Hz。時鐘節(jié)拍率越高,系統(tǒng)的額外負荷就越重。時鐘
節(jié)拍的實際頻率取決于用戶應用程序的精度。時鐘節(jié)拍源可以是專門的硬件定時器,也可
以是來自50/60Hz交流電源的信號。
用戶必須在多任務系統(tǒng)啟動以后再開啟時鐘節(jié)拍器,也就是在調用OSStart()之后。
換句話說,在調用OSStart()之后做的第一件事是初始化定時器中斷。通常,容易犯的錯
誤是將允許時鐘節(jié)拍器中斷放在系統(tǒng)初始化函數OSInit()之后,在調啟動多任務系統(tǒng)啟動
函數OSStart()之前,如程序清單L3.19所示。
程序清單L3.19啟動時鐘就節(jié)拍器的不正確做法.
voidmain(void)
{
.
.
OSInit();/* 初始化uC/OS-II*/
.
.
/* 應用程序初始化代碼 ...*/
/*... 通過調用OSTaskCreate()創(chuàng)建至少一個任務 */
.
.
允許時鐘節(jié)拍(TICKER)中斷;/* 千萬不要在這里允許時鐘節(jié)拍中斷!!! */
.
.
OSStart();/* 開始多任務調度 */
}
這里潛在地危險是,時鐘節(jié)拍中斷有可能在μC/OS-Ⅱ啟動第一個任務之前發(fā)生,此時μC/OS-Ⅱ是處在一種不確定的狀態(tài)之中,用戶應用程序有可能會崩潰。
μC/OS-Ⅱ中的時鐘節(jié)拍服務是通過在中斷服務子程序中調用OSTimeTick()實現(xiàn)的。
時鐘節(jié)拍中斷服從所有前面章節(jié)中描述的規(guī)則。時鐘節(jié)拍中斷服務子程序的示意代碼如程序清單L3.20所示。這段代碼必須用匯編語言編寫,因為在C語言里不能直接處理CPU的寄存器。
程序清單L3.20時鐘節(jié)拍中斷服務子程序的示意代碼
voidOSTickISR(void)
{
保存處理器寄存器的值;
調用OSIntEnter()或是將OSIntNesting加1;
調用OSTimeTick();
調用OSIntExit();
恢復處理器寄存器的值;
執(zhí)行中斷返回指令;
}
時鐘節(jié)拍函數OSTimeTick()的代碼如程序清單3.21所示。OSTimtick()以調用可由用戶定義的時鐘節(jié)拍外連函數OSTimTickHook()開始,這個外連函數可以將時鐘節(jié)拍函數OSTimtick()予以擴展[L3.2(1)]。筆者決定首先調用OSTimTickHook()是打算在時鐘節(jié)拍中斷服務一開始就給用戶一個可以做點兒什么的機會,因為用戶可能會有一些時間要求苛刻的工作要做。OSTimtick()中量大的工作是給每個用戶任務控制塊OS_TCB中的時間延時項OSTCBDly減1(如果該項不為零的話)。OSTimTick()從OSTCBList開始,沿著OS_TCB鏈表做,一直做到空閑任務[L3.21(3)]。當某任務的任務控制塊中的時間延時項OSTCBDly減到了零,這個任務就進入了就緒態(tài)[L3.21(5)]。而確切被任務掛起的函數OSTaskSuspend()掛起的任務則不會進入就緒態(tài)[L3.21(4)]。OSTimTick()的執(zhí)行時間直接與應用程序中建立了多少個任務成正比。
程序清單L3.21時鐘節(jié)拍函數OSTimtick()的一個節(jié)拍服務
voidOSTimeTick(void)
{
OS_TCB*ptcb;
OSTimeTickHook();(1)
ptcb=OSTCBList;(2)
while(ptcb->OSTCBPrio!=OS_IDLE_PRIO){(3)
OS_ENTER_CRITICAL();
if(ptcb->OSTCBDly!=0){
if(--ptcb->OSTCBDly==0){
if(!(ptcb->OSTCBStatOS_STAT_SUSPEND)){(4)
OSRdyGrp|=ptcb->OSTCBBitY;(5)
OSRdyTbl[ptcb->OSTCBY]|=ptcb->OSTCBBitX;
}else{
ptcb->OSTCBDly=1;
}
}
}
ptcb=ptcb->OSTCBNext;
OS_EXIT_CRITICAL();
}
OS_ENTER_CRITICAL();(6)
OSTime++; (7)
OS_EXIT_CRITICAL();
}
OSTimeTick()還通過調用OSTime()[L3.21(7)]累加從開機以來的時間,用的是一個無符號32位變量。注意,在給OSTime加1之前使用了關中斷,因為多數微處理器給32位數加1的操作都得使用多條指令。
中斷服務子程序似乎就得寫這么長,如果用戶不喜歡將中斷服務程序寫這么長,可以從任務級調用OSTimeTick(),如程序清單L3.22所示。要想這么做,得建立一個高于應用程序中所有其它任務優(yōu)先級的任務。時鐘節(jié)拍中斷服務子程序利用信號量或郵箱發(fā)信號給這個高優(yōu)先級的任務。
程序清單L3.22時鐘節(jié)拍任務TickTask()作時鐘節(jié)拍服務.
voidTickTask(void*pdata)
{
pdata=pdata;
for(;;){
OSMboxPend(...);/* 等待從時鐘節(jié)拍中斷服務程序發(fā)來的信號 */
OSTimeTick();
}
}
用戶當然需要先建立一個郵箱(初始化成NULL)用于發(fā)信號給上述任何告知時鐘節(jié)拍中斷已經發(fā)生了(程序清單L3.23)。
程序清單L3.23時鐘節(jié)拍中斷服務函數OSTickISR()做節(jié)拍服務。
voidOSTickISR(void)
{
保存處理器寄存器的值;
調用OSIntEnter()或是將OSIntNesting加1;
發(fā)送一個‘空’消息(例如, (void*)1)到時鐘節(jié)拍的郵箱;
調用OSIntExit();
恢復處理器寄存器的值;
執(zhí)行中斷返回指令;
}
3.11 μC/OS-Ⅱ初始化
在調用μC/OS-Ⅱ的任何其它服務之前,μC/OS-Ⅱ要求用戶首先調用系統(tǒng)初始化函數OSIint()。OSIint()初始化μC/OS-Ⅱ所有的變量和數據結構(見OS_CORE.C)。
OSInit()建立空閑任務idle task,這個任務總是處于就緒態(tài)的??臻e任務OSTaskIdle()的優(yōu)先級總是設成最低,即OS_LOWEST_PRIO。如果統(tǒng)計任務允許OS_TASK_STAT_EN和任務建立擴展允許都設為1,則OSInit()還得建立統(tǒng)計任務OSTaskStat()并且讓其進入就緒態(tài)。OSTaskStat的優(yōu)先級總是設為OS_LOWEST_PRIO-1。
圖F3.7表示調用OSInit()之后,一些μC/OS-Ⅱ變量和數據結構之間的關系。其解釋是基于以下假設的:
評論