uc/os-ii學習

經典教程:嵌入式實時操作系統uc/os-ii Jean J.Labrosse著 邵貝貝等譯


1. 從主函數開始

int main (void)
{
    init();//一些硬件的初始化
    
    InstallInterruptHandler((unsigned int) OSTickISR, (unsigned int) 0x18);//Timer 1 Interrupt Level 8 指定定時器中斷中斷號
    InstallInterruptHandler((unsigned int) OSCtxSw, (unsigned int) 0x80);//Context Switch 指定上下文切換陷阱
    InitialiseSystemTimer(ACTIVE_TICK_TIMER);

    OSInit(); /* Initialize uC/OS-II*/

    OSTaskCreate(FirstTestTask, (void *)0, &FirstTestTaskStk[TEST_STK_SIZE - 1], APP_TASK_ONE_PRIO);//創造任務1,給出任務1的地址、堆棧大小和優先級
    OSTaskCreate(SecondTestTask, (void *)0, &SecondTestTaskStk[TEST_STK_SIZE - 1], APP_TASK_TWO_PRIO);
    OSStart();  /* Start multitasking   */
    return 0;
}

其中重要的有三個函數OSInit() OSTskCreate() OSStart():

1.1.OSInit()

void  OSInit (void)
{
    OSInitHookBegin();                                           /* Call port specific initialization code   */
    OS_InitMisc();                                               /* Initialize miscellaneous variables       */
    OS_InitRdyList();                                            /* Initialize the Ready List                */
    OS_InitTCBList();                                            /* Initialize the free list of OS_TCBs      */
    OS_InitEventList();                                          /* Initialize the free list of OS_EVENTs    */
#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
    OS_FlagInit();                                               /* Initialize the event flag structures     */
#endif
#if (OS_MEM_EN > 0u) && (OS_MAX_MEM_PART > 0u)
    OS_MemInit();                                                /* Initialize the memory manager            */
#endif
#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u)
    OS_QInit();                                                  /* Initialize the message queue structures  */
#endif
    OS_InitTaskIdle();                                           /* Create the Idle Task                     */
#if OS_TASK_STAT_EN > 0u
    OS_InitTaskStat();                                           /* Create the Statistic Task                */
#endif
#if OS_TMR_EN > 0u
    OSTmr_Init();                                                /* Initialize the Timer Manager             */
#endif
    OSInitHookEnd();                                             /* Call port specific init. code            */
#if OS_DEBUG_EN > 0u
    OSDebugInit();
#endif
}

其中hook爲鉤子函數,是作者留給開發人員的發揮空間,可以在這裏完成一些開發人員想做的事情,比如初始化自己的硬件。條件編譯“開關”都在ucos_ii.h中,可以在這裏對內核進行“剪裁”,決定保留什麼功能,去除什麼功能。

在OSInit中最重要的是三個部分:就緒表、任務塊、事件塊。

1.1.1就緒表

每個任務有自己的優先級0~63。處於就緒態的任務會在就緒表的相應位置1。

如果一個任務的優先級爲8=00001000,即OSRdyGrp=YYY=001,OSRdyTbl[001]=XXX=000

每個任務的優先級都會分成兩部分分別記錄在OSRdyGrp和OSRdyTbl中。


當就緒表中的值是一定的,則有且僅有唯一一個最小值(優先級最高的任務),如當第7/22/30位置一,則最小值爲7。

在就緒表中找到優先級最高的任務:

y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSRdyTbl[y]];
prio = (y<<3) + x;

OSUnMapTbl爲:

若某時刻OSRdyGrp爲0x68,OSRdyTbl爲0xE4。則

3 = OSUnMapTbl[0x68];
2 = OSUnMapTbl[0xE4];
26 = (3<<3) + 2;//最高優先級任務爲26

1.1.2任務控制塊

以下爲任務控制塊精簡版本:

typedef struct os_tcb {
    OS_STK          *OSTCBStkPtr;           /* Pointer to current top of stack                         */
    struct os_tcb   *OSTCBNext;             /* Pointer to next     TCB in the TCB list                 */
    struct os_tcb   *OSTCBPrev;             /* Pointer to previous TCB in the TCB list                 */

    INT32U           OSTCBDly;              /* Nbr ticks to delay task or, timeout waiting for event   */
    INT8U            OSTCBStat;             /* Task      status                                        */
    INT8U            OSTCBStatPend;         /* Task PEND status                                        */
    INT8U            OSTCBPrio;             /* Task priority (0 == highest)                            */

    INT8U            OSTCBX;                /* Bit position in group  corresponding to task priority   */
    INT8U            OSTCBY;                /* Index into ready table corresponding to task priority   */
    OS_PRIO          OSTCBBitX;             /* Bit mask to access bit position in ready table          */
    OS_PRIO          OSTCBBitY;             /* Bit mask to access bit position in ready group          */

} OS_TCB;

