|
在51系列单片机上实现非抢先式消息驱动机制的RTOS 厦门大学许俊许克平 摘要针对51系列单片机的特点,用面向对象的思维方法,构造一个基于非抢先式消息驱动机制的RTOS。具体阐述RTOS中消息的封装和消息队列、主循环、消息的获取和发送、定时处理以及核心管理模块的构成。 关键词单片机RTOS面向对象消息队列定时处理 8051单片机在中小型应用场合相当常见。在20世纪80年代中期,Intel公司将8051内核使用权以专利互换或出售的形式转让给世界上许多著名的IC制造商,使得8051成为众多厂商支持的、发展出上百种品种的大家族;同时由于8051单片机是进入中国市场最早的单片机之一,在国内有众多的仿真器开发商支持51系列单片机,大多数的终端产品公司也大量应用51系列单片机作为产品的开发,使得51系列单片机在国内成为开发中小嵌入式系统的首选单片机之一。由于一些知名的软件开发商开发出比较可靠的面向51系列单片机的C级编译器和RTOS,在RTOS的支持下,可以应用51系列单片机开发出可靠性高、实时性强的较大型程序代码,应用于更多要求较高的场合。 商品化的51系列RTOS中,有代表性的是Franklin公司设计的RTX51。它根据RTOS内核的大小分为迷你版本、标准版本和专业版本。RTX51是一种抢先式的多任务操作系统,可以设置0~3共4级优先级,实时性很强,功能齐全。可以供用户调用的服务(函数)有3类:系统服务、信息服务和功能服务。各个任务之间的参数传递是通过邮箱操作(包含在功能服务中)来实现的。但是这样的一个操作系统对于大多数应用,过于复杂,特别是对于各个任务之间的参数传递必须使用邮箱操作来实现,需要使用外部数据存储器和300字节左右的额外代码量。迷你版本(含标志传送功能)就有700字节左右的代码量,而且分配给每个任务的内部RAM默认为8个字节。TINY版本的RTX51最多可以允许16个任务运行,这样对于内部RAM的分配变得非常困难。 笔者在某刊物上看到另外一种51单片机的RTOS,实际上是设置几个标志位。将中断产生的标志作为消息,在主程序中不断地查询这些标志位。当查询到某个标志位改变时,就调用相应的模块。首先,这种方式不是严格意义上的消息驱动机制,而且对于各个模块之间的参数传递没有定义,不利于功能模块的划分;此外,由于标志位的查询是顺序进行的,例如当某个中断发生,设置了标志位BIT0和BIT4,假设标志位的查询顺序是从BIT0开始的,本来按照正常次序要先执行模块0和模块4,但是在运行模块0时有另一个中断发生,设置了标志位BIT2,造成模块2比模块4先执行,这样就有可能造成不可预料的后果。 基于非抢先式消息驱动机制的RTOS是采用面向对象的思维方法,把各个功能模块看成是不同的对象,对象之间的通信称为发送消息。对象包含自己的数据和代码,数据表征对象的特征,代码用于相应消息,使对象进行某些动作。对象响应消息进行处理时不被中断,消息没有优先级之分,除非是中断到来,即消息驱动是非抢先式的。OS严格按照消息队列的顺序来“唤醒”相应的对象。基于非抢先式消息驱动机制的RTOS的系统运行框图如图1所示。 图1基于非抢先式消息驱动机制的 RTOS的系统运行框图这样做有几个好处: (1) 绝大多数的应用场合下,“实时性”只是体现在对外部事件的及时响应和对数据的即时接收或者发送。这可借助于51单片机的中断来实现。在中断处理程序中,单片机只对外部事件作必要的处理或者只是将接收数据放到预定的缓冲区立即返回,同时向消息队列发送一条消息通知操作系统。 (2) 采用面向对象的思维方法有利于模块的划分。在多人协同编写1个软件的时候显得尤为重要。它使得负责单个模块的软件设计人员只需要关心自己的那一个部分(当然管理模块除外),各个功能模块的交互是透明的。 (3) 具备相当的通用性。如果需要增加新的功能模块,只需要编写新模块的代码,在OS中增加新模块的标志ID号,而其他部分可以保持不变。 下面详细阐述RTOS的构成。 1 消息的封装和消息队列 基于非抢先式消息驱动机制的RTOS,消息由4个部分组成:TASKID、COMMAND、PARA1、PARA2。其中,TASKID标志功能模块号,OS中的消息循环根据TASKID来确定这个消息是发送给哪个功能模块的,占用1个字节;COMMAND指示该功能模块执行什么样的操作,占用1个字节;PARA1和PARA2是向该功能模块传递的参数(如果需要的话),各占用1个字节的空间。 这样一个消息占用4个字节的内部RAM,消息队列可以容纳10条消息(消息队列的大小可以视具体情况而定),借助2个指针:WPTR、RPTR。当WPTR=RPTR时,表示此时消息队列中没有消息,一旦WPTR≠RPTR时,表明此时消息队列非空。消息队列的存储位置可以根据具体使用场合来确定:当需要使用的RAM空间较多时,例如进行大量数据采集一类的应用,那么消息队列可以位于外部RAM的空间,消息队列可以相应设置大一些;如果消息队列位于内部RAM区,消息队列就要尽量小,而且要合理安排所处的区域,对于51单片机来说可以位于30H~58H。 2 RTOS主循环 RTOS的主循环最主要的任务就是定时查询消息队列。若消息队列非空,则取出最“旧”的那一条消息,并唤醒相应的任务。为此,RTOS还设置了1个“当前消息区”的区域MSGARA,占用3个字节的内部RAM空间。这3个字节的内容由当前取出的那一条消息来填充,分别是COMMAND、PARA1、PARA2,同时TASKID放在寄存器A中。当调用外部函数TBL_JMP时,外部函数TBL_JMP根据A中的TASKID唤醒相应的任务,同时把MSGARA区域中的参数传递给这个任务。OS的主循环程序代码详列如下: OS: LCALL〖〗TASK_0ms〖〗;清看门狗〖〗JB〖〗F_1ms, OS_GETMSG〖〗; 1ms定时到否?〖〗CLR〖〗F_1ms〖〗; 1ms定时到〖〗LCALL〖〗OS_CYCLE〖〗;定周期处理OS_GETMSG: ACALL〖〗GET_MSG;从消息队列中取消息〖〗JC〖〗OS;消息队列为空,则跳转回循环头部〖〗MOV〖〗DPTR, #TASK_TBL;任务列表首地址〖〗LCALL〖〗TBL_JMP;唤醒相应的任务〖〗AJMP〖〗OS;跳转回循环头部注1:定周期处理函数OS_CYCLE在第四部分“RTOS的定时处理”中有详细的介绍。 注2:TBL_JMP为外部函数,入口参数有两个:一个是寄存器A,另一个是函数散转表的首地址。TBL_JMP根据寄存器A中的内容执行相应的任务。 注3:原则上1个任务的完成时间不应该超过1ms。如果1个任务超过1ms,则必须进行任务的分割,具体办法在第四部分“RTOS的定时处理”中有详细的介绍。 3 消息的获取和发送 消息获取函数仅仅由RTOS使用。主要功能是检查消息队列:如果消息队列为空,则置CY=1后立即返回;若消息队列非空,则取出最“旧”的那一条消息(消息队列的排队规则遵循先入先出的规则FIFO)。TASKID放在寄存器A中;COMMAND、PARA1、PARA2放在“当前消息区”MSGARA中。 ;************************* ;名称: GET_MSG ;功能:操作系统从消息队列中取消息(如果消息队列不为空),然后把取出的消息放置当前消息区中 ;入口参数:无 ;出口参数:A(TASKID), MSGARA(COMMAND, PARA1, PARA2), ;CY:当CY=1,表示消息队列为空 ;寄存器使用:A, B, PSW, R0, DPH, DPL ;************************* GET_MSG: PUSH〖〗PSW〖1〗MOV〖〗A, MSGCNT〖1〗CLR〖〗C〖1〗SUBB〖〗A, #01H〖1〗JC〖〗GET_MSG99〖〗;消息队列空〖1〗MOV〖〗A, RPTR〖〗;测试消息队列的读指针是 ;否越界〖1〗ADD〖〗A, #MSGSIZE〖1〗CLR〖〗C〖1〗SUBB〖〗A, #MSGSIZE*MSGTOTAL〖1〗JC〖〗GET_MSG10;读指针越界 MOV〖〗A, #0〖1〗MOV〖〗RPTR, A〖〗;重新调整读指针到队列头〖1〗POP〖〗PSWGET_MSG10:MOV〖〗A, R0〖1〗PUSH〖〗ACC〖1〗MOV〖〗A, #MSGBUFFER〖1〗ADD〖〗A, RPTR〖1〗MOV〖〗R0, A〖1〗MOV〖〗A, @R0〖〗;TASKID -> A〖1〗INC〖〗R0〖1〗MOV〖〗MSGARA, @R0〖〗;COMMAND->(MSGARA)〖1〗INC〖〗 R0〖1〗MOV〖〗MSGARA+1, @R0〖〗;PARA1->(MSGARA+1)〖1〗INC〖〗R0〖1〗MOV〖〗MSGARA+2, @R0〖〗;PARA2->(MSGARA+2)〖1〗DEC〖〗MSGCNT〖1〗CLR〖〗C〖1〗POP〖〗ACC〖1〗MOV〖〗R0, AGET_MSG99: RET 消息发送函数SND_MSG在RTOS中被声明成1个PUBLIC的函数,供外部模块调用。消息发送函数只是负责向消息队列发送消息,入口参数TASKID、COMMAND、DPH、DPL分别放在寄存器A、B、DPH、DPL中。需要特别注意的是,在消息发送过程中,必须禁止任何中断的发生,以免在发送消息到消息队列的过程被中断,同时在中断返回前,中断服务子程序又可能向消息队列发送新的消息。这样就会破坏消息的完整性而带来灾难性的后果。 ;************************* ;名称: SND_MSG ;功能:发送消息到操作系统的消息队列,该函数被外部模块调用 ;入口参数: A(TASKID), B(COMMAND), DPH(PARA1), DPL(PARA2) ;出口参数:无 ;寄存器使用: A, B, DPH, DPL, PSW, R0 ;************************* SND_MSG: CLR〖〗EA〖〗;禁止中断〖1〗PUSH〖〗DPL〖1〗MOV〖〗DPL, R0〖1〗PUSH〖〗DPL〖1〗PUSH〖〗ACC〖1〗PUSH〖〗PSW〖1〗MOV〖〗A, WPTR〖〗;测试消息队列的写指针是否越 ;界〖1〗ADD〖〗A, #MSGSIZE〖1〗CLR〖〗C〖1〗SUBB〖〗A, #MSGSIZE*MSGTOTAL〖1〗JC〖〗SND_MSG10;写指针已经越界 MOV〖〗A, #0〖1〗MOV〖〗WPTR, A〖〗;重新调整写指针到队列头〖1〗POP〖〗PSWSND_MSG10: MOV〖〗A, #MSGBUFFER〖〗;消息队列的首地址〖1〗ADD〖〗A, WPTR〖1〗MOV〖〗R0, A〖1〗POP〖〗ACC〖1〗MOV〖〗@R0, A〖〗;TASKID->消息队列〖1〗INC〖〗R0〖1〗MOV〖〗@R0, B〖〗;COMMAND ->消息队列〖1〗INC〖〗 R0〖1〗MOV〖〗@R0, DPH〖〗; PARA1 ->消息队列〖1〗INC〖〗R0〖1〗POP〖〗B〖1〗POP〖〗DPL〖1〗MOV〖〗@R0, DPL〖〗; PARA2 ->消息队列〖1〗INC〖〗MSGCNT〖〗;消息总数加1〖1〗MOV〖〗R0, B〖〗;恢复R0的原始值〖1〗SETB〖〗EA〖〗;开放中断〖1〗RET4 RTOS的定时处理 RTOS的定时处理是整个RTOS中相当重要的一个环节。我们选用T0作为RTOS的定时器,定时周期为1ms。定时处理不仅提供系统时钟和各种不同的延时时间,而且对消息队列的操作、任务间的同步和长时任务(指执行时间超过1ms的任务)的分割都必须使用到定时处理。 RTOS的定时处理提供的延时时间间隔都是以1ms的定时周期作为基准,而提供给所需要的任务使用。举例来说,按键常常需要进行消除抖动的处理,延时时间通常在10ms以上,在按键处理任务中,就有1个子函数KY_10ms专门负责消除抖动的延时处理。 在RTOS中专门设置1个系统时钟CLOCK,由2个字节组成。高位字节为CLKH;低位字节为CLKL,用BCD码表示。每当1ms定时时间到,CLOCK加1,这样可以提供1~9999ms的延时时间间隔。系统时钟CLOCK的结构如图2所示。 图2系统时钟CLOCK的结构RTOS定周期处理子程序: ;************************* ;名称: OS_CYCLE ;功能: OS定周期处理子程序 ;入口参数:无 ;出口参数: A,DPTR ;寄存器使用: A, DPTR ;************************* OS_CYCLE: MOV〖〗A, CLKL〖1〗ADD〖〗A, #1〖1〗DA〖〗A〖〗;二~十进制调整〖1〗MOV〖〗CLKL, A〖1〗MOV〖〗A, CLKH〖1〗ADDC〖〗A, #0〖1〗DA〖〗A〖〗;二~十进制调整〖1〗MOV〖〗CLKH, A〖1〗MOV〖〗A, CLKL〖1〗ANL〖〗A, #0FH〖1〗MOV〖〗DPTR, #CYCLE_TBL〖1〗LCALL〖〗TBL_JMP〖〗;跳转到相应的延时处理〖1〗RET长时任务的分割也常常使用到定时处理。如果RTOS的定时基准设定为1ms,那么,1个任务的完成时间(实际上精确地说应该是RTOS的1次循环加上可能发生中断处理的时间总和)不能超过2ms,否则会使系统定时周期少1ms。这样就必须把1个长时任务分割成一个个短时任务,每个短时任务执行时间不超过1ms。前一个短时任务返回之前向RTOS发送一条消息,TASKID仍为该任务的TASKID。但是COMMAND参数变为下一个短时任务的COMMAND,PARA1和PARA2则存放下一个短时任务执行时所需要的参数。当RTOS从消息队列中取出这条消息时,就可以唤醒下一个短时任务继续执行,这样直到该长时任务执行完毕。 五、核心管理模块 核心管理模块是基于RTOS上的一个重要任务模块。主要功能是记录当前RTOS的一些关键参数和状态;提供一些公共功能函数供外部任务调用;协调各个任务的运行。限于篇幅,这里不作详细的介绍。 本文介绍的基于非抢先式消息驱动机制的RTOS编译后的二进制代码只有360个字节左右(注:不含核心管理模块),占用内部RAM大约60个字节 左右(消息队列为10个消息,位于内部RAM中)。该RTOS已经应用于实际系统,在提高软件的模块化、增强软件运行的可靠性等方面有很大的优越性。MES 参考资料 1屠祈,屠立德.操作系统基础.北京:清华大学出版社, 2马忠梅,籍顺心,张凯,马岩.单片机的C语言应用程序设计.北京:北京航空航天大学出版社 3余永权.ATMEL 89系列(MCS\ 51兼容)Flash单片机原理及应用.北京:电子工业出版社 4张国峰.Windows应用程序设计——原理、方法和技巧.北京:电子工业出版社 5Franklin Software, Inc.RTX51 REFERENCE GUIDE.
|