第 25卷 第 5期
2003年 1D月
三峡大学 学报(自然科学版 )
J of China Three Gorges Univ.(Natural Sciences)
Vo1.25 No.5
Oct.2003
51单片机实时操作系统的构建
刘从新 曾维鲁
(三峡大学 电气信息学院,湖北 宜昌 443002)
摘要:设计了一个在 51单片机上运行的基于优先级的抢占式实时多任务内核一510S,给出了其设计
思路,并对一些设计难点进行 了讨论 .
关键词:抢占式; 实时多任务内核; 单片机
中图分类号:TP368.1 TP316.2 文献标识码:A 文章编号:1007—7081(2003)05—0444—04
Construction of Real—Time Operation System for 51 MCU
Liu Congxin Zeng Weilu
(College of Electric Engineering& Information Science,China Three Gorges Univ.,Yichang 443002,China)
Abstract A preemptive real—time multitask kernel based on priority runningon 5 1 MCU is realized and some
key problems in the design are also discussed here.
Keywords preemptive; real—time multitask kernel; M CU
随着嵌入式系统应用的 日益广泛,RTOS(Real—
time Operation System)越来越受到嵌入式系统开发
人员的青睐,特别是进入 2O世纪 9O年代后,RTOS
更是逐步确立了在嵌入式系统设计中的主导地位,这
体现了单片机应用从低水平向高水平的一个很大进
步 .使用 RTOS所带来的最大好处是可提高嵌入式
系统的可靠性和确定性,提高软件的开发效率,缩短
软件开发周期 .由于商业化 RTOS软件较高的价格
和使用成本(版权费、维护费等)的限制,RTOS在国
内的应用并不普遍 .本文设计了一个在 51单片机上
运行的抢占式实时多任务内核一510S,给出了其设
计思路,并对一些设计难点进行了讨论 .
1 多任务抢 占式优 先级调度的实时内
核 的设计
1.1 任务调度机制
抢先式优先级调度实时内核为每个任务分配一
个唯一的优先级别,当前任务退出之后,内核从等待
队列挑选出任务优先级别最高的任务投入运行 .我
收稿日期l2003-06-04
作者简介;刘从新(1975一),男,硕士研究生
们称这样的调度策略为基于优先级的调度策略 .基
于优先级的调度策略在非抢占模式下,其响应的及时
性和确定性方面都不好 .比如,当一个任务在运行的
时候 ,一个更高优先级任务就绪了,但是内核并不立
即将其投入运行,而是等到这个任务放弃了 CPU的
使用权;任务的响应时间得不到保证 .51单片机大多
应用在控制系统当中,所以 510S采用了抢先式的基
于优先级的调度策略,优先级高的任务一旦就绪,立
即投入运行,其工作的核心原理是:近似地让最高优
先级的就绪任务立即处于运行状态 .
在 510S中一个任务要么是一个无 限循环 ,要么
在任务完成后删除自己,并且进入休眠状态 .
调度工作的
内容
财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容
可以分为两个部分:最高优先级
任务的寻找和任务切换 .
(1)最高优先级任务的寻找
①就绪表的形成
不同的内核有不同的处理方式 ,比如可 以将任务
进行优先级别的排序,然后从头到尾进行检索 .这种
方法
快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载
简单,设计方便,但是确定性差 .510S采用了查
表的方法 :
维普资讯 http://www.cqvip.com
第 25卷 第 5期 刘从 新等 51单片机实 时操 作 系统 的构建 445
首先 ,将 64个任务分为 8组(TaskTb[N],N一
0,1,2,⋯⋯,7),每组 8个任务,每个任务对应 Task—
Tb[N]中的一位,每组对应一个 TaskGrp[7]中的一
位 .当有某优先级的任务就绪时,TaskTb[N]中相
应位置位,TaskTb[N]中只要有一位置位,TaskGrp
ET1中 bitN就置位 .如,若优先级为 30的任务处于
就绪状态,那么 TaskTb[3]的 bit6置位 1,而且也将
TaskGrp[7]中的 bit3置位 1.
任务的优先级取值范围是 0~63,可以仅用一个
字节的低 6位来表示 .按照上面分组的方法可以总
结出这样的规律:
表 1 任务的优先级 用二进制 的表示 图
YYY表示在 TaskGrp[-I中的位置以及 TaskTb[]行
所在的位置,XXX表示在 TaskTb[]列所在的位置
②从就绪表查找出最高优先级别的任务
前面我们把优先级数分解为高三位和低三位,从
而决定任务在 TaskGrp和 TaskTb中相应位置,在
这里我们先分别求出最高优先级任务的高三位和低
三位即可 .假设 TaskGrp值为 0x24—100 100 b,表
明 TaskTb[2]和 TaskTb[5]存在准备就绪的任务 ,
显然 TaskTb[2]中的任务优先级 比 TaskTb[5]要
高,所以最高优先级就绪任务的高 3位一定是 2;再
通过 TaskTb[2]的值来确定低 3位,假设为 Ox12=
010 010b,表明第 1个和第 4个任务处于就绪态,优
先级高的任务是第 1个,所以最高优先级就绪任务的
低 3位一定是 1;最后可以得到最高优先级的就绪任
务 的优先级为 010 010 b一18.
上面我们通过观察法求出了最高优先级的就绪
任务的优先级,接下来推导一般方法 .高优先级有着
最小的优先级号,所 以不管对于求高 3位还是低 3
位,都是将已知的数展开成 8位的二进制数 ,最低为
1的位数即为相应的欲获得的数,即:
1=00000001b一>0(最低为 1的位是第 0位),
2=00000010b一>1(最低为 1的位是第 1位),
3=00000011b一>0(最低为 1的位是第 0位),
显然,用程序实现不但复杂,而且其执行时间是
不确定 的,因为有时 只需一个循 环即可 ,而 有时需 要
8个循环,不符合实时系统的确定性原则 .所 以在
51OS中,仍然采用查表 的方法实现,这个表为数组
OSTb[-2553,利用该表,计算最高优先级任务的优先
级的算法如下 :
High3=OSTb[TaskGrp];
Low3一OSTb[TaskTb[High3]];
Prio=(Hign3<< 3)+Low3;
const OSTb[]一 {//o~255个元素
0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,
0);
显然,单数下标查表结果是第 0位 .
(2)任务的切换
任务调度模块 Sched()首先检查优先级最高任
务当前是否处于运行状态,如果是,则没有必要进行
调度,否则进行调度 .51OS为每一个任务设计一个
TCB(任务控制快),它
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
了该任务的状态信息和指
向私有堆栈的指针,当任务调度的条件满足时,任务
调度模块 Sched()首先记录当前最高优先级任务的
TCB地址,然后调用切换函数进行任务切换 ,在任务
中这个函数是 TaskSw(),在中断中这个函数是 In—
tCtxSw().
TaskSw()在有的处理器环境下是一个软中断调
用,但是在 8051系列中,TaskSw()是一个函数,51
的 SP只有 8位,无法在 64K空间中自由移动,只好
采用拷贝全部硬件堆栈内容的笨办法,所以切换工作
比较麻烦,即,首先将当前 CPU工作现场保存到当前
系统硬件堆栈中,然后再把系统硬件堆栈的全部内容
保存到当前任务的私有堆栈中,接着恢复高优先级任
务的私有堆栈到系统硬堆栈中,最后模拟一次中断返
回,新任务投入运行,任务切换完成 .
IntCtxSw()工作过程有点不太一样,其工作原理
是:首先 SP=SP一4来调整 SP指针 ,去掉在调用 In—
tExit()和 IntCtxSw()过程中压入堆栈的多余内容,
然后将系统堆栈中的内容保存到被中断任务的私有
堆栈中,紧接着将高优先级的任务的现场恢复到系统
堆栈中,然后模拟一次中断返回,任务切换就完成
了.在系统硬堆栈可以建立在外 RAM 的CPU中,完
成一次任务切换实际上只要做一次堆栈指针的移动
以及一个中断返回,仅需要几条汇编指令 .另外 ,在
KeilC编译环境下,处理重入函数的时候,私有堆栈
还要有一些额外的
要求
对教师党员的评价套管和固井爆破片与爆破装置仓库管理基本要求三甲医院都需要复审吗
来满足函数重入的问题 ,这在
下面将会谈到 .
内核在下面情况中进行任务调度:
主动调用 API函数和中断(系统级的时间片中
断和用户级中断).
①主动调用 API函数 .
当 API察觉 到需要 切换 时就 调用 调度 函数
Sched(),这个过程是系统 自动完成 的,用户没有参
与 .调度函数判断是否切换,如果需要切换 ,则调用
TaskSw()(软中断)进行任务的切换,其返回地址(紧
邻 TaskSw()的下一条汇编指令的 PC地址)就被 自
维普资讯 http://www.cqvip.com
446 三 峡 大 学 学 报 (自 然 科 学 版 ) 2003年 l0月
动压入堆栈,接着在 TaskSw()里保存 CPU寄存器
(PUSHALL),堆栈结构不是任意的,而是经过设计
的 .每次切换都会保存和恢复全部现场信息(POP—
ALL),然后用 RETI回到任务断点继续执行 .这个
断点就是调度函数里的紧邻 TaskSw()的下一条汇
编指令的 PC地址 .
这里的 API包括 FlagPend()和 FlagPost().
②中断
中断可能会使高优先级的任务进入就绪状态,所
以在退出中断前需要一次优先级的调度 .任务调度
发生在中断退出前,这样可以大大提高系统的切换速
率 .中断的返回地址是被中断的地方 ,这和上面调用
TaskSw()(软中断)得到 的返 回地址 不一样 ,为 了避
免调度混乱,在 Sched()中要关中断 .
在 51的应用中,任务间的关系不会很复杂,所以
51OS中没有考虑任务优先级的反转问题,不支持同
级的任务出现,不支持时间片的轮番调度算法和事件
标志 .
1.2 任务间的通信和 同步
1.2.1 任务间的同步一信号和信号量
信号量是一种约定的机制,在多任务内核中普遍
使用 .信号量用于:
控制共享资源的使用权
标志事件的发生
任务间的行为同步
信号像一把钥匙,任务要运行下去,就得先拿到这
把钥匙 .如果信号已经被别的任务占用,该任务只得
挂起,直到别的任务释放,信号一般是二值的,其功能
主要是为了满足资源访问的互斥,如对打印机的访问.
信号量是计数式的,其值可以是 O~65 535.信号
量可以使得多个任务对某资源的访问,如:多个任务
对一块缓冲区的访问 .我们可以把信号看成是信号
量 0-1.
由于信号在任务间的同步中起到了很大作用 ,所
以 51OS实现了对信号的操作一建立、等待、发送信
号 .
建立信号(FlagCreat()):申请一个空闲的事件
控制块,信号量的数量初始化为 1,事件等待任务列
表的初始化 .
等待信号(FlagPend()):如果信号量有效,则信
号量减 1、任务继续进行;如果信号量为 0,则任务进
入该事件的等待列表,并且赋值任务等待时间,然后
启动 Sched()进行多任务的调度,当该任务得到信号
或者等待超时,它会返回原来的断点继续进行,如果
得到信号,那么任务继续运行,反之则是等待超时,那
么内核就强行将任务进入就绪,并返回超时错误 .另
外在 ISR(Interrupt Service Routine)中不允许等待
信号,但可以“不停留”的取信号 .
发送信号(FlagPost()):如果没有任务在等待信
号,信号的值加 1;如果有任务在等待信号,那么等待
列表中选择一个任务就进入就绪态,信号的值不变 .
在 51OS中是根据 FlagPost()传递的任务标识号来
选择哪个任务进入运行,如果这个任务不在等待队列
中,那么优先级最高的任务就进入运行 .在任务和
ISR中都是可以发信号 .
1.2.2 任务问的通信一信箱和消息队列
信号量可以用来任务问的同步,但是不能传递数
据 .传递数据的最好方法:全局变量、信箱和消息队
列 .
由于 51内存资源的宝贵,所以一般采用全局变
量的方法来传递数据 .在 51OS中没有设计和实现
信箱和消息队列 .
1.3 中断处理
中断是处理异步事件的有力手段,为了支持任务
的调度,5lOS设计了私有堆栈和系统堆栈的结构,支
持在中断结束前就可以进行任务的切换 .中断子程
序(ISR)一般要用到汇编语言,这样才能直接对 CPU
寄存器进行操作 .另外为了提高系统的实时响应性
能,ISR设计要尽量精简,将主要事务处理放到任务
中完成,关中断的时间也要尽量的短,最大限度的降
低中断响应 时间 .
在 51中,系统堆栈是从下往上增长,关中断定义
为 EA=0;开中断定义为 EA=1.当然这存在着一个
问题:开中断时可能会改变关中断以前的中断使能状
态 .
1.4 内存管理
在 ANSI C中用 malloc()和 free()两个函数来
动态分配内存和释放内存 ,但是这样会引起内存碎片
的问题 ,并且二者 的执行时间也不是确定的 .
在 51OS采用了文献[1]的设计思想,系统将连
续的大块内存按分区来管理,每个分区中包含有整数
个大小相同的内存块,用 MemGet()和 MemPut()来
分配和释放固定大小的内存块,系统可以同时建立多
个内存分区,每个分区有不同大小的内存控制块 .这
样内存操作的执行时间也就确定下来了 .在释放内
存块的时候要注意释放到正确的内存分区当中,否则
可能会引起系统崩溃 .
在 51OS中采用内存的动态分配,可以高效率的
使用内存,特别是对于单片机这类内存比较缺乏的系
统很是有用的 .
维普资讯 http://www.cqvip.com
第 25卷 第 5期 刘从新等 51单片机实时操作系统的构建 447
2 5lOS的堆栈设计
5lOS的设计中,一个比较关键的问题就是如何
设计出合理的私有堆栈、系统堆栈和仿真堆栈的结
构,因为任务的切换功能的实现和对函数重入的支持
都和它们休戚相关 .
系统堆栈:断点地址 区域(若干返回地址),Keil
C自动人栈;规则区:PSW,ACC,B,DPL,DPH,R0,
R1,R2,R3,R4,R5,R6,R7,SP(被中断任务的 CPU
现场,用户设计,并主动人栈).然也可以不保存 SP,
而保存私有堆栈的长度(),在任务切换时根据堆栈
长度计算出SP的值 .
仿真堆栈:仿真堆栈是为了解决函数的重入问题
而建立的堆栈,其和系统堆栈是相互独立的,它有 自
己的堆栈空间和堆栈指针,保存的内容是函数的形参
和局部变量 .Keil C根据内存模式在相应内存空间
建立仿真堆栈(生长方向由上向下,与系统堆栈相
反).对于小模式,仿真堆栈和系统堆栈共享 Idata空
间,即,函数返回地址、形参和局部变量都放在 Idata
中,栈指针为?C_IBP,IBPSTACK=l,起始值在 st—
artup.a51中初始化为 0FFH+1.对于大模式编译,
函数返回地址保存在系统堆栈里,形参和局部变量放
在仿真堆栈(xdata中)中,栈指针为?C_XBP,当XB—
PSTACK=l时,起始值在 startup.a51中初始化为
OxFFFFH(根据实际的 xdata确定)+l;仿真堆栈效
率低下,Keil C(详见 Keil用户指南)
建议
关于小区增设电动车充电建议给教师的建议PDF智慧城市建议书pdf给教师的36条建议下载税则修订调整建议表下载
尽量不用,
但为了重入操作必须使用 .
私有堆栈:私有堆栈就是每个任务 自己的堆栈,
其在系统堆栈的基础上增加了?C—XBP(大模式)这
一 指向仿真堆栈的指针和相应的仿真栈空间 .5lOS
采用的支持重入的私有堆栈结构如图 l[2],每个私有
堆栈都有各 自的仿真堆栈空间,对仿真堆栈空间的操
作只是移动指针,不进行内存拷贝,效率相对很高 .
私有堆栈空间的大小的确定 .私有堆栈空间=
系统堆栈空间+仿真堆栈空间 .如果堆栈空间过大,
会影响 Keil C编译的程序性能,并且浪费资源;如果
栈顶 —
?C-XBP—————-.
空间间隔
?c—XBP(高)
?C—xBP(f氐)
规则区域 ,
断点区域
堆栈长度
仿真栈空间
堆栈长度
图 1 5lOS的私有堆栈 结构
堆栈空间小,在中断嵌套和程序调用时会造成系统崩
溃 .可以根据函数的嵌套层次和规则区域的长度计
算出系统堆栈空间大小;仿真堆栈大小取决于形参和
局部变量的类型及数量,也可以确算出来 .由于所有
私有堆栈使用相 同空间大小 ,所以取 占用空间最大 的
任务函数的空间大小即为仿真堆栈空间大小,这样私
有堆栈空间大小就确定了.5lOS中 给每个任务的私
有堆栈空间定义一个全局数组,系统堆栈中的内容是
私有堆栈中的一部分,至于私有堆栈的其他部分主要
是由 Keil C来填补 .在新任务投入运行时,要将?C
— XBP指到 自己的私有堆栈空间中来 .
3 结语
本文对在 5l单片机上构建实时操作系统进行了
讨论 ,在实际应用还需要根据具体的应用进一步简化
其设计和扩充别的应用,比如 TCP/IP、FS、GUI等 .
参考文献 :
El3 LABROSSE JEAN J.t~C/OS-II--一源码公开的实时嵌
入式操作系统[M].邵贝贝 .北京:中国电力 出版社 ,
2001.
E23 杨 屹.t~C/OS-II移植 心 得.http://www.21iebbs.
com,2003-03—10.
[责任编辑 张 莉]
维普资讯 http://www.cqvip.com