原创 Small Rtos51学习笔记1

2010-11-27 11:27 3303 4 4 分类: MCU/ 嵌入式

从函数的执行顺序来分析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)) / 256;
        OSTsakStackBotton = cp;
        *cp-- =  ((uint16)(TaskFuction)) % 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();
    }
}
这个我也可以理解,呵呵。现在我们似乎要看看调度算法了
明天一起再看看调度算法的执行过程,一步一步理下去,我相信就可以理解了,呵呵

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
4
关闭 站长推荐上一条 /3 下一条