使用KEIL C51实现的简单合作式多任务操作系统内核

本文介绍了在51单片机上使用KEIL C51实现的一个简单合作式多任务操作系统内核。通过任务切换原理、调度器的设计和软件定时器的实现,详细阐述了在资源有限的51单片机上实现多任务并行处理的方法。文章讨论了中断前后台系统、有限状态机和操作系统调度器的优缺点,并提供了实际的代码实现和注意事项,如局部变量应定义为static以保持任务切换时的状态。
摘要由CSDN通过智能技术生成

    以前做课程设计时候,在51上实现了一个简单的合作式操作系统内核。写的时候,主要是出于检验自己单片机原理和操作系统知识的目的。这个内核现在看来,功能非常简单,实时性也不高,但是它毕竟是在51单片机上用不到每个线程17B的内存实现了一个多任务并行处理功能,而且完全用C语言写成,没有用到汇编。所以整理发出,权为资料整理。

1 单片机上的多任务操作思路

    在本实验当中,涉及到了实时性较高的电机控制,DS18B20的读写有严格的时序要求。而数码管动态显示、特别是按键扫描等涉及到了不定的延时。这两种设备在实时性上有着一定的冲突。因此,实现思路有三种:
1. 无限循环+中断的前后台系统。
2. 有限状态机(FSM)系统。
    主要思路如下:一个定时器生成一个系统基准时间systick(如1ms加1) 。其它任务拆分为多个状态放入主循环当中,通过状态转换和systick进行工作。
    例如,按键状态机分NOT_PRESSED, PRESS_DELAY, PRESSED,REALEASE_DELAY四个状态。
3. 使用调度器的操作系统。
    第一种方式在应用简单的情况下,具有编写容易、系统本身不耗费资源的优点。但当程序复杂时,各模块前后耦合维护复杂,而且很难保证实时性(当高优先级任务需要处理时,会由于低优先级任务正在运行而得不到及时处理)。如果使用中断,则当任务变多时将没有足够的中断可用,而且中断当中加入过多的程序也是稳定性的大忌。
    第二种方式主要思路如下:首先使用一个变量systick存放系统运行时间(在1ms定时器中断中自加)。而后每个外设结合systick,根据当前运行状态判断是否进行状态转换,并执行相应操作。该方法实时性好,逻辑性强,且不必对PC,SP进行操作。但缺点是程序编写非常复杂。
    第三种方式将不同的模块分为不同的任务,并根据优先程度赋予不同的优先级。在调度器的作用下,各任务在宏观上达到了一个“并行运行”的效果。该方法实时性好,任务编写容易,由于采用了合作式调度器,也不必担心任务的可重入性。缺点是调度器编写复杂,且本身会产生一定开销。

1 多任务切换原理

CPU是依靠PC来确定执行的程序。所以要想在多个函数之间切换,理论上只需要修改PC值即可。但单纯的修改PC值的话,原有的运行状态就会丢失,所以必须保护此时的运行状态(寄存器R0~R8还有PSWSP)。这个过程很像中断服务程序:函数调用过程中,LCALL指令等的返回值还有被保护的寄存器值将被保存在堆栈当中,待结束之后返回原程序时从堆栈恢复。除此之外,C语言中的一些局部变量也是存放在堆栈当中的。如图:





所以,最基本的调度器如下:在系统的初始化阶段,给每一个任务分配一个私有的栈空间。这样,在任务切换时,只需要将需要保护的现场PUSH入堆栈,将被切换的任务的现场恢复(将被保存的通用寄存器R0~R8PSW写入),再将SP指向被切换任务的私有栈即可。如图:

2 KEIL C51多任务切换实现

对于KEIL C51而言,情况有所不同。KEIL C编译器在处理函数调用时的约定规则为"子函数有可能修改任务寄存器",因此编译器在调用前已释放所有寄存器,子函数无需考虑保护任何寄存器.因此,只需要修改堆栈SPPC即可。

基于这一特性,调度器写为了一个C语言函数的形式。

最初写好的基本切换函数如下:

void os_switch()
{  
    task_sp[task_id] = SP;  
    if(++task_id == MAX_TASKS)  
        task_id = 0;   
    SP = task_sp[task_id];
}

逐句解释:

首先,任务A在合适地方调用该函数进行切换,当进入该函数之前,R

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值