Real-Time Executive (REX) 使用手册
第一章 序言
1.1 目的
本文描述了基于 ARM 平台的 Real-Time Executive ( REX )操作系统特性及使用方法。
REX 是专为小型嵌入式系统设计的简单高效的抢占式多任务实时操作系统( RTOS )。该系统最初是为 Intel80186 处理器设计的,随后被移植到 ARM 处理器。本文提供了 REX 的指南,第 7 章为编程参考。
1.2 适用范围
本手册适用于需要在 REX 系统上编写应用程序的读者。
1.3 内容组织
本文按以下结构编写:
n 第 2 章 REX 概述
n 第 3-6 章 REX 的详细叙述及内部工作机制
n 第 7 章 编程指南
1.4 字形习惯
函数声明,函数名,类型声明,示例代码使用特殊的字体,例如: #include
程序变量用尖括号包围,例如 <number>
1.5 版本历史
版本 | 日期 | 说明 |
| 1999 年 1 月 | 初始版本 |
Rev.A | 1999 年 3 月 | 内容更新 |
Rev.B | 2001 年 6 月 | 删除了与 80186 有关的部分,更新了 REX 的 API ,更新了中断处理的章节 |
Rev.C | 2001 年 9 月 | 删除了成型信息 |
1.6 参考资料
1 | REX Portation Guide | 80-24880-1 X1 | 1999 年 3 月 |
2 | REX++ REX Extensions Users Guide | 80-V3083-1 X1 | 2001 年 4 月 |
1.7 技术支持
如需要求了解本文未详细说明的信息可通过高通的 CDMA 技术支持邮箱联系:
1.8 术语及习惯用语
本文使用以下术语及习惯用语
APCS ARM 调用规范。为了支持不同厂家编译系统及汇编语言混合编程, ARM 规定了程序调用的入口、出口处理及寄存器的使用规范。
API 应用程序接口。
ARM Advanced RISC Machines Limited , ARM 系列处理器制造商,通常也指 ARM 系列微处理器。
ARM7TDMI ARM7 系列处理器中的一款。
CPSR 当前程序状态寄存器,该寄存器保存了旗语,中断控制位和处理器当前操作模式。
critical section 临界区,代码中访问共享资源的部分。
FIQ 快速中断,由 ARM 支持的中断之一, FIQ 中断服务程序正在进行时也可用来标志处理器工作模式。
IRQ 普通中断,由 ARM 支持的中断之一, IRQ 中断服务程序正在进行时也可用来标志处理器工作模式。
ISR 中断服务程序,也称为 interrupt trampoline function 。
Idle Task 操作系统中的优先级最低的任务,空闲任务的优先级为 0 ,为一个空等待循环,只能由中断抢夺其 CPU 控制权。
PC 程序当前指令寄存器
PSR 程序状态寄存器
REX 高通的实时操作系统
RTOS 实时操作系统
SPSR 受保护的程序状态寄存器,每一个处理器模式提供一个 SPSR 用以保存处理器切换到其它模式前的 CPSR 。
TCB 任务控制块, REX 内部的数据结构,用于存放任务的信息。
timer block 定时器的别名。
trampoline function REX 之外的中断服务函数,同 ISR 。
第二章 REX 概述
REX 是一个抢先的多任务实时操作系统,为任务的控制,同步,互斥,定时和中断控制提供了相应的 API ,所有的函数在调用它们的任务提供的设备环境下运行。
2.1 任务
REX 将每个任务视为独立的实体句柄,有独享的堆栈和优先级并共同组成任务的设备环境,每个任务有一组数据组成的结构,称为任务控制块( TCB ), REX 通过任务控制块记录任务运行的设备环境。
REX 运行期间允许在任何时候动态创建任意数量的任务,尽管更多的任务造成了遍历任务链表的时间延长,但新增任务对 REX 性能造成的损失是微乎其微的。不过仍要注意尽量使任务的数量保持最小。
REX 所能负担的任务最终取决于处理器种类,时钟速率以及特定应用下的中断响应指标。
2.2 堆栈
前一节提到过每个任务有独立的堆栈空间,任务处于运行状态时,该堆栈被激活,当任务挂起时,任务的设备环境被保存于堆栈顶部,堆栈指针则存放于该任务的 TCB 中。任务可能由于阻塞,等待信号量,等待中断服务而挂起。
如果任务被重新激活到运行状态,调度程序从 TCB 中恢复堆栈指针,任务的设备环境就可从堆栈中弹出,任务即可恢复运行。任务调度处理对于任务来讲是透明的。
2.3 优先级和调度
每一个任务都有一个优先级,优先级存放于任务的 TCB 中,优先级可以是任何的非零的 32 位数,数值越小则优先级越低, REX 占用了优先级 0 用于空闲任务,旧版本的 REX 要求每个任务独占优先级,新的版本已经没有这个限制了。
REX 的调度策略为放行优先级最高的就绪态任务,即激活不等待任何事件的最高优先级任务。如果满足条件的同优先级任务不只一个,则 REX 会任选其中的一个任务。被激活的任务会一直运行到主动挂起或中断程序使另一个更高优先级的任务恢复运行。
一个任务等待的事件到达后,该任务进入就绪态,如果所有的任务都处于挂起状态,则空闲任务被激活。
REX 支持任务动态修改优先级,一个任务可以提升或降低自己或其他任务的优先级。
2.4 中断
REX 为抢占式内核,当中断返回时,控制会交给优先级最高的就绪任务而不是被中断的任务。
2.5 互斥
当两个任务需要共享一个资源时,需要有一个访问互斥机制,访问共享资源部分的代码成为临界区。
通过关中断可以简单的实现临界区, REX 还提供一种不太彻底的方式,导出函数可用于锁定或释放公共资源。
2.6 禁用中断后的挂起
只有正在运行的任务可以禁止中断,一旦某个任务禁止中断后挂起,中断状态则一直由该任务保存,任务重新激活后可以恢复中断状态。有一种潜在的危险是中断被下一个激活的任务允许,这一特性在以后的版本中可能被修改,但是程序员不能依赖这一点。
2.7 信号量
通用信号量集与每一个任务关联,这些信号量集作为相关任务的设备环境保存在任务的 TCB 里,用来表示与任务有关的某类事件发生了。一个任务的信号量可以被所有任务及中断服务程序设置或清除。
关于信号量需要注意的重点:
n 信号量是通用旗语,用户可以任意定义信号量的含义。
n 一个任务可以通过其他任务或中断任意设置一个特定的信号量挂起,需要强调的是任意,如果一个任务并没有因该信号量挂起,则设置的信号量不会对该任务的运行状态产生影响。
2.8 定时器
定时器用来确定某个时间间隔,任务通过定时器来实现一段延时,延时时间到了以后会有一个信号量时标,任务可以查询该时标,或者任务可以挂起自己等待该信号量时标。
定时器可以和其他事件联合使用,这样就可以确定事件是否超时。 REX 通过维护定时器链表的方式管理所有正在计时的定时器。对定时器的数量没有限制,定时器越多则每次遍历链表耗时越长,但是新增一个定时器对性能的影响是微弱的。已经到期的计数器不会产生管理开销。
2.9 扩展接口
REX 提供了一些扩展接口以增强可操作性,例如异步进程调用,延迟进程调用,内存管理。详情参考 REX+ + — REX 扩展用户使用手册( 80-V3083-1 )。
第三章 任务
本章详细描述了 REX 的调度及设备环境调度机制。
3.1 任务的创建
创建新任务使用 REX 提供的函数 rex_def_task() 。 REX 并不为任务堆栈和 TCB 分配空间。这一工作由调用创建任务函数的程序负责。不过 REX 要求避免用户直接操作 TCB 的数据结构。
任务创建函数 rex_def_task() 完成以下工作:
1. 将设备环境数据入栈
2. 设置 TCB
3. 将要创建的任务加入任务列表
4. 调度处理
如果新建任务优先级高于当前任务,则新任务取得控制权,否则,调度直接返回而不发生任务切换。新建的任务直到成为优先级最高的就绪任务时开始执行。
任务的入口由 rex_def_task() 指定为 rex_task_preamble() ,任务 在第一次获得控制权时初始化堆栈。
任务永远不会返回,因此 rex_task_preamble() 在调用了任务函数之后,会调用 rex_kill_task() ,这样的话一旦任务异常返回,则该任务会被 REX 终止。
3.1.1 调度
任务的调度由函数实现,调度函数为 REX 保留的内部函数,不能被应用程序直接调用。调用该函数时必须禁止中断,调用函数 rex_sched() 之前必须先设置全局变量 rex_best_task 并将该变量指向优先级最高的就绪任务的 TCB 。
调度算法的基本规则为:
1. 调度器检查 rex_best_task 是否指向当前正运行的任务 rex_curr_task 。
2. 如果 rex_best_task 与 rex_curr_task 相同,则调度器直接返回。
3. 如果 rex_best_task 与 rex_curr_task 不同,将 rex_best_task 的值赋给 rex_curr_task ,然后调度器检查是否在中断服务程序,如果在中断服务程序,则调度器返回。
4. 如果系统未在中断服务,则调度器开始执行设备环境切换,将当前的设备环境入栈,栈顶指针存入当前运行任务的 TCB ,并从 rex_curr_task 指向的任务的 TCB 中恢复堆栈指针,再从堆栈中恢复设备环境。
3.1.2 ARM 平台上任务的特殊性
ARM 是一款 32 位微处理器,具有线性地址空间,因此堆栈指针仅占用 TCB 的一个字段: sp 。
设备环境数据结构
设备环境包括 r0-r12 , lr , pc , CPSR 寄存器, 图3-1 表示了一个挂起任务的堆栈状态。
| ||
程序状态寄存器 CPSR | ||
r0-r12 | ||
连接寄存器 lr | ||
返回地址 | ||
应用程序堆栈数据 |
由于 rex_sched() 运行时中断被禁止,在 ARM 处理器上,设备环境的保存与恢复必须由 rex_sched() 自己处理。程序状态寄存器保 存的是函数入口时的 CPSR 值,因此设备环境保存了中断状态。
保存设备环境需进行如下操作:
1. 从 rex_curr_task 指向的任务 TCB 中取出堆栈指针。
2. 将已保存的 PSR 值考入 SPSR 寄存器。
3. 带 ^ 后缀调用 ldmfd 指令
n 装载 r0-r12,lr,pc
n 切换到 Thumb 模式
n 返回到任务
注:为保证同时恢复 PC 和 CPSR , 调用 ldmfd 指令一 定要记得使用 ^ 后缀。
第四章 中断处理
本章叙述了 REX 在进入中断和退出中断时所进行的操作。
ARM 有两级中断, FIQ 和 IRQ ,本章只讨论 IRQ ,因为 FIQ 中断处理期间不需要进行设备环境切换,所以 FIQ 非常简单。
当产生中断时,采用 ARM 汇编语言实现的函数 IRQ_Handler() 取得控制权,根据 异常事件中断向量表调用相应的中断服务处理。 rex_set_interrupt_vector() 用来加载中断向量(该函数的详细说明见第八章 7.19 节)。产生中断时, ARM 处理器切换到 IRQ 模式,使用 IRQ 寄存器区,将控制权交给 IRQ_Handler() ,由其进行以下操作:
1. 中断服务程序要使用的寄存器入栈,如果函数是由 C 语言编写,则受保护的寄存器包括: r0-r3 , r10 , r12 , r14 ,如果中断嵌套,还要保护 SPSR 。
2. 中断嵌套计数加一。
3. 切换回系统模式,并保存系统模式的 lr 寄存器,因为该寄存器在后面的处理中要使用。
4. 调用中断向量表注册了的中断服务处理程序。
5. 中断服务处理完毕返回后,恢复 lr 寄存器,工作模式切换回 IRQ 模式。
6. 中断嵌套计数减一。
7. 如果嵌套计数减为 0 ,并且 rex_best_task 不等于 rex_curr_task 时,需要进行任务切换。
8. 如需要任务切换,作如下处理:
a. 从 IRQ 的堆栈恢复 SPSR 及其它保护的寄存器。
b. 切换到超级用户模式。
c. 在当前任务的堆栈中保存其设备环境
d. 将超级用户模式的堆栈指针保存至任务的 TCB 中。
e. rex_best_task 的值赋给 rex_curr_task 。
f. 恢复 rex_curr_task 的设备环境。
9. 如果不需要任务切换,则从 IRQ 堆栈中恢复 SPSR 及其它受保护的寄存器,切换回超级用户模式。
注 :某些版本的 IRQ_Handler 不切换回系统模式处理中断,他们不支持中断嵌套,因此也不管理中断嵌套。
这种机制通过中断时的任务切换实现了强占式多任务,在中断到来时,既是当前任务正在运行,也会切换到更高优先级的就绪任务。
第五章 信号量和定时器
REX 使用信号量和定时器来实现任务间的同步机制及内部定时。
5.1 信号量
REX 为任务间通讯提供了信号量机制,信号量集与每个任务都关联,这样任何一个任务都可以通过 rex_get_sigs() , rex_set_sigs() 和 rex_clr_sigs() 函数读取、置位、清除任何其它任务使用的信号量。
任务可以调用 rex_wait() 函数来设置自己所等待的信号量子集,但不能等待别的任务的信号量。使用或操作可以设置等待多个信号量,任意信号量有效即可唤醒该任务。如果任务要等待的信号亮已经被置位则等待函数立即返回而不会挂起任务。
信号量值为一整形变量, ARM 处理器支持 32 位整形变量,因此一个任务可以同时设置 32 个信号量。
5.2 定时器
通过调用 rex_def_timer() 函数可以定义一个定时器,任务可以使用定时期来获得需要的时间间隔。
n 函数 rex_set_timer() 启动定时器。
n 函数 rex_pause_timer() 暂停定时器。
n 函数 rex_resume_timer() 重启定时器。
任务如果需要一个延时,可以调用 rex_timed_wait() 函数,然后等待超时信号量。定时时间到了定时器会设置信号量通知任务。
注 :需要注意任务必须设置为等待一个定时器信号量的超集,这一点非常重要,因为定时器通常已经在程序一开始就初始化过了,这时它的信号量属性已经确定。如果没有注意这一点,当一个任务调用 rex_timed_wait() 时所指定的信号量如果未包含在定时器的信号量集里,任务将捕获不到任何信号量。
时间的单位以毫秒计,最小计时单位为 1 毫秒。定时的精度与硬件平台有关,为每毫秒时钟嘀嗒中断的次数。
定时通过在每个时钟嘀嗒中断服务程序里调用 rex_tick() 来实现,需要定时多少毫秒,就相应调用多少次,定时结束后,将信号量写入等待定时任务的 TCB 中。
REX 负责维护所有未结束的定时器列表,一旦定时时间到,将从列表中删除该定时器,不过 REX 并不知道定时器的数据结构,因此,为定时器数据结构申请空间并维护由任务来完成。
注 :对调用 rex_def_timer() 函数的次数没有限制,但是不能对已有的定时器调用该函数,否则会破坏定时器列表,对任务来讲是致命错误。
第六章 REX 内幕
本章描述了一些 REX 内部的数据结构及变量,虽然这些数据可以访问到,但是它们不应该被应用程序直接操作,了解这一点有助于查找程序的问题。
6.1 任务控制块
每一个任务都有一个任务控制块来保存任务的设备环境。我们比较感兴趣的字段包括:
n sp ——堆栈指针,指示挂起的任务堆栈的栈顶位置。
n stack_limit ——指示任务的堆栈大小,堆栈指针不能小于这一值。
n sigs ——保存任务当前设置的信号量集。
n wait ——保存任务正在等待的信号量,如果该值不为零则表明任务处于挂起,如果该值为零则表明任务已经就绪或正在运行。
n pri ——任务的优先级
6.2 当前任务
全局指针变量 rex_curr_task 指向当前正在运行任务的 TCB 。
6.3 优选任务
全局指针变量 rex_best_task 指向优先级最高就绪任务的 TCB 。
6.4 任务列表
所有任务的 TCB 都按优先级排队保存在队列中,该队列为双向链表结构, next_ptr 和 prev_ptr 分别指向下一个和前一个数据。全局结构变量 rex_task_list 作为队首,它的 next_ptr 指针指向系统中的最高优先级任务(无论该任务是否就绪) 。通过前向遍历该队列,查找 TCB 中 wait 字段为 0 的任务即可找到最高优先级的就绪任务,空闲任务以优先级 0 排在队尾,并且该任务总是处于就绪态,因此可以保证遍历总是能完成。
注 :优先级 0 被保留,用户任务不能占用该优先级。
第七章 API 参考
本章列出了 REX 提供的 API 参考,由于 REX 不对函数的入口参数作检验,因此程序员在调用这些 API 时必须符合接口规范。系统提供了如下函数:
n rex_init( )
n rex_def_task( )
n rex_set_sigs( )
n rex_clr_sigs( )
n rex_get_sigs( )
n rex_wait( )
n rex_def_timer( )
n rex_set_timer( )
n rex_get_timer( )
n rex_clr_timer( )
n rex_pause_timer( )
n rex_resume_timer( )
n rex_tick( )
n rex_timed_wait( )
n rex_self( )
n rex_get_pri( )
n rex_set_pri( )
n rex_task_pri( )
n rex_set_interrupt_vector( )
n rex_enable_interrupt( )
n rex_disable_interrupt( )
n rex_init_crit_sect( )
n rex_enter_crit_sect( )
n rex_leave_crit_sect( )
7.1 rex_init()
原形 :
extern void rex_init (
void * p_istack, /* interrupt stack */
rex_stack_word_type p_istksiz, /* interrupt stack size */
rex_tcb_type *p_tcb, /* task control block */
void * p_stack, /* stack */
rex_stack_word_type p_stksiz, /* stack size */
rex_priority_type p_pri, /* task priority */
void (*p_task)( dword ), /* task function */
dword p_param /* task parameter */
);
描述 :
函数 rex_init() 初始化 REX ,必须在上电后首先调用该函数,并且只能调用一次,之后才允许调用其它 API 。只有调用该函数后中断才被允许。
功能 :
1. 创建第一个用户堆栈 p_task ,并作如下处理
n 堆栈大小为 p_istksiz
n 优先级为 p_pri
n p_tcb 作为 任务的 TCB
2. 调用调度器,将控制权交给创建的任务。
前两个参数 p_istack 和 p_istksiz 是为了与以前的版本兼容,以后的版本不再使用这两个参数。
副作用 :
无
返回值 :
该函数不返回。
用法 :
#include “rex.h”
#define FIRST_STACK_SIZE 512 /* 1024 bytes */
#define FIRST_TASK_PRI 200 /* Some non-zero unique value */
#define FIRST_TASK_PARAM 101 /* Some value understood by the new task */
rex_tcb_type first_task_tcb;
int first_task_stack[FIRST_STACK_SIZE];
void first_task(dword p)
{
/*
* This is the first task in the system.
* When control comes here …
* - p has been set to FIRST_TASK_PARAM by REX
* - first_task_stack is in use 11
* - this function is not supposed to return.
*/
}
上电初始化期间:
rex_init (
NULL,
0,
&first_task_tcb,
first_task_stack,
FIRST_STACK_SIZE * sizeof (int) / sizeof (word),
FIRST_TASK_PRI,
first_task,
FIRST_TASK_PARAM
);
7.2 rex_def_task()
原形 :
extern void rex_def_task (
rex_tcb_type *p_tcb, /* valid TCB for new task */
void * p_stack, /* stack for new task */
rex_stack_word_type p_stksiz, /* stack size for new task */
rex_priority_type p_pri, /* priority for new task */
void (*p_task)(dword), /* task startup function */
dword p_param /* parameter for new task */
);
描述 :
函数 rex_def_task 创建一个新任务,由 p_tcb 所指向的数据作为新任务的 TCB ,内存的分配由调用函数负责。
功能 :
新任务的设备环境为:
n 任务的私有堆栈,栈底为 p_stack ,栈空间为 p_stksiz 字(字长 16 bit )
n 任务优先级为 p_pri ,入口地址 p_task ,入口参数 p_param 在第一次运行任务时传递给任务函数, REX 不处理该数据,用户可根据需要定义入口参数的用处。
REX 定义了新任务后,立刻调用调度器,但是并不能保证新建的任务会立即获得控制权,仍然要视新任务的优先级相对于就绪任务是否为最高,新建任务为就绪态。
副作用 :
调用本函数会引起一次任务调度。
返回值 :
无
用法 :
#include “rex.h”
#define NEW_STACK_SIZE 512 /* 1024 bytes */
#define NEW_TASK_PRI 200 /* Some non-zero unique value */
#define NEW_TASK_PARAM 101 /* Some value understood by the new task */
rex_tcb_type new_task_tcb;
int new_task_stack[NEW_STACK_SIZE];
void new_task(dword p)
{
/*
* When control comes here …
* - p has been set to NEW_TASK_PARAM by REX
* - new_task_stack is in use
* - this function is not supposed to return.
*/
}
void existing_task(dword p)
{
…
rex_def_task ( &new_task_tcb,
new_task_stack,
NEW_STACK_SIZE * sizeof (int) / sizeof (word) ,
NEW_TASK_PRI,
new_task,
NEW_TASK_PARAM
);
…
}
7.3 rex_set_sigs ()
原形 :
extern rex_sigs_type rex_set_sigs (
rex_tcb_type *p_tcb, /* TCB for which the sigs will be set */
rex_sigs_type p_sigs /* the sigs to set */
);
描述 :
函数 rex_set_sigs 将一个信号量 p_sigs 以掩码的方式写入 p_tcb 所指任务的 TCB , p_sigs 为位寻址变量,每一位代表特定的信号量,任务获得了其中任何一个信号量后,重新作为候选的待执行任务。
副作用 :
调用本函数会引起一次任务调度。
返回值 :
返回原始的任务信号量。
用法 :
#include “rex.h”
#define NEW_SIGNALS 0x3 /* Some signals. */
extern rex_tcb_type target_task;
void signal_setting_task( dword p)
{
rex_sigs_type old_sigs;
old_sigs = rex_set_sigs( &target_task, (rex_sigs_type)NEW_SIGNALS);
}
7.4 rex_clr_sigs()
原形 :
extern rex_sigs_type rex_clr_sigs (
rex_tcb_type *p_tcb, /* TCB for which the signals will be cleared */
rex_sigs_type p_sigs /* which signals to clear */
);
描述 :
函数 rex_clr_sigs 清除 p_tcb 指向任务的信号量,不调用调度器。
返回值 :
返回原始的任务信号量。
用法 :
#include “rex.h”
#define CLEAR_THESE 0x30 /* Some signals. */
extern rex_tcb_type target_task;
void signal_clearing_task( dword p)
{
rex_sigs_type old_sigs;
old_sigs = rex_clr_sigs(&target_task, (rex_sigs_type)CLEAR_THESE);
}
7.5 rex_get_sigs()
原形 :
extern rex_sigs_type rex_get_sigs (
rex_tcb_type *p_tcb /* TCB for which sigs will be returned */
);
描述 :
函数 rex_get_sigs 读取 p_tcb 指向的任务的信号量。
返回值 :
返回原始的任务信号量。
用法 :
#include “rex.h”
extern rex_tcb_type target_task;
void signal_reading_task( dword p)
{
rex_sigs_type present_sigs;
present_sigs = rex_get_sigs( &target_task );
}
7.6 rex_wait()
原形 :
extern rex_sigs_type rex_wait (
rex_sigs_type p_sigs /* signals to wait on */
);
描述 :
函数 rex_wait 挂起调用它的任务, p_sigs 掩码写入 TCB 的信号量字段,任务直到等待的信号量被设置后,恢复就绪态。如果调用 rex_wait 时等待的信号量已被设置,则函数立即返回,任务能够继续进行。
任务只能等待自己的信号,不能等待其他任务的信号。
副作用 :
调用本函数会引起一次任务调度。
返回值 :
返回原始的任务信号量。
用法 :
#include “rex.h”
#define WAIT_FOR_THESE 0x50 /* Some signals. */
void wanting_to_wait_task( dword p)
{
rex_sigs_type got_these_sigs;
got_these_sigs = rex_wait((rex_sigs_type)WAIT_FOR_THESE);
}
7.7 rex_def_timer()
原形 :
extern void rex_def_timer(
rex_timer_type *p_timer, /* pointer to a valid timer structure */
rex_tcb_type *tcb_ptr, /* TCB to associate with the timer */
rex_sigs_type sigs /* sigs to set upon timer expiration */
);
描述 :
函数 rex_def_timer 初始化一个定时器,用于实现一个指定时间的延迟。
n 定时时间到后, tcb_ptr 指向的任务将获得通知。
n 定时时间到后设置信号量为 sigs 。
REX 默认为定时器运行所用内存空间由调用函数分配。
本函数至少需调用一次定时器才可用,但不能对正在计时的定时器调用该函数。
返回值 :
无
用法 :
#include “rex.h”
#define SET_THESE 0x12 /* Some signals. */
extern rex_tcb_type target_task;
rex_timer_type new_timer;
void timer_defining_task( dword p)
{
rex_def_timer(&new_timer, &target_task, (rex_sigs_type)SET_THESE);
}
7.8 rex_set_timer()
原形 :
extern rex_timer_cnt_type rex_set_timer(
rex_timer_type *p_timer, /* pointer to timer to set */
rex_timer_cnt_type msecs /* value in milliseconds */
);
描述 :
函数 rex_set_timer 启动由 p_timer 所 指的定时器,定时长度为 msecs 的毫秒数。该定时器对应的信号量在调用本函数时清零,定时结束后重新置位。
由 p_timer 所 指的定时器必须事先用 rex_def_timer 函数进行初始化,如果该定时器已在运行,则会按新的时间重新开始计时。
副作用 :
调用本函数会引起一次任务调度。
返回值 :
返回定时器写入新值前的定时计数值。
用法 :
#include “rex.h”
#define TIMER_VALUE 20 /* 20-millisecond timer */
extern rex_timer_type existing_timer;
void timer_setting_task( dword p)
{
rex_timer_cnt_type old_timer_count;
old_timer_count = rex_set_timer(&existing_timer, TIMER_VALUE);
}
7.9 rex_get_timer( )
原形 :
extern rex_timer_cnt_type rex_get_timer(
rex_timer_type *p_timer /* pointer to the timer to get */
);
描述 :
函数 rex_get_timer 返回 *p_timer 指向的定时器当前计数值,如返回值为 0 ,表示该定时器未启动。
返回值 :
返回定时器当前计数值。
用法 :
#include “rex.h”
extern rex_timer_type existing_timer;
void timer_reading_task( dword p)
{
rex_timer_cnt_type timer_count;
timer_count = rex_get_timer(&existing_timer);
}
7.10 rex_clr_timer( )
原形 :
extern rex_timer_cnt_type rex_clr_timer(
rex_timer_type *p_timer /* pointer to timer to clear */
);
描述 :
函数 rex_clr_timer 将由 *p_timer 指向的定时器定时值清零,同时该定时器被停止并从活动定时器列表中移出。
返回值 :
返回定时器当前计数值。
用法 :
#include “rex.h”
extern rex_timer_type existing_timer;
void timer_clearing_task( dword p )
{
rex_timer_cnt_type old_timer_count;
old_timer_count = rex_clr_timer( &existing_timer );
}
7.11 rex_pause_timer( )
原形 :
extern void rex_pause_timer(
rex_timer_type *p_timer /* pointer to timer to pause */
);
描述 :
函数 rex_pause_timer 将由 *p_timer 指向的定时器从活动定时器列表中移出,暂停该定时器。该函数与 rex_clr_timer 不同,前者不会将计数值清零。
返回值 :
无
用法 :
#include “rex.h”
Extern rex_timer_type existing_timer;
void timer_pausing_task( dword p)
{
rex_pause_timer(&existing_timer);
}
7.12 rex_resume_timer( )
原形 :
extern void rex_resume_timer(
rex_timer_type *p_timer /* pointer to timer to resume */
);
描述 :
函数 rex_resume_timer 将暂停的定时器加入到活动定时器列表中以恢复该定时器的运行。该函数与 rex_set_timer 不同,前者未明确给出定时长度,定时器将使用其原有值。
返回值 :
无
用法 :
#include “rex.h”
Extern rex_timer_type paused_timer;
void timer_resuming_task( dword p )
{
rex_resume_timer( &paused_timer );
}
7.13 rex_tick( )
原形 :
extern void rex_tick(
rex_timer_cnt_type msecs /* number of milliseconds elapsed */
);
描述 :
函数 rex_tick 不是供应用程序的任务使用,它有每次时钟嘀嗒中断服务函数在每次中断时进行调用,参数 msecs 指定每个时钟嘀嗒间隔的毫秒数,与硬件相关。
副作用 :
调用本函数会引起一次任务调度。
返回值 :
无
用法 :
#include “rex.h”
#define MS_PER_CLK_INTERRUPT 5
void clock_tick_isr()
{
rex_tick(MS_PER_CLK_INTERRUPT);
}
7.14 rex_timed_wait( )
原形 :
extern rex_timer_cnt_type rex_timed_wait(
rex_sigs_type p_sigs, /* sigs to wait on */
rex_timer_type *p_timer, /* timer to set and wait on */
rex_timer_cnt_type p_cnt /* timer to wait */
);
描述 :
函数 rex_timed_wait 的功能与一下操作相似:
rex_set_timer( p_timer , p_cnt );
return rex_wait( p_sigs );
调用该函数的任务在收到其他任务设置的信号量或定时时间到后,进入就绪态。
副作用 :
调用本函数会引起一次任务调度。
返回值 :
调用该函数的任务所等待的信号量子集被覆盖。
用法 :
#include “rex.h”
#define TIMER_VALUE 20 /* 20-millisecond timer */
#define WAIT_FOR_THESE 0x30 /* Some signals. */
Extern rex_timer_type existing_timer;
void timed_waiting_task( dword p)
{
rex_sigs_type got_these_sigs;
got_these_sigs = rex_timed_wait ( (rex_sigs_type)WAIT_FOR_THESE),
&existing_timer,
TIMER_VALUE
);
}
7.15 rex_self( )
原形 :
extern rex_tcb_type* rex_self ( void );
描述 :
函数 rex_self 返回调用它的任务的自身的 TCB ,任务通过调用该函数获得自身 TCB 的地址。
返回值 :
指向调用任务的 TCB 的指针。
用法 :
#include “rex.h”
void dont_know_my_own_name_task( dword p )
{
rex_tcb_type * my_tcb;
my_tcb = rex_self();
}
7.16 rex_get_pri( )
原形 :
extern rex_priority_type rex_get_pri( void );
描述 :
函数 rex_get_pri 返回调用它的任务的当前优先级。
返回值 :
调用任务的当前优先级。
用法 :
#include “rex.h”
Void dont_know_my_priority_task( dword p )
{
rex_priority_type my_priority;
my_priority = rex_get_pri();
}
7.17 rex_set_pri( )
原形 :
extern rex_priority_type rex_set_pri(
rex_priority_type p_pri /* the new priority */
);
描述 :
函数 rex_set_pri 的功能是将调它的其任务自身优先级修改为 p_pri 。
返回值 :
调用任务的原优先级。
用法 :
#include “rex.h”
void nice_task(dword p)
{
rex_priority_type old_priority
/* I am nice. I reduce my priority by 10. */
old_priority = rex_set_pri( rex_get_pri() – 10);
}
7.18 rex_task_pri( )
原形 :
extern rex_priority_type rex_task_pri(
rex_tcb_type *p_tcb, /* TCB to set priority on */
rex_priority_type p_pri /* the new priority */
);
描述 :
函数 rex_task_pri 设置 *p_tcb 所指任务的优先级为 p_pri 。
副作用 :
调用本函数会引起一次任务调度。
返回值 :
*p_tcb 所指任务的原优先级
用法 :
#include “rex.h”
Extern rex_tcb_type some_other_task;
void extremely_nice_task(dword p)
{
rex_priority_type old_priority;
/* I am extremely nice. I set this task’s priority to a 1000
* above my own priority.
*/
old_priority = rex_task_pri(
&some_other_task,
rex_get_pri() + 1000
);
}
7.19 rex_set_interrupt_vector( )
原形 :
void rex_set_interrupt_vector(
rex_vect_type v,
void (*fnc_ptr)( void )
);
描述 :
REX 操作系统在软件中维护了一个中断向量表, 调用这个函数可以在向量表中第 V 条写入一个入口函数句柄,作为对应向量的 IRQ 或 FIQ 的中断服务程序。
返回值 :
无
用法 :
#include “arm.h”
#include “rex.h”
void irq_isr ( void );
void irq_handler_setting_function( )
{
rex_set_interrupt_vector(P_IRQ_VECT, irq_isr);
}
7.20 rex_enable_interrupt( )
原形 :
void rex_enable_interrupt (
rex_vect_type v
);
描述 :
REX 操作系统在软件中维护了一个中断向量表,调用该函数会修改 CPSR 寄存器对应位,允许向量表中第 V 条中断 。
返回值 :
无
用法 :
#include “arm.h”
#include “rex.h”
1void irq_enabling_function( )
{
rex_enable_interrupt (P_IRQ_VECT);
}
7.21 rex_disable_interrupt( )
原形 :
void rex_disable_interrupt (
rex_vect_type v
);
描述 :
REX 操作系统在软件中维护了一个中断向量表,调用该函数会修改 CPSR 寄存器对应位,禁止向量表中第 V 条中断 。
返回值 :
无
用法 :
#include “arm.h”
#include “rex.h”
void fiq_disabling_function( )
{
rex_disable_interrupt ( P_FIQ_VECT );
}
7.22 rex_init_crit_sect( )
原形 :
extern void rex_init_crit_sect (
rex_crit_sect_type *crit_sect /* Pointer to critical section variable */
);
描述 :
函数 rex_init_crit_sect 初始化一个临界区。所有的临界区变量在使用之前必须先进行初始化。
返回值 :
无
用法 :
#include “rex.h”
rex_crit_sect_type sample_cs;
void cs_initializing_function( )
{
rex_init_crit_sect(&sample_cs);
}
注: 有些版本的 REX 操作系统不支持该函数。
7.23 rex_enter_crit_sect( )
原形 :
extern void rex_enter_crit_sect (
rex_crit_sect_type *crit_sect /* Pointer to critical section variable */
);
描述 :
任务通过调用 rex_enter_crit_sect 函数 进入临界区数据操作。如果该临界区数据已被其他任务封锁,则调用该函数的任务会进入等待队列等待正在操作临界区的任务释放该临界区。如果要进入的临界区不可用,则调用该函数的任务被阻塞。
副作用 :
如果临界区不可用则会挂起调用该函数的任务。
返回值 :
无
用法 :
#include “rex.h”
extern rex_crit_sect_type initialized_cs;
void cs_entering_function( )
{
rex_enter_crit_sect( &initialized_cs );
}
注: 有些版本的 REX 操作系统不支持该函数。
7.24 rex_leave_crit_sect( )
原形 :
extern void rex_leave_crit_sect (
rex_crit_sect_type *crit_sect /* Pointer to critical section variable */
);
描述 :
任务通过调用 rex_leave_crit_sect 函数退出它占用的临界区,该临界区被释放供等待队列中的其他任务操作,如果等待队列中的任务优先级高于当前任务,则高优先级任务获得执行权。
副作用 :
可能会导致一次设备环境上下文切换。
返回值 :
用法 :
#include “rex.h”
extern rex_crit_sect_type acquired_cs;
void cs_leaving_function( )
{
rex_leave_crit_sect(&acquired_cs);
}