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();
}
}
這個我也可以理解,呵呵。現在我們似乎要看看調度算法了
明天一起再看看調度算法的執行過程,一步一步理下去,我相信就可以理解了,呵呵