-
实时系统概念
1.
有两种类型的实时系统:
软实时系统和硬实时系统。
在软实时系统中系统
的宗旨是使各个任务运行得越快越好,并不要求限定某
一任务必须在多长
时间内完成。在硬实时系统中,各任务不仅要执行无误而且要做到准时
。
2.
前后台系统
:
应用程序是一个无限的
循环,
循环中调用相应的函数完成相
应的操作,这部分可以看成
后台行为
(background)
。中断服务程序处理异
p>
步事件,这部分可以看成前台行为(
foreground
)。
后台也可以叫做任务
级
。
前台也叫中断级
。
3.
可重入型函数
:
可重入型函数可以被
一个以上的任务调用,
而不必担心数
据的破坏
< br>。可重入型函数任何时候都可以被中断,一段时间以后又可以运
行,而相应数据不
会丢失。可重入型函数或者只使用局部变量,即变量保
存在
CP
U
寄存器中或堆栈中。如果使用全局变量,则要对全局变量予以保
护。以下技术之一即可使不可重入函数具有可重入性:
?
把变量定义为局部变量
?
调用函数之前关中断,调动后再开中断
?
用信号量禁止该函数在使用过程中被再次调用
4.
优先级反转
:
应用程序执行过程中,
任务的优先级是可变的,则称之为动
态优先级。
实时内核应当避
免出现优先级反转问题
。为防止发生优先级反
转
,
内核能自动变换任务的优先级
,
这叫
做优先级继
承
(Priori
ty
inheritance)
5.
互斥条件
:
实现任务间通讯最简便到办法是使用
共享数据结构
。
特别是当所
有到任务都在一个单一地
址空间下,能使用全程变量、指针、缓冲区、链
表、循环缓冲区等,使用共享数据结构通
讯就更为容易。虽然共享数据区
法简化了任务间的信息交换,但是必须保证每个任务在处
理共享数据时的
排它性,以避免竞争和数据的破坏。与共享资源打交道时,使之满足互斥
条件最一般的方法有:
?
关中断
(
μ
C/OS-
Ⅱ在
处理内部变量和数据结构时就是使用的这种手
段
)
?
使用测试并置位指令
?
禁止做任务切换
?
利用信号量
6.
信号量
:
信号量用于:
?
控制共享资源
的使用权
(
满足互斥条件
)
?
标志某事件的发生
?
使两个任务的行为同步
对信号量只能实施三种操作:
?
初始化
(INITIALIZE)
,也可称作建立
(
CREATE)
;
?
等信号
(WAIT)
也可称作挂起
(PEND)
p>
;
?
给信号
(SIGNAL)
或发信号
p>
(POST)
。
这是我自己写的验证信号量的部分代码
:
void task_one(void* pdata);
void task_two(void* pdata);
OS_EVENT
*tasktwo;
#include
GUI_Init();
VCInit();
//
初始化一些变量
OSInit();
timeSetEvent(OS_TICKS_PER_SEC,
0,
OSTickISR,
0,
TIME_PERIODIC);
//
产生节拍
tasktwo =
OSSemCreate(0);
OSTaskCreate(task_two, 0,
&TaskStk[7][TASK_STK_SIZE-1], 1);
OSTaskCreate(task_one, 0,
&TaskStk[8][TASK_STK_SIZE-1], 2);
OSStart();
7.
使用实时内核的优缺点
:
实时内核也
称为实时操作系统或
RTOS
。
它的使
用
使得实时应用程序的设计和扩展变得容易,不需要大的改动就可以增加新
的功能。通过将应用程序分割成若干独立的任务,
RTOS
< br>使得应用程序的设
计过程大为减化。使用可剥夺性内核时,所有时间要求苛刻的事
件都得到
了尽可能快捷、有效的处理。通过有效的服务,如信号量、邮箱、队列、
延时、超时等,
RTOS
使得资源得到更好的
利用。如果应用项目对额外的需
求可以承受,应该考虑使用实时内核。这些额外的需求是
:内核的价格,
额外的
ROM/RAM
开销,
2
到
4
百分点的
CPU
额外负荷。
内核结构
1.
任务
:
一个任务通常是一个无限的循
环。看起来像其它
C
的函数一样,有
函
数返回类型,有形式参数变量,
但是任务是绝不会返回的
。故返
回参数
必须定义成
void
。
当任务完成以后任务代码并非真的删除了,
μ
C
/OS-
Ⅱ只
是简单地不再理会这个任务了。
< br>
列出一任务:
void YourTask (void *pdata)
{
for (;;) {
(2)
/*
用户代码
*/
调用
uC/OS-
II
的某种系统服务
:
OSMboxPend();
OSQPend();
(1)
OSSemPend();
OSTaskDel(OS_PRIO_SELF);
OSTaskSuspend(OS_PRIO_SELF);
OSTimeDly();
OSTimeDlyHMSM();
/*
用户代码
*/
}
}
形式参数变量
(1)
是由用户代码在第一次执行的时候带入的
。该变量的类型是一
个指向
void
的
指针。这是为了允许用户应用程序传递任何类型的数据给任务。
μ
C/OS-
Ⅱ可以管理多达
64
个任
务,但目前版本的
μ
C/OS-
Ⅱ有两
个任务已经被
系统占用了。作者保留了优先级为
0
、
1
、
2
< br>、
3
、
OS_LOWEST_P
RIO-3
、
OS_LOWEST_PRI0-2
,
OS_LOWEST_PRI0-1
以及
OS_LOWEST_PRI0
这
8
个任务以被将
来使用。为了使
μ
< br>C/OS-
Ⅱ能管理用户任务,用户必须在建立一个任务的时候,
将任务的起始地址与其它参数一起传给下面两个函数中的一个:
OSTastC
reat
或
OSTaskCreatExt()
。
2.
p>
任务控制块:一旦任务建立了,任务控制块
OS_TCBs
将被赋值。任务控制
块是一个
数据结构
,当任务的
CPU
使用权被剥夺时,
μ
C/OS-
Ⅱ用它来保存
该任务的状态。当任务重新得到
CPU
使用权时,任务控制块
能确保任务从
当时被中断的那一点丝毫不差地继续执行。
OS_
TCBs
全部驻留在
RAM
中。
?C/OS-
II
任务控制块清单:
typedef struct os_tcb {
OS_STK *OSTCBStkPtr; //
指向当前任务
栈顶的指针。
每个任务的栈的
容量可以是
//
任意的
。
#if OS_TASK_CREATE_EXT_EN
void *OSTCBExtPtr;
//
指向用户定义的任务控制块扩展
OS_STK *OSTCBStkBottom;
//
是指向任务栈底的指针
INT32U OSTCBStkSize;
//
存有栈中可容纳的指针元数目
INT16U OSTCBOpt; //
把“选择
项”传给
OSTaskCreateExt()
INT16U OSTCBId;
//
存储任务的识别码,留给将来扩展用
#endif
//
用于任务控制块<
/p>
OS_TCBs
的双重链接,该
链表在时
钟节
struct
os_tcb
*OSTCBNext;
//
拍函数
OSTimeTick()
中使用,用于刷新各个<
/p>
任务的任
struct
os_tcb *OSTCBPrev;
//
务延迟变量
.
#if (OS_Q_EN && (OS_MAX_QS
>= 2)) || OS_MBOX_EN || OS_SEM_EN
OS_EVENT *OSTCBEventPtr;
//
指向事件控制块的指针
#endif
#if
(OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN
void *OSTCBMsg;
//
是指向传给任务的消息的指针
#endif
INT16U OSTCBDly;
INT8U
OSTCBStat;
INT8U
OSTCBPrio;
INT8U
OSTCBX;
INT8U OSTCBY;
INT8U OSTCBBitX;
INT8U OSTCBBitY;
#if OS_TASK_DEL_EN
BOOLEAN OSTCBDelReq;
#endif
} OS_TCB;
目前,
一个用于空闲任务,
另一个用于任务统计
(如果
OS_TASK_STAT_EN
是设为
1
的)。在
μ
C/O
S-
Ⅱ初始化的时候,所有任务控制块
OS_TCBs
被链接成单向空
任务链表。
当任务一旦建立,<
/p>
空任务控制块指针
OSTCBFreeList
< br>指向的任务控制
块便赋给了该任务,
然后
OSTCBFreeList
的值调整为指向下链表中下一个空的任
务控制块。一旦任务被删除,任务控制块就还给空任务链表。
3.
就绪表(
Ready
List
):每个任务被赋予不同的优先级等级,从
0
级到最
低优先级
OS_LOWEST_PR1O
。每个任务的就绪态标志都放入就绪表中的,就
绪表中有两个变量
OSRedyGrp
和
OSRdyTbl[]
。
在
OSRdyGrp
中,
任务按优先
级分组,
8
个任务为一组。
OSRdyGrp
中的每一位表
示
8
组任务中每一组中
是否有进入就绪
态的任务。任务进入就绪态时,就绪表
OSRdyTbl[]
中
的相
应元素的相应位也置位。
以下程
序清单中的代码用于将任务放入就绪表。
Prio
是任务的优先
级
OSRdyGrp |=
OSMapTbl[prio >> 3];
OSRdyTbl[prio >>
3] |= OSMapTbl[prio & 0x07];
如果一个任务被删除了,则用程序清单中的代码做求反处理
if ((OSRdyTbl[prio >> 3] &=
~OSMapTbl[prio & 0x07]) == 0)
OSRdyGrp &= ~OSMapTbl[prio >>
3];
找出进入就绪态的优先级最高的任务
y = OSUnMapTbl[OSRdyGrp];
x =
OSUnMapTbl[OSRdyTbl[y]];
prio = (y << 3) + x;
4.
任务调度(
Task
Schedul
ing
):
μ
C/OS-
Ⅱ总是运行进入就绪态任务中优
先级最高的那一个。确定哪个任务优先级最高
,下面该哪个任务运行了的
工作是由调度器(
Schedule
r
)完成的。
任务级的调度是由函数
O
SSched()
完成的。
中断级的调度是由另一个函数
OSIntExt()
完成的
,
OSSched()
的所
有代码都属临界段代码。<
/p>
5.
< br>系统初始化
OSIint():OSInit()
建立空
闲任务
idle task
,这个任务总是
处于就绪态的。
OSInit()
还得建立统计任务
OSTaskStat()
并且让其进入就
绪
态。
以上两个任务的任务控制块
(
OS
_TCBs
)
是用双向链表链接在一起的。
μ
C/OS-
Ⅱ还初始化了
4
p>
个空数据结构缓冲区。
6.
任务启动
OSStart()
:多任务的启动是用户通过调用
OSStart()
实现的。
然而,
启动
μ
C/OS-
Ⅱ之前,
用户至少要建立一个应用任务。
当调用
OSSt
art()
时,
OSStart()
从
任务就绪表中找出那个用户建立的优先级最高任务的任务
控制块,然后,
OSStart()
调用高优先级就绪任务启动函数
任务管理
1.
建立任务
:
建立任务:
OSTaskCreate()
或
OSTaskCreateExt()
。
OSTaskCreate()
与
?C/OS
是向下兼容的,
OSTaskCreateExt
()
是
OSTaskCreate()
的扩展版本,提供了一些附加的功能。任务可以在多任务
调度开始前建立,也可以在其它
任务的执行过程中被建立。在开始多任务
调度
(
即调用
OSStart())
前,
用户必须建立至少一个任务。
任务不能由中断
服务程序
p>
(ISR)
来建立。
OSTaskCreate()
需要四个参数:
task<
/p>
是任务代码的指针,
pdata
是当任务
开
始执行时传递给任务的参数的指针,
ptos
是分配给任务的堆栈的栈顶指针,
prio
是分配给任
务的优先级。
OSTaskCreate()
清单
INT8U
OSTaskCreate
(void
(*task)(void
*pd),
void
*pdata,
OS_STK
*ptos,
INT8U prio)
{
void *psp;
INT8U err;
if
(prio > OS_LOWEST_PRIO) {
//
检测分配给任务的优先级是否
有效
return (OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
//
关中断
if
(OSTCBPrioTbl[prio] == (OS_TCB *)0) { //
确保在规定的优先级上还没
有建立任务
OSTCBPrioTbl[prio] = (OS_TCB
*)1;
//
放置一个非空指针保留该优
先级
-
-
-
-
-
-
-
-
-
上一篇:AX88796总结
下一篇:新概念英语第一册_19-33课1_练习题