小虎OS(XiaoHuOS)打造自己的RTOS,基于stc12c5a60s2(51内核)的可剥夺多任务管理操作系统

来源:互联网 发布:java中如果不用static 编辑:程序博客网 时间:2024/04/29 18:02

       因为实在对自动控制感兴趣,所以16年10月份开始计划学习单片机之类的东西。仗着有点 C 的基础,花了1个月的时间学习51单片机,然后开始琢磨STM32。看着各位前辈们的经验,貌似学习操作系统是非常不错的选择。因为我认为操作系统很神秘,所以刚开始的学习计划仅仅是学会移植某种操作系统。

       鉴于我手上又有现成的基于cortex-3 的 ucos 学习资料,于是寒假一开始,我就开始琢磨起 ucos,发现 ucos 的核心其实就是任务调度只要实现了任务调度,其他的就简单了。ucos 关于任务调度的核心代码不长,不过因为是汇编写的,而我又从未接触过汇编,所以也是花了相当的时间去理解它。就这样,边学习 ucos 的源码,边查资料,总算是对任务调度有些理解了,这个时候移植已经无法使我满足了,便萌发了写一个自己的 RTOS 的想法。因为 51 单片机相对简单,所以就决定了在51单片机上写一个自己的操作系统。除夕夜开工,断断续续的,除了走亲戚拜年聚会,心思全在这个系统上,到昨晚终于草草完工了,也算是有个雏形,包含任务创建、任务挂起、任务恢复、任务删除等基本的功能,回头看了看代码,确实不是很完美,但是也能实现多任务管理的功能啦,也就不修改了,所以这个算是最原始的底稿了,迫不及待的加了注释分享出来,抛砖引玉,希望能够给同在学习 RTOS 的一些参考。

       这个操作系统我取名为 小虎OS(XiaoHuOS),代码很简单,核心就是任务调度。不过正是因为简单,所以应该很方便阅读和参考。


从上图看出,代码大小还算可以接受。

       简单说一下 小虎OS  任务调度的原理,其实整个过程可以参考 CPU 的中断。中断发生时,CPU 立刻暂停当前正在运行的任务,保护好现场(CPU寄存器和其他信息),转去执行中断服务,执行完中断服务,CPU 又返回中断发生之前的地方,恢复现场继续执行。如果这一过程能够人为控制,实际上就实现了任务调度。小虎OS 为每一个任务建立了任务栈来保存CPU寄存器和其他信息,在需要执行某个任务时,将其对应的任务栈装载入 CPU 即可。比如当前正在运行任务A,需要执行任务B时,小虎OS 首先将当前的CPU寄存器和其他信息保存到任务A 的栈中,然后将任务B 的栈装载,即可实现任务A到B的调度。在中断级的任务调度中,CPU 自动保护现场,因此不需要手动压栈,只需要调整SP指针即可。这一过程可以参照工程里的源码。那么,如何开始小虎OS呢?

小虎OS 通过 OSStkInit 函数初始化任务栈,栈底保存堆栈长度,然后就是任务代码起始地址,接下来是CPU寄存器,最后是仿真堆栈指针。仿真堆栈指针主要跟局部变量有关系,保存在?C_XBP里,保存恢复现场时也是从这里获取。

OS_STK *OSStkInit(void (*pTask)(void) reentrant, OS_STK* ptos) reentrant{    OS_STK *stk;     stk    = ptos;                              //用户堆栈最低有效地址    *stk++ = 15;                                //用户堆栈长度    *stk++ = (uint16)pTask & 0xFF;              //任务地址低8位    *stk++ = (uint16)pTask >> 8;                //任务地址高8位        *stk++ = 0x00;                                  *stk++ = 0x00;                                  *stk++ = 0x00;                                  *stk++ = 0x00;                                  *stk++ = 0x00;                                  *stk++ = 0x00;                                      *stk++ = 0x00;                 *stk++ = 0x00;                   *stk++ = 0x00;                                  *stk++ = 0x00;                                  *stk++ = 0x00;                                  *stk++ = 0x00;                                  *stk++ = 0x00;                                                                                      *stk++ = (uint16) (ptos+MaxStkSize) >> 8;   //?C_XBP 仿真堆栈指针高8位    *stk++ = (uint16) (ptos+MaxStkSize) & 0xFF; //?C_XBP 仿真堆栈指针低8位            return ((void *)ptos);}
reentrant 是keil4中函数可重入的关键字。

      小虎OS 通过MaxUserTaskNum的预定义决定最大的用户任务数目,最多可以管理7个用户任务,通过MaxStkSize决定任务堆栈深度,任务如果资源比较多,则堆栈深度也得随之增加。

      小虎OS 中,任务被创建后删除前,分为挂起和就绪两个状态,在所有就绪任务中,小虎OS 采用优先级来决定任务执行的顺序,优先级数字越低,优先级越高,小虎OS 总是执行优先级最高的就绪任务。小虎OS 有一个空闲任务,不可挂起,不可删除,优先级最低,是系统初始化自动创建的,用户可以自己在里面添加自己的代码。

void OSIdleTask(void){while(1){// 可添加代码}}
       小虎OS占用定时器0作为系统的时钟节拍,通过OS_TICKS_PER_SECOND决定系统的时钟节拍。小虎OS提供的OSTickDly延时函数可以暂时释放CPU,供其他任务使用。比如

/************************************************************************* *任务1,控制led1亮灭变换,并向串口打印任务1运行*************************************************************************/void task1(void)  reentrant{while(1){led1 = ~led1;OSTickDly(100);prints("task1 running...\r\n"); }}/************************************************************************* *任务2,控制led2亮灭变换,并向串口打印任务2运行*************************************************************************/void task2(void)  reentrant{while(1){ led2 = ~led2; prints("task2 running...\r\n");OSTickDly(300);    // 释放cpu 让低优先级的任务有机会运行}}
在任务1 OSTickDly 期间,其释放CPU给任务2使用,所以即使任务1优先级比任务2高,任务2此时也有机会运行。在两个任务都出于延时中时,空闲任务得以运行。实际上,此时CPU 的利用率被大大提高了。

工程下载地址: http://download.csdn.net/detail/ryuchong/9750794





0 0
原创粉丝点击