一旦任務建立,一個任務控制塊就被賦值。當任務的CPU使用權被剝奪,uc/os-ii用它來保存該任務的狀態。OS_TCB全部駐留在RAM中。

在ucos初始化時,所有任務控制塊OS_TCB都被連接成單向空任務鏈表,然後OSTCBFreeList的值調整爲指向鏈表下一個空的任務控制塊。一旦任務被刪除,任務控制塊就還給空任務鏈表。


任務鏈表初始化:

static  void  OS_InitTCBList (void)
{
    INT8U    ix;
    INT8U    ix_next;
    OS_TCB  *ptcb1;
    OS_TCB  *ptcb2;

    OS_MemClr((INT8U *)&OSTCBTbl[0],     sizeof(OSTCBTbl));      /* Clear all the TCBs                 */
    OS_MemClr((INT8U *)&OSTCBPrioTbl[0], sizeof(OSTCBPrioTbl));  /* Clear the priority table           */
    for (ix = 0u; ix < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1u); ix++) {    /* Init. list of free TCBs     */
        ix_next =  ix + 1u;
        ptcb1   = &OSTCBTbl[ix];
        ptcb2   = &OSTCBTbl[ix_next];
        ptcb1->OSTCBNext = ptcb2;
#if OS_TASK_NAME_EN > 0u
        ptcb1->OSTCBTaskName = (INT8U *)(void *)"?";             /* Unknown name                       */
#endif
    }
    ptcb1                   = &OSTCBTbl[ix];
    ptcb1->OSTCBNext        = (OS_TCB *)0;                       /* Last OS_TCB                        */
#if OS_TASK_NAME_EN > 0u
    ptcb1->OSTCBTaskName    = (INT8U *)(void *)"?";              /* Unknown name                       */
#endif
    OSTCBList               = (OS_TCB *)0;                       /* TCB lists initializations          */
    OSTCBFreeList           = &OSTCBTbl[0];
}

1.1.3事件控制塊

事件控制塊ECB是用於實現以下功能函數的基本數據結構:信號量管理、互斥型信號量管理、消息郵箱管理以及消息隊列管理。

typedef struct os_event {
    INT8U    OSEventType;                    /* Type of event control block (see OS_EVENT_TYPE_xxxx)    事件類型*/
    void    *OSEventPtr;                     /* Pointer to message or queue structure                   等待任務所在的組*/
    INT16U   OSEventCnt;                     /* Semaphore Count (not used if other EVENT type)          計數器(當事件是信號量的時候)*/
    OS_PRIO  OSEventGrp;                     /* Group corresponding to tasks waiting for event to occur 指向消息或者消息隊列的指針*/
    OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur                等待任務列表*/

#if OS_EVENT_NAME_EN > 0u
    INT8U   *OSEventName;
#endif
} OS_EVENT;
每個信號量、互斥型信號量、消息郵箱以及消息隊列都應分配到一個事件控制塊ECB。

1.2.OSTaskCreate()

通過將任務的地址和其他參數如優先級傳遞到此函數中來建立任務。

1.3.OSStart()

void OSStart(void){

if (OSRunning == OS_FALSE) { OS_SchedNew(); /* Find highest priority's task priority number */ OSPrioCur = OSPrioHighRdy; OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; /* Point to highest priority task ready to run */ OSTCBCur = OSTCBHighRdy; OSRunning = 1; OSStartHighRdy(); /* Execute target specific code to start task */ } }

在這裏完成最高優先級查找和開始執行最高優先級任務。


兩個用戶任務的定義:

void FirstTestTask (void *pdata)
{
	pdata = pdata;
	InitiateTimer(ACTIVE_TICK_TIMER);
	while(1)
	{
		get_status_for_ucos();//用戶任務
		
		OSTimeDly(10);//任務延時10個時鐘節拍
	}
}
void SecondTestTask (void *pdata)
{
	pdata = pdata;
	InitiateTimer(ACTIVE_TICK_TIMER);
	while(1)
	{
		get_vector_for_ucos();
		OSTimeDly(15);//任務延時15個時鐘節拍
	}
}


2. 系統的基本運作

在任務開始運行之後,每遇到任務的“OSTimeDly”,任務就進入等待狀態。在這個函數中會調用OS_Sched()函數進行任務調度,重新尋找就緒列表中的最高優先級任務,並調用OS_TASK_SW()函數,出發陷阱,開始任務切換。

3.系統移植

與處理器相關的代碼只有OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C。

OS_CPU.H中包含臨界區的實現方式。

OS_CPU_A.ASM中實現OSStartHighRdy()使就緒態任務中優先級最高的任務開始運行,OSCtxSw()任務切換,OSIntCtxSw()和OSTickISR()提供節拍定時中斷。

OS_CPU_C.C中實現任務堆棧初始化以及所有鉤子函數(可以不寫)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章