1.简介
RTX51 Tiny是一个实时操作系统(RTOS),允许创建应用程序,同时执行多个功能或任务。这在嵌入式应用程序中是经常需要的。虽然可以在没有RTOS的情况下创建实时程序(通过在循环中执行一个或多个函数或任务),但是像RTX51 Tiny这样的RTOS可以解决许多调度、维护和计时问题。实时操作系统(real-time operating system, RTOS)可以灵活地调度CPU、内存等系统资源,并提供任务之间的通信。RTX51 Tiny是一个功能强大的RTOS,易于使用,并可以与所有8051衍生品一起配合使用。
RTX51的基本程序是用标准C结构编写,用Keil C51 C编译器编译的。C语言的补充允许我们可以轻松地声明任务函数,而不需要复杂的堆栈和变量框架配置。RTX51微型程序只需要包含一个特殊的头文件(#include <rtx51tny.h>),并将RTX51微型库连接到我们的程序中。
2.运行原理
因为RTX51 Tiny使用和管理目标系统的资源,所以RTX51 Tiny的许在多方面可以项目的基础上进行配置。
1.时钟中断
RTX51 Tiny使用标准的8051 Timer 0(模式1)来产生周期性中断。这个中断是RTX51 Tiny Timer Tick。为RTX51 Tiny库例程指定的超时和间隔值是使用RTX51 Tiny Timer Tick来测量的。默认情况下,RTX51 Timer Tick中断每10,000个机器周期发生一次。因此,对于运行在12MHz的标准8051,定时器的周期是0.01秒或频率为100Hz (12MHz / 12 / 10,000)。可以在CONF_TNY.A51中修改相应的配置文件。也可以将我们自己的代码附加到RTX51定时器中断CONF_TNY.A51配置文件中以实现自定义。
2.任务
RTX51 Tiny基本上是一个任务切换器。要创建RTX51 Tiny程序,必须创建一个具有一个或多个任务函数的应用程序。接下来将对此进行详细的讲解,但有以下基本概念:
任务是在C编程语言中使用Keil C51编译器支持的新关键字定义的。
RTX51 Tiny将每个任务保持在一个状态(运行、就绪、等待、删除或超时)。
一次只能有一个任务处于“运行状态”。
许多任务可能处于就绪、等待、删除或超时状态。
Idle Task总是准备好在所有定义的任务都被阻塞的情况下运行。
3.任务状态
运行(RUNNING)
当前正在运行的任务处于“running State”状态。一次只能有一个任务处于此状态。os_running_task_id返回当前执行任务的任务号。
就绪(READY)
准备运行的任务处于ready状态。一旦Running任务完成处理,RTX51 Tiny选择并启动下一个Ready任务。可以通过使用os_set_ready或isr_set_ready函数设置就绪标志,使任务立即就绪(也就是使任务正在等待超时或信号)。
等待(WAITING)
等待事件发生的任务处于等待状态。事件发生后,任务切换到READY状态。os_wait功能用于将任务置于等待状态。
删除(DELETED)
未启动或已删除的任务处于“已删除状态”。os_delete_task例程将已启动的任务(使用os_create_task)置于DELETED State。
超时(TIME-OUT)
被Round-Robin Time-Out中断的任务将处于“Time-Out”状态。这个状态相当于轮询程序的READY状态
4.事件
实时操作系统中的事件可以用来控制程序中任务的执行。任务可以等待事件,也可以为其他任务设置事件标志。
os_wait函数允许任务等待一个或多个事件,但还有以下细节
Timeout是任务可以等待的常见事件。超时仅仅是时钟的次数。当一个任务等待超时时,其他任务可能会执行。一旦指定的计时器数过去,任务就可以继续执行。
Interval可以说是Timeout的变体。间隔类似于超时,不同之处在于指定的时钟周期数与任务上次调用os_wait函数的时间有关。Interval可用于生成一个任务,该任务按照常规的同步计划(比如每秒钟运行一次)运行,而不管调用os_wait函数的时间间隔是多少。如果已经过了指定的时钟节拍数(因为上次调用了os_wait函数),则立即重新启动任务——不执行其他任务。
Signal是任务间通信的一种简单形式。任务可以等待另一个任务发送信号(使用os_send_signal和isr_send_signal函数)。
每个任务都有一个Ready标志,可以由其他任务设置(使用os_set_ready和isr_set_ready函数)。一个正在等待超时、间隔或信号的任务可以通过设置其ready标志来启动。
每个事件都有一个由RTX51 Tiny维护的相关事件标志。以下事件选择器可以与os_wait函数一起使用,以指定要等待的内容:
事件选择器 | 简述 |
K_IVL | 等待指定的时间Interval |
K_SIG | 等待一个Signal |
K_TMO | 等待指定的Time-out |
当os_wait函数返回时,发生的事件由返回值指定:
返回值 | 简述 |
RDY_EVENT | 任务被设成READY标志 |
SIG_EVENT | 接收到一个Signal |
TMO_EVENT | Time-out完成或Interval已过去 |
os_wait函数可以等待以下事件组合:
K_SIG | K_TMO: os_wait将延迟任务,直到向其发送信号或经过指定的时钟周期。
K_SIG | K_IVL: os_wait将延迟任务,直到向其发送信号或经过指定的时间间隔。
其中还要非常注意K_IVL和K_TMO事件选择器不能组合使用。
5.任务调度
任务调度器将处理器分配给一个任务。RTX51微型调度器使用以下规则来决定运行哪个任务:
当出现以下情况时,当前任务中断:
1.任务调用os_switch_task,另一个任务准备好运行了。
2.任务调用os_wait函数,而指定的事件没有发生。
3.任务的执行时间超过了定义的轮询时间片。
当出现以下情况时,另一个任务将运行:
1.没有其他任务正在运行。
2.待启动的任务处于“READY”或“TIME-OUT”状态。
6.轮询任务切换
RTX51 Tiny可以被配置为使用轮循多任务(或任务切换)。Round-Robin允许多个任务的准并行执行。任务实际上并不是并发执行的,而是按时间划分的(可用的CPU时间被划分为多个时间片,RTX51 Tiny为每个任务分配了一个时间片)。因为时间片很短(只有几毫秒),所以看起来好像任务是同时执行的。
任务在它们的时间片期间执行(除非任务的时间片被放弃)。然后,RTX51 Tiny切换到下一个准备运行的任务。一个时间片的持续时间可以由RTX51 Tiny Configuration定义。
下面的例子展示了一个简单的RTX51 Tiny程序,它使用了轮询多任务处理。这个程序中的两个任务是计数器循环。RTX51 Tiny开始执行task 0,即名为job0的函数。这个函数创建另一个名为job1的任务。在它的时间片执行job0之后,RTX51 Tiny切换到job1。在为它的时间片执行job1之后,RTX51 Tiny切换回job0。这个过程是无限重复的。
#include <rtx51tny.h>
int count0;
int count1;
void job0 (void) _task_0
{
os_create(1); /*标志task1已就绪*/
while(1)
{
count0++;
}
}
void job1 (void) _task_1
{
while(1)
{
count1++;
}
}
我们可以使用os_wait函数或os_switch_task函数来允许RTX51 Tiny切换到另一个任务,而不是等待任务的时间片过期。os_wait函数会暂停当前任务(将当前任务状态变为WAITING状态),直到发生指定的事件(任务状态变为READY状态)。在此期间,可以运行任意数量的其他任务。
7.联合任务切换
如果禁用Round-Robin多任务,则必须设计和实现任务,使它们能够协同工作。具体来说,必须在每个任务中调用os_wait函数或os_switch_task函数。这些功能信号RTX51微小切换到另一个任务。
os_wait和os_switch_task的区别在于,os_wait允许您的任务等待某个事件,而os_switch_task会立即切换到另一个就绪的任务。
8.空闲任务
当没有任务准备运行时,RTX51 Tiny会执行一个空闲任务。空闲任务只是一个无尽的循环。例如:
JMP $
一些8051兼容的设备提供空闲模式,通过暂停程序执行直到中断发生来降低功耗。在这种模式下,所有外设包括中断系统仍然继续运行。
RTX51 Tiny允许你在空闲任务中启动空闲模式(当没有其他任务准备好执行时)。当RTX51小定时器滴答中断(或任何其他中断)发生时,微控制器恢复程序执行。Idle Task执行的代码可以在CONF_TNY.A51配置文件中启用和配置。
9.堆栈管理
RTX51 Tiny仅使用8051的内部内存(IDATA)为每个任务维护一个堆栈。当一个任务正在运行时,它会被赋予尽可能多的堆栈空间。当任务切换发生时,前一个任务堆栈会收缩并重新定位,当前任务的堆栈则会扩展并重新定位。
下图演示了带有三个独立任务的示例应用程序的内部内存布局
STACK符号表示堆栈的起始地址。在这个例子中,位于堆栈下面的对象包括全局变量、寄存器和可位寻址内存。剩余的内存用于任务堆栈。内存的顶部可以在配置中指定。
3.具体配置
RTX51 Tiny必须为创建的嵌入式应用程序配置。所有的配置设置都可以在CONF_TNY中找到。A51文件位于\KEIL软件安装目录\C51\RTXTINY\文件夹中。CONF_TNY中的配置选项A51允许:
*指定定时器中断寄存器。
*指定定时器间隔(以8051机器周期为单位)。
*指定在定时器中断中执行的用户代码。
*指定轮询超时时间。
*启用/禁用轮询任务切换功能。
*指定应用程序包含长时间中断。
*指定是否使用代码分体。
*定义RTX51微型堆栈的顶部。
*指定所需的最小堆栈空间。
*指定发生堆栈错误时要执行的代码。
*定义空闲任务操作。
CONF_TNY的默认配置。A51包含在RTX51微型库中。但是,要保证应用程序使用的配置,必须复制CONF_TNY.A51文件到我们的项目文件夹,并将其添加到我们的项目。如果我们的项目中没有包含配置文件(CONF_TNY.A51),则会自动包含库中的默认配置文件。对存储在库中的配置文件的后续更改可能会对应用程序的操作产生不利影响。
1.硬件定时器
下面的EQUates指定如何配置RTX51微型硬件定时器
INT_REGBANK指定RTX51 Tiny Timer Interrupt使用的寄存器组。默认设置为1(对于寄存器bank1)
INT_CLOCK指定定时器产生中断之前的周期数。取值范围为1000 ~ 65535。小数目产生更快的中断。这个数字用于计算计时器的重新加载值(65536-INT_CLOCK)。默认设置为10000。
HW_TIMER_CODE是一个宏,指令代码在RTX51小定时器中断结束时执行。这个宏的默认设置是从中断(RETI)返回。
2.轮询任务切换
系统默认开启轮询任务切换功能。通过以下等效参数,可以配置轮询任务切换时间或完全禁用轮询。
TIMESHARING指定在轮询任务切换前,每个任务运行的RTX51 Tiny timer数。取值为0时,禁用轮询任务切换。默认设置为5个计时滴答。
3.中断
通常,中断服务程序(isr)被设计为快速执行。在某些情况下,我们的isr可能会执行很长一段时间。如果一个高优先级的ISR执行时间超