3 实时操作系统的实现
基于以上的分析与目的,近日完成了这个操作系统。在堆栈上借用RTx的管理方法,即当前任务使用全部的堆空间,如图1所示。
3.1 堆栈的初始化与任务的创建
堆栈的初始化实际是初始化 0STaskStackBotton数组,并将当前任务指定为空闲任务,下一个运行任务指定为最高优先级任务,即优先级为零的任务。初始化时,将SP的值存人OSTaslkStackBotton[O],SP+2的值存入OSTaskStacKBotton[1],依此类推。而任务是调用0STa- skCreate函数建立的。实际上只是将任务(假设为n号任务)的地址填人到对应OSTaskStackBotton[n]所指向的位置,并将SP向后移动2个字节,如图2所示。
为什么要以这样一种规律而不是其他的方式呢?这是由于在任务建立后,还未进行任务调度之前,各任务的堆栈实际上是它们自身的地址,因而其堆栈深度为2,为了程序的简便而直接填入。
- void main(void){
- OSInit(); /*初始化OSTaskStackBcBotton队列*/
- TMOD=(TMOD&0XFO)| 0XOl;
- TL0=0xBF;
- TH0=0xFC;
- TRO=1;
- ETO=1;
- TFO=O;
- OSTaskCreate(TaskA,NULL,0);
- OSTaskCreate(TaskB,NULL,1);
- OSTaskCreate(TaskC,NULL,2);
- OSStart();
- }
上面这段代码中,所有任务建立后,便调用OSStart()开始任务调度。OSStart()是一个宏定义,如下所示:
- #deflne OSStart() d0{
- OSTaskCreate(TaskIdle,NULL,OS_MAX_TASKS);
- EA=l;
- return;
- }while(O)
首先,它创建了一个空闲任务并打开中断,然后便返回。返回到哪里了呢?我们知道,空闲任务是优先级最低的任务,当调OSTaskCreate建立时,会将其地址填人到SP的位置,并把SP向后移动2个字节(见图2及说明),因而此时处在堆栈顶端的,一定是空闲任务Taslddle。这就使得这里的 return一定会返回到空闲任务。至此,系统进入正常运行状态。
3.2 任务的切换
任务的切换分两种情况,在当前任务优先级低于下一个取得CPU控制权的任务时,将下一个取得CPU控制权的任务的栈顶到当前任务的栈顶之间的内容向RAM空间的高端搬移,以空出全部的RAM空间作下一个任务的堆空间,同时更新对应的OSTaskStackBotton,使其指向新的正确任务的堆栈栈底。如果当前任务的优先级高于下一个任务的优先级,则作相反的搬移,如图3与图4所示。
所有任务必须主动调用OSSleep,放弃CPU的控制权。任务调用OSSleep后,将选择优先级最高的就绪任务运行。
结 语
系统完成后,内核的代码量在400多个字节左右,占用1个定时器中断及小量的内存空间。系统设置容量为8个任务,用户实际可用任务为7个,能够满足一般需求,也达到了在小容量芯片中应用的开发要求。由于没有采用占先式的任务调度,除开全程相关的个别任务的一些局部变量外,其他局部变量已经不存在覆盖关系,由于是任务主动放弃CPU控制权,对于个别需要保护的变量单独进行处理也变得容易。在系统中,全程不需要反复地开关中断,实时性能也很好。对个别时序要求严格的外设(如DSl8820)除外。