Small Rtos51學習筆記1

http://bbs.ednchina.com/BLOG_ARTICLE_1923949.HTM

從函數的執行順序來分析Small RTOS51內核,以便了解整個內核的實現過程及運行機理。
照配套光盤裏面的例程分析
EXT1
#include "config.h"


void main(void)
{
 TMOD = (TMOD & 0XF0) | 0X01; // 定時器0初始化爲16位定時器
 TL0 = 0x0;
 TH0 = 0x0;
 TR0 = 1;
 ET0 = 1;
    OSStart();
}


首先是設定定時器的基本參數,並未開啓總中斷。接着便進入了OSStart函數,接下來我們看看OSStart函數都做了些什麼工作。
OSStart函數屬於OS_cpu_c.c文件中
函數將初始化small rtos51,並開始執行任務ID爲0的任務
       
void OSStart(void)
       
{
    uint8 idata *cp;    //新建一個指針用於後面建立堆棧空間使用
    uint8 i;
   
 // extern idata uint8 STACK[1]; 堆棧起始位置,在OS_CPU_A定義 CP指向這段空間
    cp = STACK;        
   
 /* uint8 idata * data OSTsakStackBotton[OS_MAX_TASKS + 2]; 任務堆棧底部位置
   在config.h中有做如下定義
  void  (* const TaskFuction[OS_MAX_TASKS])(void)={TaskA,TaskB,TaskC};
   將棧頂指向STACK
 */
    OSTsakStackBotton[0] = STACK;
    // 堆棧底部
    OSTsakStackBotton[OS_MAX_TASKS + 1] = (uint8 idata *)(IDATA_RAM_SIZE % 256);
   
    /* 初始化優先級最高的任務堆棧,使返回地址爲任務開始地址 */
    *cp++ = ((uint16)(TaskFuction[0])) % 256;
    SP = (uint8) cp;
    *cp = ((uint16)(TaskFuction[0])) / 256;


    /* 初始化優先級最低的任務堆棧 */
    cp = (uint8 idata *)(IDATA_RAM_SIZE - 1) ;
    *cp-- = 0;
    *cp-- =  ((uint16)(OSIdle)) / 256;
    OSTsakStackBotton[OS_MAX_TASKS] = cp;
    *cp-- =  ((uint16)(OSIdle)) % 256;
   
    /* 初始化其它優先級的任務堆棧 爲其他任務分配堆棧空間*/
    for(i = OS_MAX_TASKS - 1; i > 0; i--)
    {
        *cp-- = 0;
        *cp-- =  ((uint16)(TaskFuction[i])) / 256;
        OSTsakStackBotton[i] = cp;
        *cp-- =  ((uint16)(TaskFuction[i])) % 256;
    }
    /* 允許中斷 */
    Os_Enter_Sum = 1;
    OS_EXIT_CRITICAL();
    /* 函數返回優先級最高的任務 */
}
其實也就是爲每一個任務分配一個空間。
這個時候定時器會開始計時了。當函數返回的時候,由於SP指向的是ID0的位置
所以函數就會跳轉到TaskA函數處運行
void TaskA(void)
{
    while (1)
    {
        OSWait(K_TMO,5);
    }
}
進入函數之後就會一直在while循環中。不斷調用OSWait函數做延時,
接下來我們再看看它又做了些什麼工作
 uint8 OSWait(uint8 typ, uint8 ticks)


{
    OSWaitTick[OSTaskID] = ticks;               /* 設置超時時間         */
                                                /* 可以優化寄存器的使用  */
    switch(typ)
    {
    case K_SIG:                                 /* 等待信號,即掛起自己  */
        OSWaitTick[OSTaskID] = 0;               /* 沒有超時處理         */
        OSClearSignal(OSTaskID);                /* 任務進入等待狀態     */
        OSSched();                              /* 運行下一個任務       */
        return SIG_EVENT;
    case K_TMO:                                 /* 等待超時,即延時一段時間 */
        OS_ENTER_CRITICAL();
        while (OSWaitTick[OSTaskID] != 0)       /* 判斷超時時間是否到   */
        {
            OSClearSignal(OSTaskID);            /* 任務進入等待狀態     */
            OSSched();                          /* 運行下一個任務       */
        }
        OS_EXIT_CRITICAL();
        return TMO_EVENT;
    case (K_TMO | K_SIG):                       /* 等待信號(掛起自己)直到超時  */
                                                /* 別的任務或中斷可以恢復它 */
        OS_ENTER_CRITICAL();
        if (OSWaitTick[OSTaskID] == 0)          /* 判斷超時時間是否到   */
        {
            return TMO_EVENT;
        }
        OSClearSignal(OSTaskID);                /* 任務進入等待狀態     */
        OS_EXIT_CRITICAL();
        OSSched();                              /* 運行下一個任務       */
        if (OSWaitTick[OSTaskID] != 0)
        {
            OSWaitTick[OSTaskID] = 0;
            return SIG_EVENT;
        }
        return TMO_EVENT;
    default:
        OSWaitTick[OSTaskID] = 0;
        return NOT_OK;
    }
}
這個是內核函數來的,包含在OS_core.c中,靠定時器0中斷調用OSTimeTick函數來
使 OSWaitTick[OSTASKID] -- 直至OSWaitTick[OSTASKID]爲0,當不爲零的時候
 OSClearSignal(OSTaskID)會使任務進入等待狀態,OSSched()函數將會將下一個
 就緒任務運行,現在我們就來看看如何將該任務取消運行進入等待狀態的


 void OSClearSignal(uint8 TaskId)
 {
  //  判斷當前任務是否在許可範圍內否則返回
    if (TaskId < OS_MAX_TASKS)
    {
  // 進入臨界狀態
        OS_ENTER_CRITICAL();
#if OS_MAX_TASKS < 9
/* 將OSTaskRuning的相應位復位
現在我們來看看OSTaskRuning的定義
#if OS_MAX_TASKS < 9
uint8 OSTaskRuning = 0xff;
#else
uint16 OSTaskRuning = 0xffff; 它被定義爲一個全局變量每一位代表一個任務的狀態
爲1表示任務就緒,爲零表示任務掛起。
uint8 const OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00};
*/
        // 總任務數要是小於9,那麼用UINT可以表示,則可以直接用TABLE表清零
        OSTaskRuning &= ~OSMapTbl[TaskId];
#else
    // 任務總數大於9,若是當前任務小於8,那麼將低8位操作就可以了
        if (TaskId < 8)
        {
            ((uint8 *)(&OSTaskRuning))[LOW_BYTE] &= ~OSMapTbl[TaskId];
        }
    // 任務若是大於8,那麼必須操作高8位
        else
        {
            ((uint8 *)(&OSTaskRuning))[HIGH_BYTE] &= ~OSMapTbl[TaskId & 0x07];
        }
#endif
        OS_EXIT_CRITICAL();
    }
}
這個我也可以理解,呵呵。現在我們似乎要看看調度算法了
明天一起再看看調度算法的執行過程,一步一步理下去,我相信就可以理解了,呵呵

發佈了9 篇原創文章 · 獲贊 9 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章