第15章RTX51实时操作系统RTOS概述RTX51系统特点RTX51的程序设计RTX51的系统配置RTX51的应用举例15.1RTOS概述单任务系统的设计思路:传统的单片机程序多为单任务系统,其业务逻辑顺序安排在主函数中。主函数是整个程序的入口,一般包含一个死循环,循环过程中通过调用函数来完成相应的操作,而对于一些较短的实时任务则通过中断方式进行处理。此种程序结构简单、直观、易于实现,但对于较复杂的应用,此种结构极为不便,并且不能满足实时性要求较高的场合15.1.1单任务/多任务顺序执行的单任务程序设计voidmain(){intcounter=0;while(1){check_serial_io();//检查串行输入process_serial_cmds();//处理串行输入check_kbd_io();//检查键盘输入process_kbd_cmds();//处理键盘输入app_execute();//应用程序执行counter++;//循环计数}}顺序执行的单任务程序设计该例中,每个函数执行一个独立操作或任务。任务依次按顺序执行。当任务数量增加时,调度会成为问题。例如,若process_kbd_cmds()函数的执行耗费大量时间,主循环会很慢才执行到check_serial_io(),此时串口数据可能已经丢失。多任务系统的执行特点多任务系统的设计思路:各功能模块(如显示、键盘扫描等等)处于等同地位。各功能模块执行顺序可在程序运行过程中动态地改变。各子任务在自已的时间片内运行,通过合理设计时间片大小和各任务的优先级,可以自然地满足系统内各种复杂的时序要求。类似这样的任务管理和调度,就是多任务OS的核心。多任务系统的执行特点check_serial_io()process_serial_cmds()check_kbd_io()process_kbd_cmds()app1_execute()app2_execute()任务调度时间片轮转、任务优先级设定等功能15.1.2什么是RTOS实时操作系统(Real-TimeOperatingSystem,RTOS),是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的操作系统。RTOS广泛应用于嵌入式计算机技术领域,比如μCOS、VxWork、Linux、WinCE等,51单片机上常用的SmallRTOS51,还有目前手机中广泛使用的Android、iOS,都是典型的RTOS。15.2RTX51的特点RTX51是一款小巧的针对基于8051核心的嵌入式系统的多任务RTOS。使用它可以简化比较复杂、有严格时间限制的程序的设计过程。RTX51主要有两个不同的可用版本:标准版(RTX51-Full)和精简版(RTX51-Tiny)。在RTX51-Full中:既可以以轮循(Round-Robin)方式执行任务,也可以按4级任务优先级的方式切换不同优先级的任务。以并行方式工作,支持中断管理,信号和消息可以通过邮箱系统在不同任务之间传递。RTX51-Tiny是RTX51-Full的一个子集,支持RTX51中绝大多数的特性,且不需要外部RAM(XDATA)。RTX51-Tiny支持RTX51-Full的许多特性,但不具有以下功能:不支持优先任务切换不包含信息子程序无存储器库分配子程序。15.2RTX51的特点描述RTX51-FullRTX51-Tiny任务数量最多256个;可同时激活19个16个RAM需求40~46Byte的DATA空间20~200ByteIDATA空间(用户堆栈)最小650字节XDATA空间7Byte的DATA空间3倍于任务数量的IDATA空间代码要求6KB~8KB900Byte硬件要求定时器0或定时器1定时器0系统时钟1000到40000个周期1000到65535个周期中断请求时间小于50个周期小于20个周期任务切换时间快速任务:70~100个周期标准任务:180~700个周期(取决于堆栈负载)100~700个周期(取决于堆栈负载)邮箱系统8个分别带有整数入口的信箱不提供内存池最多16个内存池不提供信号量8*1位不提供15.3RTX51的程序设计由于KeilC中自带RTX51-Tiny版,下面就以Tiny版本为例,简要介绍其软件设计方法。软件环境的要求:在使用RTX51-TINY时,需要以下软件支持:1)C51编译器2)BL51连接定位器3)A51宏汇编器库文件RTX51TNY.LIB必须存储在C51\LIB下,必须指定C51运行库的路径。头文件RTX51TNY.h必须存储在C51\INC下,必须指定C51包含文件的路径。15.3RTX51的程序设计—运行机制RTX51Tiny通过轮循(Round-Robin)方式来实现多任务,以达到多个无限循环或任务的准并行执行。这里的多任务并不是真正同时执行的,而是使用不同的时间片来执行,即只是宏观上的同时执行。它将可用的CPU周期分成多个时间片,由RTX51把这些时间片分配给每一个任务使用。每个任务只能在预定的时间片里运行,然后RTX51再切换到另一个己经准备就绪的任务,让它再执行一定的时间片。时间片一般是比较短促的,一个时间片大约只有毫秒级时间。正是由于这个原因,在用户看来,多个任务似乎是在同时执行的。15.3RTX51的程序设计—运行机制RTX51利用了一个由定时器0的中断信号驱动的定时程序来实现上述时间片的控制。定时器产生的周期性中断信号用来驱动RTX51的定时节拍。SFR中的全局中断允许位EA或定时器0中断允许位ET0被屏蔽,都可能使RTX51-Tiny停止运行。因此,除非有特殊的应用目的,应该使定时器0的中断始终开启,以保证RTX51-Tiny的正常运行。15.3RTX51的程序设计—任务在RTX51系统中,一个任务体现为一个C51函数,该函数不能有返回值,不能有参数,且函数体必须是一个无限循环,以保证该函数不能返回。实际应用中,一个复杂的系统往往被分解成若干可以并行处理的任务,每个任务只完成一个单一的操作(如键盘扫描、显示、通信等),从而降低系统设计的难度。在RTX51-Tiny系统中一个具体的任务通过下面的格式定:15.3RTX51的程序设计—任务voidtaskname(void)_task_num其中,num是任务号,取值为0-15;taskname是任务名称(亦即函数名)。下面是一个具体的任务定义voidinit(void)_task_0{/*操作语句*/while(1){/*操作语句*/}}RTX51-Tiny最多只允许处理16个任务15.3RTX51的程序设计—任务RTX51区分2类任务:快速任务和标准任务。快速任务有很快的响应速度,每个快速任务使用8051一个单独的寄存器组,并且有自己的堆栈区域。RTX51支持最大同时有3个快速任务。标准任务需要多一点的时间来进行任务切换,因此使用的内部RAM相对快速任务要少,所有的标准任务共用1个寄存器组和堆栈。当任务切换的时候,当前任务的寄存器状态和堆栈内容转移到外部存储器中。RTX51-Full支持任务最多达64个;RTX51-Tiny仅支持标准任务,最多16个。这里我们仅讨论标准任务15.3RTX51的程序设计—任务状态RTX51-Tiny的用户任务有5种状态,如下表所示。某一时刻用户任务处在某个状态,在一定条件下任务状态可以发生改变。状态描述运行(RUNNING)当前正在运行的任务处于RUNNING态,同一时刻只能有1个任务处于该状态。就绪(READY)等待运行的任务处于READY态,可能有多个。当前运行的任务时间片完成后,从READY态的任务队列中选取下一个任务运行,使其进入RUNNING态。超时(TIMEOUT)任务由于时间片用完处于TIMEOUT态,在仅具有时间片轮循调度方式的RTX51-Tiny中,该状态等价于READY态。等待(WAITING)正在等待一个事件发生的任务处于WAITING态。如果该事件发生,则任务进入READY态。删除(DELETED)尚未启动的任务处于DELETED态15.3RTX51的程序设计—任务状态5种状态之间的转化条件:READY态/TIMEOUT态RUNNING态WAITING态等待一个事件15.3RTX51的程序设计—一个示例#includereg51.h#includertx51tny.huintcounter0=0;uintcounter1=0;voidjob0()_task_0{//程序的执行从任务0开始os_create_task(1);//将任务1标记为“READY”状态while(1)counter0++;//任务函数内部必须构成死循环}voidjob1()_task_1{while(1)counter1++;//任务函数内部必须构成死循环}思考:counter0和counter1是交替加1么?不能出现main()函数15.3RTX51的程序设计—用于任务管理的常见系统函数1、os_create_task函数原型:charos_create_task(unsignedchartask_id);功能说明:启动已定义的编号为task_id的任务,并标记为就绪,准备执行。返回值:如果任务成功启动,此函数返回0值;如果没有task_id说明的任务,则返回-1。2、os_delete_task函数原型:charos_delete_task(unsignedchartask_id);功能说明:停止编号为task_id的任务,并将此任务从任务表中删除。返回值:如果任务被成功停止并删除,函数返回0值;如果编号为task_id的任务没有启动或不存在,则返回-1。用于任务管理的常见系统函数3、os_running_task_id函数原型:charos_running_task_id(void);功能说明:检测当前处于运行态的任务编号。返回值:返回当前处于运行态的任务编号,返回值为0~15。4、os_set_ready函数原型:voidos_set_ready(unsignedchartask_id);功能说明:将编号为task_id的任务设置为就绪态。返回值:无用于任务管理的常见系统函数5、os_wait函数原型:charos_wait(unsignedcharevent_sel,/*等待的事件*/unsignedcharticks,/*等待时长,即定时器的溢出次数*/unsignedchardummy);/*Tiny版未用,恒为0*/功能说明:暂停当前执行的任务,并等待一个或多个事件(如时间间隔、超时、从另一个任务或中断发出的信号等)发生。参数event_sel说明所等待的一个或几个事件的组合,事件种类如下表所示。事件描述K_SIG等待一个信号量K_TMO等待由ticks指定的超时时间K_IVL等待由ticks指定的时间间隔用于任务管理的常见系统函数5、os_wait返回值:当有一个指定的事件发生时,任务被置为就绪态。当任务继续执行时,os_wait返回重新启动任务的特定事件。有以下可能的返回值:事件描述RDY_EVENT任务就绪标志被os_set_ready或isr_set_ready函数置位SIG_EVENT接收到一个信号量TMO_EVENT达到超时或间隔时间NOT_OKevent_sel参数无效用于任务管理的常见系统函数6、os_wait1函数原型:charos_wait1(unsignedcharevent_sel);/*等待的事件*/功能说明:暂停当前执行的任务,并等待一个事件发生。该函数是os_wait函数的一个子集,它不支持所有的事件,参数event_sel只能是K_SIG。返回值:与os_wait函数对比,缺少TMO_EVENT。7、os_wait2函数原型:charos_wait2(unsignedch