第二章实时程序实时程序必须对实时发生的事件快速响应。事件很少的程序不用实时操作系统也很容易实现。随着事件的增加,编程的复杂程度和难度也随之增大,这正是RTOS的用武之地。一、单任务程序嵌入式程序和标准C程序都是从main函数开始执行的,在嵌入式应用中,main通常是一个无限循环,可以认为是一个持续执行的单个任务,例如:voidmain(void)﹛while(1)/*永远重复*/﹛do_something();/*执行do_something“任务”*/﹜﹜在这个例子里,do_something函数可以认为是一个单任务,由于仅有一个任务在执行,所以没有必要进行多任务处理或使用多任务操作系统。二、多任务程序许多C程序通过在一个循环里调用服务函数(或任务)来实现伪多任务调度。如:voidmain(void)﹛intcounter=0;while(1)/*一直重复执行*/﹛check_serial_io();/*检查串行输入*/process_serial_cmds();/*处理串行输入*/check_kbd_io();/*检查键盘输入*/process_kbd_cmds();/*处理键盘输入*/adjust|ctrlr_parms();/*调整控制器*/counter++;/*增加计数器*/﹜﹜该例中,每个函数执行一个单独的操作或任务,函数(或任务)按次序依次执行。当任务越来越多,调度问题就被自然而然的提出来了。例如,如果process_kbd_cmds函数执行时间较长,主循环就可能需要较长的时间才能返回来执行check_sericd_io函数,导致串行数据可能被丢失。当然,可以在主循环中更频繁的调用check_serial_io函数以纠正这个问题,但最终这个方法还是会失效三、RTX51Tiny程序当使用Rtx51Tiny时,为每个任务建立独立的任务函数,例如:voidcheck_serial_io_task(void)_task_1﹛/*该任务检测串行I/0*/﹜voidprocess_serial_cmds_task(void)_task_2﹛/*该任务处理串行命令*/﹜voidcheck_kbd_io_task(void)_task_3﹛/*该任务检测键盘I/O*/﹜voidprocess_kbd_cmds_task(void)_task_4﹛/*处理键盘命令*/﹜voidstartup-_task(void)_task_0﹛os_create_task(1);/*建立串行I/O任务*/os_create_task(2);/*建立串行命令任务*/os_create_task(3);/*建立键盘I/O任务*/os_create_task(4);/*建立键盘命令任务*/os_delete_task(0);/*删除启动任务*/﹜该例中,每个函数定义为一个RTX51Tiny任务。RTX51Tiny程序不需要main函数,取而代之,RTX51Tiny从任务0开始执行。在典型的应用中,任务0简单的建立所有其他的任务。第三章原理RTX51Tiny用于管理目标系统的资源,本章讨论RTX51Tiny如何使用这些资源。一、定时器滴答中断RTX51Tiny用标准8051的定时器0(模式1)生产一个周期性的中断。该中断就是RTX51Tiny的定时滴答(TimerTick)。库函数中的超时和时间间隔就是基于该定时滴答来测量的。默认情况下,RTX51每10000个机器周期产生一个滴答中断,因此,对于运行于12MHZ的标准8051来说,滴答的周期是0.01秒,也即频率是100HZ(12MHz/12/10000)。该值可以在CONF_TNY.A51配置文件中修改。附注:l可以在RTX51的定时滴答中断里追加自己的代码。参见CONF_TNY.A51配置文件。l关于RTX51Tiny如何使用中断可以参考概述中中断一节的叙述。二、任务RTX51Tiny本质上是一个任务切换器,建立一个RTX51Tiny程序,就是建立一个或多个任务函数的应用程序。下面的信息可以帮助你快速的理解RTX51。l任务用新的关键字由C语言定义,该关键字是KeicC51所支持的。lRTX51Tiny维护每个任务的正确状态(运行、就绪、等待、删除、超时)。l某个时刻只有一个任务处于运行态。l任务可能处于就绪态、等待态、删除态或超时态。l空闲任务(Idle_Task)总是处于就绪态,当定义的所有任务处于阻塞状态时,运行该任务。三、任务管理每个RTX51Tiny任务总是处于下述状态中的一种状态中。状态描述运行正在运行的任务处于运行态。某个时刻只能有一个任务处于该状态。os_running_task_id函数返回当前正在运行的任务编号。就绪准备运行的任务处于就绪态。一旦运行的任务完成了处理,RTX51Tiny选择一个就绪的任务执行。一个任务可以通过用os_set_ready或os_set_ready函数设置就绪标志来使其立即就绪(即便该任务正在等待超时或信号)。等待正在等待一个事件的任务处于等待态。一旦事件发生,任务切换到就绪态。Os_wait函数用于将一个任务置为等待态。删除没有被启动或已被删除的任务处于删除态。Os-delete-task函数将一个已经启动(用os_create_task)的任务置为删除态。超时被超时循环中断的任务处于超时态,在循环任务程序中,该状态相当于就绪态。四、事件在实时操作系统中,事件可用于控制任务的执行,一个任务可能等待一个事件,也可能向其他任务发送任务标志。os_wait函数可以使一个任务等待一个或多个事件。l超时是一个任务可以等待的公共事件。超时就是一些时钟滴答数,当一个任务等待超时时,其他任务可以执行。一旦到达指定数量的滴答数,任务就可以继续执行。l时间间隔(Interval)是一个超时(Timeout)的变种。时间间隔与超时类似,不同的是时间间隔是相对于任务上次调用os_wait函数的指定数量的时钟滴答数。l信号是任务间通信的方式。一个任务可以等待其他任务给它发信号(用os_send_signal和isr_send_signal函数)。l每个任务都有一个可被其它任务设置的就绪标志(用os_set_ready和isr_set_ready函数)。一个个等待超时、时间间隔或信号的任务可以通过设置它的就绪标志来启动。lisr_set_ready函数)。一个等待超时、时间间隔或信号的任务可以通过设置它的就绪标志来启动。下表是os_wait函数等待的事件:os-wait返回时,返回值表明发生了的事件:os_wait可以等待下面的事件组合:lK_SIG︱K_TMO:任务延迟直到有信号发给它或者指定数量的时钟滴答到达。lK_SIG︱K_IVL:任务延迟直到有信号到来或者指定的时间间隔到达。附注:K_IVL等待制定的时间隔K_SIG等待一个信号K_TMO等待指定的超时返回值意义RDY_EVENT任务的就绪标志被置位SIG_EVENT收到一个信号TMO_EVENT超时完成或时间间隔到达。lK_IVL和K_TMO事件不能组合五、任务调度程序:任务调度程序给任务分配处理器,RTX51Tiny调度程序用下列规则确定哪个任务要被运行:当前任务被中断如果:1、任务调用了os_switch_task且另一个任务正准备运行。2、任务调用了os_wait且指定的事件没有发生。3、任务执行了比轮转时间片更长的时间。另一个任务启动如果:1、无其它任务运行。2、要启动的任务处于就绪态或超时态。六、循环任务切换RTX51Tiny可以配置为用循环法进行多任务处理(任务切换)。循环法允许并行的执行若干任务。任务并非真的同时执行,而是分时间片执行的(CPU时间分成时间片,RTX51Tiny给每个任务分配一个时间片)。由于时间片很短(几毫秒),看起来好象任务在同时执行。任务在它的时间片内持续执行(除非任务的时间片用完)。然后,RTX51Ting切换到下一个就绪的任务运运行。时间片的持续时间可以通过RTX51Ting配置定义。下面是一个RTX51Tiny程序的例子,用循环法多任务处理,程序中的两个任务是计数器循环。RTX51Tiny在启动时执行函数名为job0的任务0,该函数建立了另一个任务job1,在job0执行完它的时间片后,RTX51Tiny切换到job1。在job1执行完它的时间片后,RTX51Ting又切换到job0,该过程无限重复。#includeintcounter0;intcounter1;voidjob0(void)_task_0﹛os_create(1);/*标记任务1为就绪*/while(1)﹛/*无限循环*/counter0++;/*更新记数器*/}}voidjob1(void)_task_1﹛while(1)﹛/*无限循环*/counter++;/*更新记数器*/}}附注:l可以用os_wait或os_switch_task让RTX51Tiny切换到另一个任务而不是等待任务的时间片用完。os_wait函数挂起当前的任务(使之变为等待态)直到指定的事件发生(接着任务变为就绪态)。在此期间,任意数量的其他任务可以运行。七、协作任务切换如果禁止了循环任务处理,就必须让任务以协作的方式运作,在每个任务里调用os_wait或os_switch_task,以通知RTX51Tingy切换到另一个任务。os_wait与os_switch_task的不同是,os_wait是让任务等待一个事件,而os_switch_task是立即切换到另一个就绪的任务。八、空闲任务没有任务准备运行时,RTX51Ting执行一个空闲任务。空闲任务就是一个无限循环。如:SJMP$有些8051兼容的芯片提供一种降低功耗的空闲模式,该模式停止程序的执行,直到有中断产生。在该模式下,所有的外设包括中断系统仍在运行。RTX51Tiny允许在空闲任务中启动空闲模式(在没有任务准备执行时)。当RTX51Tiny的定时滴答中断(或其它中断)产生时,微控制器恢复程序的执行。空闲任务执行的代码在CONF_TNY.A51配置文件中允许和配置。九、栈管理RTX51Tiny为每个任务在8051的内部RAM区(IDATA)维护一个栈。任务运行时,将得到可能得到的最大数量的栈空间。任务切换时,先前的任务栈被压缩并重置,当前任务的栈被扩展和重置。下图表明一个三任务应用的内部存储器的布局。图略……:-)?STACK表示栈的起始地址。该例中,位于栈下方的对象包括全局变量、寄存器和位寻址存储器,剩余的存储器用于任务栈。存储器的顶部可在配置中指定。第四章RTX51Tiny配置RTX51Tiny可根据应用的不同定制。一、配置建立了嵌入式应用后,RTX51Tiny必须要配置。所有的配置设置都在CONF_TNY.A51文件中,该文件位于\KEIL\CS1\RTXTINY2\目录下。在CONF_TNY.A51中的配置选项允许:l指定滴答中断寄存器组。l指定滴答间隔(以8051机器周期为单位)。l指定在滴答中断中执行的代理。l指定循环超时。l允许或禁止循环任务切换。l指定应用程序占用长时间的中断。l指定是否使用codebanking。l定义RTX51Tiny的栈项。l指定最小的栈空间需求。l指定栈错误发生时要执行的代码。l定义栈错误发生时要执行的代码。l定义空闲任务操作。CONF_TNY.A51的默认配置包含在RTX51Tiny库中。但是,为了保证配置的有效和正确,须得将CONF_TNY.A51文件拷贝到工程目录下并将其加入列工程中。通过改变CONF_TNY.A51中的设置来定制RTX51Tiny的配置。附注:l如果在工程中没有包含配置文件(CONF_TNY.A51),库中的默认配置将自动加载,后续的改变将存储在库中,这样可能会对以后的应用起到不良影响。1、硬件定时器下面的常数指定RTX51Tiny的硬件定时器如何配置。lINT_REGBANK指定用于定时器中断的寄存器组,默认为1(寄存器组1)。lINT_CLOCK指定定时器产生中断前的指令周期数。该值用于