从函数的执行顺序来分析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();
}
}
这个我也可以理解,呵呵。现在我们似乎要看看调度算法了
明天一起再看看调度算法的执行过程,一步一步理下去,我相信就可以理解了,呵呵
文章评论(0条评论)
登录后参与讨论