1. 程式人生 > >Small RTOS OSStart 函式解析

Small RTOS OSStart 函式解析

Small RTOS 是在 Keil C51 上面 編譯的。
看如下程式碼:

#include "config.h"

void main(void)
{
	TMOD = (TMOD & 0XF0) | 0X01;
	TL0 = 0x0;
	TH0 = 0x0;
	TR0 = 1;
	ET0 = 1;
    OSStart();
}

Keil C51 編譯器 在 程式進入main函式之前,會做如下的工作,
在這裡插入圖片描述

進入 main函式之後 ,
進入 OSStart() 函式:
程式碼如下:

void OSStart(void)        
{
    uint8 idata *cp;
    uint8 i;
	  uint8 tmp ;
    
    cp = STACK;
    
    OSTsakStackBotton[0] = STACK;

    OSTsakStackBotton[OS_MAX_TASKS + 1] = (uint8 idata *)(IDATA_RAM_SIZE % 256);
    
    /* 初始化優先順序最高的任務堆疊,使返回地址為任務開始地址 */
	  /*SP  PCL 然後 SP+1  PCH*/
		tmp = cp ;
    *cp++ = ((uint16)(TaskFuction[0])) % 256; //低8位位元組
		tmp = cp ;
    *cp = ((uint16)(TaskFuction[0])) / 256;  //高8位位元組
	


	/* 初始化優先順序最低的任務堆疊 */
    cp = (uint8 idata *)(IDATA_RAM_SIZE - 1) ;
		tmp = cp ;
    *cp-- = 0;
		tmp = cp ;
	
    *cp-- =  ((uint16)(OSIdle)) / 256;
		
		tmp = cp ;
		
		
    OSTsakStackBotton[OS_MAX_TASKS] = cp;
		
    *cp-- =  ((uint16)(OSIdle)) % 256;
    
		tmp = cp ;

		/* 初始化其它優先順序的任務堆疊 */
    for(i = OS_MAX_TASKS - 1; i > 0; i--)
    {
        *cp-- = 0;
				tmp = cp ;
        *cp-- =  ((uint16)(TaskFuction[i])) / 256;
				tmp = cp ;
        OSTsakStackBotton[i] = cp;
        *cp-- =  ((uint16)(TaskFuction[i])) % 256;
			  tmp = cp ;
    }
    /* 允許中斷 */
    Os_Enter_Sum = 1;
    OS_EXIT_CRITICAL();
    /* 函式返回優先順序最高的任務 */
}

其中的
cp = STACK;
STACK 是經過C51 初始化之後,sp堆疊指標指向的RAM地址。
這樣 cp指標 也指向堆疊指標指向的RAM地址了。

Keil C51 在編譯的時候,會將全域性變數,區域性變數等都分配到RAM的某一個地址上去。
之後,RAM剩餘的地址,才會指定給sp指標,作為棧使用。

/* 初始化優先順序最高的任務堆疊,使返回地址為任務開始地址 */
  /*SP  PCL 然後 SP+1  PCH*/
	tmp = cp ;
*cp++ = ((uint16)(TaskFuction[0])) % 256; //低8位位元組
	tmp = cp ;
*cp = ((uint16)(TaskFuction[0])) / 256;  //高8位位元組

這一部分程式碼的作用是 將 void TaskA(void) 函式的地址,放入堆疊中,
首先將地址的低8位位元組放入sp指向的地址,
然後sp+1 ,
將地址ide高8位位元組放入sp指向的地址。

這樣做的目的是 OSStart 返回之後,會執行 RET 彙編指令。
RET指令的作用如下:
在這裡插入圖片描述

這樣OSStart 會首先跳轉到 TaskA 函式中去。

檢視一下 :test.m51
OSTsakStackBotton 的地址:
D:0010H PUBLIC OSTsakStackBotton
I:0021H PUBLIC STACK

在這裡插入圖片描述

#define IDATA_RAM_SIZE 0x100
cp = (uint8 idata *)(IDATA_RAM_SIZE - 1) ;
cp指標指向了RAM的0xFF地址

函式指向完畢 跳轉到TaskA 去執行 :

void TaskA(void)
{
    while (1)
    {
        OSWait(K_TMO,5);
    } 
}

進入 OSWait(K_TMO,5);
uint8 data OSTaskID = 0;
OSWaitTick[OSTaskID] = ticks; //ticks = 5

    case K_TMO:                                 /* 等待超時,即延時一段時間 */
        OS_ENTER_CRITICAL();
        while (OSWaitTick[OSTaskID] != 0)       /* 判斷超時時間是否到   */
        {
            OSClearSignal(OSTaskID);            /* 任務進入等待狀態     */
            OSSched();                          /* 執行下一個任務       */
        }
        OS_EXIT_CRITICAL();
        return TMO_EVENT;

uint8 OSTaskRuning = 0xff; // 初始值
uint8 const OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00};

OSTaskRuning &= ~OSMapTbl[TaskId]; //將對應的bit位清零
變為:0xfe了