几个嵌入式系统相关的概念
任务:
任务即是
RTOS的一个调度单位。一般实时应用程序会由多个任务组成,每个任务都有自己的优先级与任务栈空间。 任务栈空间固定死了对应实际内存的某块空间,这与window程序是不一样的。
任务一般有五种运行状态:睡眼态,就绪态,运行态,挂起态与被中断态,每种状态从字面意义就可以很好理解,其中挂起态是是任务主动的交出执行权,而被中断态是被动被剥夺
CPU执行权。
从这些任务本身看并不知道存在其它的任务的存在,任务什么时候获得
CPU的执行权也不由任务本身决定,而是由RTOS根据各任务的优先级及运行状态综合考虑决定开始运行哪个任务。
软实时与硬实时:
硬实时要求某个时间点内事件必须得到处理,软实时要求事件尽可能快的得到处理。从字面上也很好的反应了这两者的差别。
^0^
任务优先级:
所有任务建位时都需要赋一个优先级,有些
RTOS允许多个任务共用同一个优先级(VxWork),而有些RTOS却要求每个任务必须有独立的优先级(UC/OS2)。在软件设计的时候,一般来说运行频率越高的任务其优先级也要越高,另外对有硬实时需求的任务也要配相对较高的优先级,总之为任务选合适的优先级不是一件容易的事情。
内核是否可剥夺:
当前一个低优先级任务
1正获得CPU的执行权,如果此时另一个高优先级的任务2变为就绪态需要得到CPU执行权。对不可剥夺的内核,任务1继续拥有CPU的执行权,直到其主动放弃执行权(如需要等待某一事件的发生)任务2才能得到CPU的执行权。可剥夺内核的遇到此种情况的反应是,任务2立马得到CPU的执行权,而任务1只有当任务2运行完后且没有其它比任务1优先级更高的任务就绪时才能重新得到CPU的执行权。
函数的可重入性:
一个简单的实例:
Int temp;
Void swap (int *a, int *b)
{
temp = *a; // 1
*a = *b; // 2
*b = temp; // 3
}
如果一个低优先级任务
1调用了此函数,执行到第1句;此时恰好另有一个调用这个函数的高优先级任务2就绪或是发了中断而相应的中断子程序会调用这个函数;那么当执行完任务2或是中断子程序后。重新回到任务1继续执行到第3句时,temp值已经被改写,保存的不再是先前*a的值,从而出错。这种问题很难查,因为它可能一连几天,几个月甚至几年都不会出错,却在某一天突然发难。
当然
,把temp定义成局部变量就不会存在问题了,如下:
Void swap (int *a, int *b)
{
Int temp;
temp = *a; // 1
*a = *b; // 2
*b = temp; // 3
}
从上面反映出了高质量软件应具备高内聚低藕合。
如果
temp值必须要用到一个全局变量的话,上述办法就无能为力了,此时就必须使用其它的互斥方法。
中断:
中断是一种硬件机制,用于通知
CPU有一个“异步事件发生了”。CPU一旦识别出一个中断,立即跳到该中断对应的子程序执行,处理完这个中断后回到所有就绪态任务中具有最高优先级的任务执行。
一般来说硬件人员设计会设计好中断对应的
CPU引脚,而软件人员需要为每个需要处理的中断设计处理子程序。并且需要维护一个中断向量表,用于建立各个中断与中断处理子程序的联系,这个中断向量表放在内存的某个CPU知道的固定位置。一旦CPU检测到一个中断,就跳到中断向量表里查询对应的中断处理子程序,如果找到则跳到该处理子程序的地址去执行,找不到则不处理。
任务间通信:
在
RTOS里任务间可以通过很多的方式进行通信,主要有:全局变量,信号量,邮箱,消息队列,事件标志组等。具体细节日后再说。 ^ 0 ^
看门狗:
看门狗是嵌入式系统一种常用的检测异常的机制,包括一个元器件定时器,这个元器件和
CPU的reset引脚相连,一般RTOS会提供一个接口供一个处理函数与一个定时器建立联系。当这个定时器计数到某一个特定的时间后就会输出一个脉冲到CPU的reset引脚,从而让CPU复位,重新动并运行软件。所以一般会在某个优先级比较低的任务里重置定时器的计时,从而不让CPU重新启动,如果CPU已经处在某种异常状态下,使这个低优先级的任务一直得不到运行,于是当看门狗定时器到达一定计数后就重启CPU,重新启动软件运行试图消除异常状态。