1、第第9章章 多任务实时操作系统多任务实时操作系统RTX-51 RTX-51是是Keil公司开发的一款应用于公司开发的一款应用于80C51系列单片机的实时多任务操作系统。采用系列单片机的实时多任务操作系统。采用RTX-51可简化复杂的软件设计,缩短项目周期。可简化复杂的软件设计,缩短项目周期。RTX-51使得复杂的多任务程序设计变得简单,因此在使得复杂的多任务程序设计变得简单,因此在80C51系列单片机嵌入式系统中应用很广泛。系列单片机嵌入式系统中应用很广泛。n9.1 RTX-51实时多任务操作系统简介实时多任务操作系统简介n9.2 RTX-51 TINY的任务管理的任务管理n9.3 如何使用如
2、何使用RTX-51 n9.4 RTX-51 TINY提供的系统函数提供的系统函数n9.5 RTX-51 TINY的配置的配置n9.6 基于基于Proteus的的RTX-51应用实例应用实例n 本本 章章 小小 结结RTX-51实时多任务操作系统简介实时多任务操作系统简介 RTX-51是是Keil公司开发的用于公司开发的用于80C51系列单片机的多任系列单片机的多任务实时操作系统。务实时操作系统。RTX-51可以在单个可以在单个CPU上管理几个作业上管理几个作业(任务),因而使复杂的系统和软件设计以及有时间限制的(任务),因而使复杂的系统和软件设计以及有时间限制的工程开发变得简单。工程开发变得简
3、单。RTX-51有有2个模式:个模式:RTX-51 FULL(完全模式)和(完全模式)和RTX-51 TINY(最小模式)。(最小模式)。RTX-51 FULL允许允许4个优先权任务的循环和切换,并且还能并行个优先权任务的循环和切换,并且还能并行地利用中断功能。地利用中断功能。RTX-51支持信号传递,以及与系统邮箱和信号支持信号传递,以及与系统邮箱和信号量进行消息传递。量进行消息传递。RTX-51的的os_wait 函数可以等待以下事件:中函数可以等待以下事件:中断、时间到、来自任务或中断的信号、来自任务或中断的消息、断、时间到、来自任务或中断的信号、来自任务或中断的消息、信号量。信号量。R
4、TX-51 TINY是是RTX-51 FULL的一个子集,可以很容的一个子集,可以很容易地运行在易地运行在80C51系统上,而不需要外部系统上,而不需要外部RAM。RTX-51 TINY支持按时间片循环任务调度,支持任务支持按时间片循环任务调度,支持任务间信号传递,最大间信号传递,最大16个任务,可以并行地利用中断。个任务,可以并行地利用中断。具有以下等待操作:超时、另一个任务或中断的信号。具有以下等待操作:超时、另一个任务或中断的信号。但它不能进行信息处理,不支持存储区的分配和释放,但它不能进行信息处理,不支持存储区的分配和释放,不支持占先式调度。不支持占先式调度。RTX-51 TINY是一
5、个很小的内核,是一个很小的内核,完全集成在完全集成在Keil C51编译器中。更重要的是,它仅占编译器中。更重要的是,它仅占用用800 B左右的程序存储空间,可以在没有外部数据存左右的程序存储空间,可以在没有外部数据存储器的储器的80C51系统中运行,但应用程序仍然可以访问系统中运行,但应用程序仍然可以访问外部存储器。外部存储器。9.1.1 单任务程序与多任务程序的比较单任务程序与多任务程序的比较1简单的单任务简单的单任务嵌入式程序和标准嵌入式程序和标准C程序都是从程序都是从main()函数开始执行的,在函数开始执行的,在嵌入式应用中,嵌入式应用中,main()通常是一个无限循环,可以认为是一
6、通常是一个无限循环,可以认为是一个持续执行的单个任务,个持续执行的单个任务,例如例如void main(void)while(1)/*永远重复永远重复*/do_something();/*执行执行 do_something“任务任务”*/在这个例子里,在这个例子里,do_something函数可以认为是一个单任务,由函数可以认为是一个单任务,由于仅有一个任务在执行,所以没有必要进行多任务处理或使用多于仅有一个任务在执行,所以没有必要进行多任务处理或使用多任务操作系统。任务操作系统。2多任务循环多任务循环 main()函数通过在一个循环里调用多个服务函数(或任务)函数通过在一个循环里调用多个服务
7、函数(或任务)来实现伪多任务调度。来实现伪多任务调度。例如例如void main(voidvoid main(void)intint counter=0;counter=0;while(1)while(1)/*一直重复执行一直重复执行*/check_serial_io check_serial_io();();/*检查串行输入检查串行输入*/process_serial_cmds process_serial_cmds();();/*处理串行输入处理串行输入*/check_kbd_io check_kbd_io();();/*检查键盘输入检查键盘输入*/process_kbd_cmds pro
8、cess_kbd_cmds();();/*处理键盘输入处理键盘输入*/adjust_ctrlr_parms adjust_ctrlr_parms()();/*调整控制器调整控制器*/counter+;counter+;/*增加计数器增加计数器*/3前后台系统前后台系统 main()函数仍然是在一个循环中调用相应的函数完成函数仍然是在一个循环中调用相应的函数完成相应的操作,这部分可以看成是后台行为,前台程序则通过相应的操作,这部分可以看成是后台行为,前台程序则通过中断来处理紧急事件。中断来处理紧急事件。bit int0_flag=0;/中断中断0发生标记,初始化为发生标记,初始化为0void m
9、ain(void)int counter=0;TCON=0 x55;/*电平触发外部中断电平触发外部中断*/IE=0 x81;/*打开外中断打开外中断int0*/while(1)/*后台运行的任务后台运行的任务*/check_serial_io();/*检查串行输入检查串行输入*/process_serial_cmds();/*处理串行输入处理串行输入*/check_kbd_io();/*检查键盘输入检查键盘输入*/process_kbd_cmds();/*处理键盘输入处理键盘输入*/counter+;/*增加计数器增加计数器*/if(int0_flag)例如例如:do_int0_someth
10、ing();/*执行执行do_int0_something任务任务*/int0_flag=0;/清除清除int0_flag void exint0(void)interrupt 0 /处理紧急事件任务处理紧急事件任务 int0_flag=1;/*设置中断设置中断0标记标记*/;在程序运行时,后台程序检查每个任务是否具备运行条件,通在程序运行时,后台程序检查每个任务是否具备运行条件,通过一定的调度算法来完成相应的操作。对于实时性要求特别严过一定的调度算法来完成相应的操作。对于实时性要求特别严格的操作通常由中断来完成,仅在中断服务程序中标记事件的格的操作通常由中断来完成,仅在中断服务程序中标记事件
11、的发生,不再做任何工作就退出中断,经过后台程序的调度完成发生,不再做任何工作就退出中断,经过后台程序的调度完成事件的处理,这样就不会造成在中断服务程序中处理费时的事事件的处理,这样就不会造成在中断服务程序中处理费时的事件而影响后续事件和其他中断。件而影响后续事件和其他中断。4RTX-51实时多任务实时多任务 RTX-51TINY允许允许“准并行准并行”同时执行几个任务。各个任务并非持续运行,同时执行几个任务。各个任务并非持续运行,CPU执行时间被划分为若干时间片(执行时间被划分为若干时间片(time slice),每一个任务在预先定义),每一个任务在预先定义好的时间片内得以执行。时间到使正在执
12、行的任务挂起,并使另一个任务开好的时间片内得以执行。时间到使正在执行的任务挂起,并使另一个任务开始执行。当使用始执行。当使用RTX-51 TINY时,为每个任务建立独立的任务函数。时,为每个任务建立独立的任务函数。void check_serial_io_task(voidvoid check_serial_io_task(void)_task_ 1)_task_ 1 /*该任务检测串行该任务检测串行I/0I/0*/void process_serial_cmds_task(voidvoid process_serial_cmds_task(void)_task_ 2)_task_ 2 /*该
13、任务处理串行命令该任务处理串行命令*/void check_kbd_io_task(voidvoid check_kbd_io_task(void)_task_ 3)_task_ 3 /*该任务检测键盘该任务检测键盘I/OI/O*/void process_kbd_cmds_task(voidvoid process_kbd_cmds_task(void)_task_ 4)_task_ 4 /*处理键盘命令处理键盘命令*/void startup-_task(voidvoid startup-_task(void)_task_ 0)_task_ 0 os_create_task(1);/os_
14、create_task(1);/*建立串行建立串行I/OI/O任务任务*/os_create_task(2);/os_create_task(2);/*建立串行命令任务建立串行命令任务*/os_create_task(3)os_create_task(3);/*建立键盘建立键盘I/OI/O任务任务*/os_create_task(4);/os_create_task(4);/*建立键盘命令任务建立键盘命令任务*/os_delete_task(0);/os_delete_task(0);/*删除启动任务删除启动任务*/例如例如:9.1.2 使用使用RTX-51 TINY的软硬件要求的软硬件要求1
15、编译环境编译环境 操作系统操作系统RTX-51的软件环境要求:的软件环境要求:C51编译程序。编译程序。BL51连接程序。连接程序。A51宏汇编程序。宏汇编程序。库文件库文件RTX-51TNY.LIB必须保存在必须保存在DOS环境变量环境变量C51LIB指定的程序库路径内,一般是目录指定的程序库路径内,一般是目录C51LIB。头文件。头文件RTX-51TNY.H必须保存在必须保存在DOS环境变量环境变量C51INC指定的包含路径指定的包含路径内,一般是目录内,一般是目录C51INC。RTX-51内核完全集成在内核完全集成在Keil C51编译器中,在编译器中,在Vision2 IDE完成安装之
16、后,软件环境即满足上述要求。完成安装之后,软件环境即满足上述要求。使用使用RTX-51 TINY系统时,需要了解其在编译环境、硬件系系统时,需要了解其在编译环境、硬件系统方面的要求和技术参数。统方面的要求和技术参数。RTX-51 TINY运行于大多数运行于大多数80C51兼容的器件及其变种上。兼容的器件及其变种上。RTX-51 TINY应用程序可以访问外部数据存储器,但应用程序可以访问外部数据存储器,但RTX-51 TINY内核无此需求。内核无此需求。2硬件系统硬件系统RTX-51 TINY技术参数技术参数描 述RTX-51 TINY任务数量16个RAM需求7字节DATA空间3倍于任务数量的I
17、DATA空间代码要求900字节硬件要求定时器0系统时钟100065535个周期中断请求时间小于20个周期任务切换时间100700个周期取决于堆栈的负载 RTX-51 TINY支持支持Keil C51编译器全部的存储模编译器全部的存储模式。存储模式的选择只影响应用程序对象的位置,式。存储模式的选择只影响应用程序对象的位置,RTX-51 TINY系统变量和应用程序栈空间总是位于系统变量和应用程序栈空间总是位于8051的内部存储区(的内部存储区(DATA或或IDATA区),一般情况下,区),一般情况下,应用程序应使用小(应用程序应使用小(SMALL)模式。)模式。RTX-51 TINY执行协作式任务
18、切换(每个任务至执行协作式任务切换(每个任务至少调用一个操作系统例程)和循环任务切换(每个任少调用一个操作系统例程)和循环任务切换(每个任务在操作系统切换到下一个任务前运行一个固定的时务在操作系统切换到下一个任务前运行一个固定的时间段),不支持抢先式任务切换以及任务优先级。间段),不支持抢先式任务切换以及任务优先级。9.1.3 使用使用RTX-51 TINY的注意事项的注意事项 RTX-51 TINY中的中断、再入函数、指针和寄存器的选择,与中的中断、再入函数、指针和寄存器的选择,与普通的单片机程序也有所区别,这些在使用时都要及时注意。普通的单片机程序也有所区别,这些在使用时都要及时注意。1中
19、断中断RTX-51 TINY与中断函数并行运作,中断服务程序可以通过发与中断函数并行运作,中断服务程序可以通过发送信号(用送信号(用isr_send_signal函数)或设置任务的就序标志函数)或设置任务的就序标志(用(用isr_set_ ready函数)与函数)与RTX-51 TINY的任务进行通信。的任务进行通信。如同在一个标准的、没有如同在一个标准的、没有RTX-51 TINY的应用中一样,中断例的应用中一样,中断例程必须在程必须在RTX-51TINY应用中实现并允许,应用中实现并允许,RTX-51 TINY没有没有中断服务程序的管理。中断服务程序的管理。RTX-51 TINY使用定时器
20、使用定时器0、定时器、定时器0中断和寄存器组中断和寄存器组1。如果。如果在程序中使用了定时器在程序中使用了定时器0,则,则RTX-51 TINY将不能正常运转。将不能正常运转。RTX-51 TINY认为总中断总是允许(认为总中断总是允许(EA=1)。)。RTX-51 TINY库例程在需要时改变中断系统(库例程在需要时改变中断系统(EA)的状态,以确保)的状态,以确保RTX-51 TINY的内部结构不被中断破坏。当允许或禁止总中断时,的内部结构不被中断破坏。当允许或禁止总中断时,RTX-51 TINY只是简单地改变只是简单地改变EA的状态,不保存并重装的状态,不保存并重装EA,EA只是简单地被置
21、位或清除。因此,如果程序在调用只是简单地被置位或清除。因此,如果程序在调用RTX-51例程前禁止了中断,例程前禁止了中断,RTX-51可能会失去响应。可能会失去响应。在程序的临界区,可能需要在短时间内禁止中断。但是,在中在程序的临界区,可能需要在短时间内禁止中断。但是,在中断禁止后,不能调用任何断禁止后,不能调用任何RTX-51 TINY的例程。如果程序确实的例程。如果程序确实需要禁止中断,应该持续很短的时间。需要禁止中断,应该持续很短的时间。1中断中断2再入函数再入函数C51编译器提供对再入函数的支持,再入函数在再入堆栈中存编译器提供对再入函数的支持,再入函数在再入堆栈中存储参数和局部变量,
22、从而保护递归调用或并行调用。储参数和局部变量,从而保护递归调用或并行调用。RTX-51 TINY不支持对不支持对C51再入栈的任何管理。因此,如果在程序中使再入栈的任何管理。因此,如果在程序中使用再入函数,必须确保这此函数不调用任何用再入函数,必须确保这此函数不调用任何RTX-51 TINY系统系统函数,且不被循环任务切换所打断。函数,且不被循环任务切换所打断。仅用寄存器传递参数和保存自动变量的仅用寄存器传递参数和保存自动变量的C函数具有内在的再入函数具有内在的再入性,这些函数可以被不同的性,这些函数可以被不同的RTX-51 TINY任务无限制地调用。任务无限制地调用。非可再入非可再入C51函
23、数不能被超过一个以上的任务或中断过程调用。函数不能被超过一个以上的任务或中断过程调用。非再入非再入C51函数在静态存储区段保存参数和自动变量(局部数函数在静态存储区段保存参数和自动变量(局部数据),该区域在函数被多个任务同时调用或递归调用时可能会据),该区域在函数被多个任务同时调用或递归调用时可能会被修改。被修改。如果确定多个任务不会递归(或同时)调用,则多个任务可以如果确定多个任务不会递归(或同时)调用,则多个任务可以调用非再入函数。通常,这意味着必须禁止循环任务调度,且调用非再入函数。通常,这意味着必须禁止循环任务调度,且该非再入函数不能调用任何该非再入函数不能调用任何RTX-51 TIN
24、Y系统函数。系统函数。3C51库例程库例程可再入可再入C51库函数可在任何任务中无限制地使用。对于非再入的库函数可在任何任务中无限制地使用。对于非再入的C51库函数,用户要保证它们不能同时被几个任务所调用。库函数,用户要保证它们不能同时被几个任务所调用。4多数据指针多数据指针Keil C51编译器允许使用多数据指针(存在于许多编译器允许使用多数据指针(存在于许多80C51的派生的派生芯片中),但芯片中),但RTX-51 TINY不提供对它们的支持。因此,在不提供对它们的支持。因此,在RTX-51 TINY的应用程序中应小心使用多数据指针。的应用程序中应小心使用多数据指针。5运算单元运算单元Ke
25、il C51编译器允许使用运算单元(存在于许多编译器允许使用运算单元(存在于许多8051的派生芯的派生芯片中)。片中)。RTX-51 TINY不提供对它们的支持。因此,在不提供对它们的支持。因此,在RTX-51 TINY的应用程序中须小心使用运算单元。的应用程序中须小心使用运算单元。6寄存器组寄存器组RTX-51 TINY分配所有的任务到寄存器分配所有的任务到寄存器0,因此,所有的函数必,因此,所有的函数必须用须用C51的默认设置进行编译。中断函数可以使用剩余的寄存器的默认设置进行编译。中断函数可以使用剩余的寄存器组。然而,组。然而,RTX-51 TINY需要寄存器组中的需要寄存器组中的6个固
26、定的字节,用个固定的字节,用于这些字节的寄存器组在配置文件于这些字节的寄存器组在配置文件Conf_tny.A51中由中由INT_REGBANK指定。指定。9.2.1 定时器滴答中断定时器滴答中断9.2 RTX-51 TINY的任务管理的任务管理RTX-51 TINY用标准用标准80C51的定时器的定时器0(模式(模式1)生产一个周期性)生产一个周期性的中断。该中断就是的中断。该中断就是RTX-51 TINY的定时滴答(的定时滴答(Timer Tick)。)。库函数中的超时和时间间隔就是基于该定时滴答来测量的。库函数中的超时和时间间隔就是基于该定时滴答来测量的。默认情况下,默认情况下,RTX-5
27、1每每10000个机器周期产生一个滴答中断,因个机器周期产生一个滴答中断,因此,对于运行于此,对于运行于12 MHz的标准的标准8051来说,滴答的周期是来说,滴答的周期是0.01秒秒/10毫秒,也即频率是毫秒,也即频率是100 Hz(12 MHz/12/10000)。该值可以在)。该值可以在Conf_tny.A51配置文件中修改。配置文件中修改。可以在可以在RTX-51的定时滴答中断(定时器的定时滴答中断(定时器0中断)里追加自己的代中断)里追加自己的代码。参见码。参见Conf_tny.A51配置文件。配置文件。9.2.2 任务任务 RTX-51 TINY本质上是一个任务切换器,建立一个本质
28、上是一个任务切换器,建立一个RTX-51 TINY程序,就是建立一个或多个任务函数的应用程序。下面的程序,就是建立一个或多个任务函数的应用程序。下面的信息可以帮助读者快速地理解信息可以帮助读者快速地理解RTX-51。任务函数用关键字任务函数用关键字_task_定义,该关键字是定义,该关键字是Keil C51所支所支持的。持的。RTX-51 TINY维护每个任务的正确状态(运行、就绪、等维护每个任务的正确状态(运行、就绪、等待、删除、超时)。某个时刻只有一个任务处于运行态。任务待、删除、超时)。某个时刻只有一个任务处于运行态。任务可能处于就绪态、等待态、删除态或超时态。空闲任务可能处于就绪态、等
29、待态、删除态或超时态。空闲任务(Idle_Task)总是处于就绪态,当定义的所有任务处于等待状)总是处于就绪态,当定义的所有任务处于等待状态时,运行该任务。态时,运行该任务。9.2.3 任务状态任务状态RTX-51 TINY的用户任务具有一下几个状态的用户任务具有一下几个状态 RUNNING运行运行READY就绪就绪WAITING等待等待DELETED删除删除TIME-OUT超时超时各状态可以进行切换。各状态可以进行切换。9.2.4 事件事件在实时操作系统中,事件可用于控制任务的执行,一个任务在实时操作系统中,事件可用于控制任务的执行,一个任务可能等待一个事件,也可能向其他任务发送任务标志。可
30、能等待一个事件,也可能向其他任务发送任务标志。超时(超时(timeout):挂起运行的任务指定数量的时钟周期。):挂起运行的任务指定数量的时钟周期。间隔(间隔(interval):类似于超时,但是软件定时器没有复位,):类似于超时,但是软件定时器没有复位,典型应用是产生时钟。典型应用是产生时钟。信号(信号(signal):用于任务内部同步协调。):用于任务内部同步协调。os_wait()函数挂起一个任务来等待一个事件的发生。这样函数挂起一个任务来等待一个事件的发生。这样可以同步可以同步2个或几个任务。它的工作过程如下:当任务等待个或几个任务。它的工作过程如下:当任务等待的事件没有发生时,系统挂
31、起这个任务;当事件发生时,系的事件没有发生时,系统挂起这个任务;当事件发生时,系统根据任务切换规则切换任务。统根据任务切换规则切换任务。9.2.5 任务调度任务调度可利用的中央处理器时间被划分成时间片,由可利用的中央处理器时间被划分成时间片,由RTX-51 TINY分分配一个时间片给每个任务。每个任务允许执行一个预先确定的配一个时间片给每个任务。每个任务允许执行一个预先确定的时间,然后,时间,然后,RTX-51 TINY切换到另一个准备运行的任务并且切换到另一个准备运行的任务并且允许这个任务执行片刻。一个时间片的持续时间可以用配置变允许这个任务执行片刻。一个时间片的持续时间可以用配置变量量TI
32、MESHARING定义。即使是在等待一个任务的时间片到达定义。即使是在等待一个任务的时间片到达时,也可以使用时,也可以使用os_wait系统函数通知系统函数通知RTX-51让另一个任务让另一个任务开始执行。开始执行。os_wait中止正在运行的当前任务,然后等待一个中止正在运行的当前任务,然后等待一个指定事件的发生,这时,任意数量的其他任务仍然可以执行。指定事件的发生,这时,任意数量的其他任务仍然可以执行。RTX-51 TINY将处理器分配到一个任务的过程称为调度程序。将处理器分配到一个任务的过程称为调度程序。RTX-51 TINY调度程序定义那些任务按照下面的规则运行。调度程序定义那些任务按
33、照下面的规则运行。如果出现以下情况,当前运行任务中断:如果出现以下情况,当前运行任务中断:1任务调用任务调用os_wait函数并且指定事件没有发生。函数并且指定事件没有发生。2任务运行时间超过定义的时间片轮转超时时间。任务运行时间超过定义的时间片轮转超时时间。如果出现以下情况,则开始另一个任务:如果出现以下情况,则开始另一个任务:1没有其他的任务运行。没有其他的任务运行。2将要开始的任务处于将要开始的任务处于READY或或TIME-OUT状态。状态。9.2.6 任务切换任务切换2种方式种方式1循环任务切换循环任务切换循环法允许并行地执行若干任务。循环法允许并行地执行若干任务。int count
34、er0;int counter1;void job0(void)_task_ 0os_create(1);/*标记任务标记任务1为就绪为就绪*/while(1)/*无限循环无限循环*/counter0+;/*更新记数器更新记数器*/void job1(void)_task_1while(1)/*无限循环无限循环*/counter+;/*更新记数器更新记数器*/例:例:2协作任务切换协作任务切换可以用可以用os_wait 或或os_switch_task让让RTX-51 TINY切换到另切换到另一个任务而不是等待任务的时间片用完。一个任务而不是等待任务的时间片用完。#include /*RTX-
35、51 tiny functions&defines*/int counter0;/*任务任务0的计数器的计数器 */int counter1;/*任务任务1的计数器的计数器 */job0()_task_ 0 os_create_task(1);/*启动任务启动任务1 */while(1)/*无穷循环无穷循环 */counter0+;/*counter0加加1 */os_wait(K_TMO,5,0);/*等待超时信号等待超时信号:5个滴答超时个滴答超时*/job1()_task_ 1 while(1)/*无穷循环无穷循环 */counter1+;/*counter1加加1 */os_wait(
36、K_TMO,10,0);/*等待超时信号等待超时信号:10个滴答超时个滴答超时*/os_wait例例1:#include /*RTX-51 tiny functions&defines*/int counter0;/*任务任务0的计数器的计数器 */int counter1;/*任务任务1的计数器的计数器 */int counter2;/*任务任务2的计数器的计数器 */int counter3;/*任务任务3的计数器的计数器 */job0()_task_ 0 os_create_task(1);/*启动任务启动任务1 */os_create_task(2);/*启动任务启动任务2 */os_
37、create_task(3);/*启动任务启动任务3 */while(1)/*无穷循环无穷循环 */counter0+;/*counter0加加1 */os_wait(K_TMO,5,0);/*等待超时信号等待超时信号:5个时钟报时个时钟报时*/job1()_task_ 1 while(1)/*无穷循环无穷循环 */counter1+;/*counter1加加1 */os_wait(K_TMO,10,0);/*等待超时信号等待超时信号:10个时钟报时个时钟报时*/os_wait例例2:job2()_task_ 2 while(1)/*无穷循环无穷循环 */counter2+;/*counter
38、2加加1 */if(counter2&0 xFFFF)=0)/*如果如果counter2=0*/os_send_signal(3);/*发信号至任务发信号至任务3 */job3()_task_ 3 while(1)/*无穷循环无穷循环 */os_wait(K_SIG,0,0);/*等待信号等待信号 */counter3+;/*收到信号后,收到信号后,counter3加加1*/os_wait例例2续:续:3空闲任务空闲任务没有任务准备运行时,没有任务准备运行时,RTX-51 TINY执行一个空闲任务。空闲执行一个空闲任务。空闲任务就是一个无限循环。任务就是一个无限循环。例如例如SJMP$有些有些
39、8051兼容的芯片提供一种降低功耗的空闲模式,该模式停兼容的芯片提供一种降低功耗的空闲模式,该模式停止程序的执行,直到有中断产生。在该模式下,所有的外设包止程序的执行,直到有中断产生。在该模式下,所有的外设包括中断系统仍在运行。括中断系统仍在运行。RTX-51 TINY允许在空闲任务中启动空闲模式(在没有任务准允许在空闲任务中启动空闲模式(在没有任务准备执行时)。当备执行时)。当RTX-51 TINY的定时滴答中断(或其他中断)的定时滴答中断(或其他中断)产生时,微控制器恢复程序的执行。产生时,微控制器恢复程序的执行。空闲任务执行的代码在空闲任务执行的代码在Conf_tny.A51配置文件中允
40、许和配置。配置文件中允许和配置。9.3 如何使用如何使用RTX-51 TINY9.3.1 编写程序编写程序使用使用RTX-51 TINY要实现下面三步:要实现下面三步:(1)编写)编写RTX-51程序程序(2)编译并连接程序)编译并连接程序(3)测试和调试程序)测试和调试程序1包含文件包含文件RTX-51 TINY仅需要包含一个文件仅需要包含一个文件RTX-51TNY.H,所有的库,所有的库函数和常数都在该头文件中定义。在建立多任务模块的源文函数和常数都在该头文件中定义。在建立多任务模块的源文件中要包含:件中要包含:#include2编程原则编程原则(1)确保包含了)确保包含了RTX-51TN
41、Y.H头文件。头文件。(2)不要建立)不要建立main()函数,函数,RTX-51 TINY有自己的有自己的main()函函数。它会自动地从任务数。它会自动地从任务0开始运行。如果用户程序中包含有开始运行。如果用户程序中包含有main()函数,则需要利用函数,则需要利用os_create_task函数来启动函数来启动RTX-51实时操作系统。实时操作系统。(3)程序必须至少包含一个任务函数。)程序必须至少包含一个任务函数。(4)中断必须有效()中断必须有效(EA=1),在临界区,如果要禁止中断时),在临界区,如果要禁止中断时一定要小心。一定要小心。(5)程序必须至少调用一个)程序必须至少调用一
42、个RTX-51 TINY库函数(像库函数(像os_wait)。否则,连接时将不包含)。否则,连接时将不包含RTX-51 TINY库。库。(6)Task 0是程序中首先要执行的函数,必须在任务是程序中首先要执行的函数,必须在任务0中调用中调用os_create_task 函数以启动其他任务。函数以启动其他任务。(7)任务函数必须是从不退出或返回的。任务必须用一个)任务函数必须是从不退出或返回的。任务必须用一个while(1)或类似的结构重复。用或类似的结构重复。用os_delete_task函数停止运行函数停止运行的任务。的任务。(8)必须在)必须在Vision2中设置使用操作系统中设置使用操作
43、系统RTX-51 TINY,或,或者在连接器命令行中指定。者在连接器命令行中指定。实时或多任务应用是由一个或多个执行具体操作的任务组成的,实时或多任务应用是由一个或多个执行具体操作的任务组成的,RTX-51 TINY支持最多支持最多16个任务。个任务。3定义任务定义任务任务就是一个简单的任务就是一个简单的C函数,返回类型为函数,返回类型为void,参数列表为,参数列表为void,并且用并且用_task_声明函数属性。声明函数属性。例例:1:void func(void)_task_ task_id例例2:Void job0(void)_task_ 0 while(1)counter0+;9.3
44、.2 编译和连接编译和连接用用Vision2 IDE建立工程,添加建立工程,添加RTX-51 TINY程序文件。程序文件。(1)打开如图所示的目标对话框选项(从)打开如图所示的目标对话框选项(从project菜单中选菜单中选择择Options for Target)。)。(2)选择)选择Target标签。标签。(3)从)从Operating选项列表中选择选项列表中选择RTX-51 TINY,使用操,使用操作系统。作系统。其他设置同非其他设置同非RTX-51 TINY一致。一致。9.3.3 调试调试Vision2模拟器允许运行和测试模拟器允许运行和测试RTX-51 TINY应用程序。应用程序。R
45、TX-51 TINY程序的加载和非程序的加载和非RTX-51 TINY程序的加载是一样的。无须指程序的加载是一样的。无须指定特别的命令和选项。定特别的命令和选项。启动调试后,一个核心的对话框显示启动调试后,一个核心的对话框显示RTX-51 TINY核心和程序中核心和程序中任务的所有特征。从任务的所有特征。从Peripherals菜单中选择菜单中选择RTX-51 TINY Tasklist显示该对话框显示该对话框9.3.4 实例实例os_wait函数的使用函数的使用例例9.1如图如图9.4所示,假设在所示,假设在AT89C52的的P1口接有口接有8个个LED,使用使用RTX-51 TINY,编写
46、程序,编写程序使使8个个LED以不同的频率闪烁。以不同的频率闪烁。分析:需要建立分析:需要建立9个任务,个任务,初始化任务和初始化任务和8个个LED闪烁闪烁任务,在初始化任务中建任务,在初始化任务中建立立8个个LED闪烁任务,之后闪烁任务,之后删除自身。使用删除自身。使用os_wait函函数等待超时进行任务切换,数等待超时进行任务切换,修改修改Conf_tny.A51中的中的TIMESHARING禁止循环禁止循环人为切换人为切换9.4 RTX-51 TINY提供的系统函数提供的系统函数1isr_send_signal 概要:概要:#includechar isr_send_signal(uns
47、igned char task_id);/*信号发往的任务信号发往的任务*/描述:描述:isr_send_signal函数给任务函数给任务task_id发送一个信号。如果发送一个信号。如果指定的任务正在等待一个信号,则该函数使该任务就绪,但不启指定的任务正在等待一个信号,则该函数使该任务就绪,但不启动它,信号存储在任务的信号标志中。该函数仅被中断函数调用。动它,信号存储在任务的信号标志中。该函数仅被中断函数调用。返回值:成功调用后返回返回值:成功调用后返回0,如果指定任务不存在,则返回,如果指定任务不存在,则返回-1。例:例:#include void tst_isr_send_signal(
48、void)interrupt 2 isr_send_signal(6);/*给任务给任务6发信号发信号*/2isr_set_ready概要:概要:#include char isr_set_ready unsigned char task_id;/*使就使就绪的任务绪的任务*/描述:将由描述:将由task_id指定的任务置为就绪态。该函数仅被中断函指定的任务置为就绪态。该函数仅被中断函数调用。数调用。返回值:无。返回值:无。例:例:#include void tst_isr_set_ready(void)interrupt 2 isr_set_ready(1);/*置位任务置位任务1的就绪标志
49、的就绪标志*/3os_clear_signal概要:概要:#include char os_clesr_signal(unsigned cahr task_id);/*清除信号清除信号的任务的任务*/描述:清除由描述:清除由task_id指定的任务信号标志。指定的任务信号标志。返回值:信号成功清除后返回返回值:信号成功清除后返回0,指定的任务不存在时返回,指定的任务不存在时返回-1。参阅:参阅:isr_send_signal,os_send_signal,os_wait例:例:#include void tst_os_clsar_siganl(void)_task_8 os_clear_sig
50、nal(5);/*清除任务清除任务5的信号标志的信号标志*/4os_create_task概要:概要:#include char os_create_task(unsigned char task_id);/*要启动要启动的任务的任务ID*/描述:启动任务描述:启动任务task_id,该任务被标记为就绪,并在下一个,该任务被标记为就绪,并在下一个时间点开始执行。时间点开始执行。返回值:任务成功启动后返回返回值:任务成功启动后返回0,如果任务不能启动或任务已,如果任务不能启动或任务已在运行,或没有以在运行,或没有以task_id定义的任务,返回定义的任务,返回-1。参阅:参阅:os_delete