新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 浅析μC/OS-ⅡAPI的设计思想及实现机制

浅析μC/OS-ⅡAPI的设计思想及实现机制

作者:时间:2012-08-24来源:网络收藏

void MyTask (void *pdata)

函数参数为一指针变量,指向对应任务的OS_TCB结构地址。本函数是有用的调试工具。

3. 消息和同步类的设计思路和

μⅡ中有三种方法消息通信和同步:信号量、邮箱和消息队列。一个任务或者中断服务子程序可以通过事件控制块ECB(Event Control Blocks)来向另外的任务发信号。这里,所有的信号都被看成是事件(Event)。这也说明为什么上面把用于通讯的数据结构叫做事件控制块。一个任务还可以等待另一个任务或中断服务子程序给它发送信号。这里要注意的是,只有任务可以等待事件发生,中断服务子程序是不能这样做的。对于处于等待状态的任务,还可以给它指定一个最长等待时间,以此来防止因为等待的事件没有发生而无限期地等下去。多个任务可以同时等待同一个事件的发生。在这种情况下,当该事件发生后,所有等待该事件的任务中,优先级最高的任务得到了该事件并进入就绪状态,准备执行。上面讲到的事件,可以是信号量、邮箱或者消息队列等。当事件控制块是一个信号量时,任务可以等待它,也可以给它发送消息。

μII中的信号量由两部分组成:一个是信号量的计数值,它是一个16位的无符号整数(0 到65,535之间);另一个是由等待该信号量的任务组成的等待任务表。用户要在OS_CFG.H中将OS_SEM_EN开关量常数置成1,这样μII才能支持信号量。

邮箱是μC/OS-II中另一种通讯,它可以使一个任务或者中断服务子程序向另一个任务发送一个指针型的变量。该指针指向一个包含了特定“消息”的数据结构。为了在μC/OS-II中使用邮箱,必须将OS_CFG.H中的OS_MBOX_EN常数置为1。

消息队列是μC/OS-II中另一种通讯,它可以使一个任务或者中断服务子程序向另一个任务发送以指针方式定义的变量。因具体的应用有所不同,每个指针指向的数据结构变量也有所不同。为了使用μC/OS-II的消息队列功能,需要在OS_CFG.H 文件中,将OS_Q_EN常数设置为1,并且通过常数OS_MAX_QS来决定μC/OS-II支持的最多消息队列数。

μC/OS-Ⅱ提供一系列函数供用户调用,各个任务之间的通信和同步功能。下面以信号量为例说明各个的实现。

μC/OS-II提供了5个对信号量进行操作的函数。它们是:OSSemCreate(),OSSemPend(),OSSemPost(),OSSemAccept()和OSSemQuery()函数。图 F6.5说明了任务、中断服务子程序和信号量之间的关系。图中用钥匙或者旗帜的符号来表示信号量:如果信号量用于对共享资源的访问,那么信号量就用钥匙符号。符号旁边的数字N代表可用资源数。对于二值信号量,该值就是1;如果信号量用于表示某事件的发生,那么就用旗帜符号。这时的数字N代表事件已经发生的次数。从图 F6.5中可以看出OSSemPost()函数可以由任务或者中断服务子程序调用,而OSSemPend()和OSSemQuery()函数只能有任务程序调用。

3.1建立一个信号量, OSSemCreate()

OS_EVENT *OSSemCreate (INT16U cnt)

函数参数传递的是要创建的信号量的初始值,在函数内部对任务控制块进行初始化。OSSemCreate()返回给调用函数一个指向任务控制块的指针。以后对信号量的所有操作,如OSSemPend(), OSSemPost(), OSSemAccept()和OSSemQuery()都是通过该指针完成的。因此,这个指针实际上就是该信号量的句柄。如果系统中没有可用的任务控制块,OSSemCreate()将返回一个NULL指针。

值得注意的是,在μC/OS-II中,信号量一旦建立就不能删除了,因此也就不可能将一个已分配的任务控制块再放回到空闲ECB链表中。如果有任务正在等待某个信号量,或者某任务的运行依赖于某信号量的出现时,删除该任务是很危险的。

3.2等待一个信号量, OSSemPend()

void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

它首先检查指针pevent所指的任务控制块是否是由OSSemCreate()建立的。如果信号量当前是可用的(信号量的计数值大于0),将信号量的计数值减1,然后函数将“无错”错误代码返回给它的调用函数。显然,如果正在等待信号量,这时的输出正是我们所希望的,也是运行OSSemPend()函数最快的路径。

3.3发送一个信号量, OSSemPost()

INT8U OSSemPost (OS_EVENT *pevent)

它首先检查参数指针pevent指向的任务控制块是否是OSSemCreate()函数建立的,接着检查是否有任务在等待该信号量。如果该任务控制块中的.OSEventGrp域不是0,说明有任务正在等待该信号量。这时,就要调用函数OSEventTaskRdy(),使一个任务进入就绪状态,把其中的最高优先级任务从等待任务列表中删除并使它进入就绪状态。然后,调用OSSched()任务调度函数检查该任务是否是系统中的最高优先级的就绪任务。如果是,这时就要进行任务切换[当OSSemPost()函数是在任务中调用的],准备执行该就绪任务。如果不是,OSSched()直接返回,调用OSSemPost()的任务得以继续执行。如果这时没有任务在等待该信号量,该信号量的计数值就简单地加1。

上面是由任务调用OSSemPost()时的情况。当中断服务子程序调用该函数时,不会发生上面的任务切换。如果需要,任务切换要等到中断嵌套的最外层中断服务子程序调用OSIntExit()函数后才能进行。

3.4无等待地请求一个信号量, OSSemAccept()

INT16U OSSemAccept (OS_EVENT *pevent)

当一个任务请求一个信号量时,如果该信号量暂时无效,也可以让该任务简单地返回,而不是进入睡眠等待状态。这种情况下的操作是由OSSemAccept()函数完成的。该函数在最开始也是检查参数指针pevent指向的事件控制块是否是由OSSemCreate()函数建立的,接着从该信号量的事件控制块中取出当前计数值,并检查该信号量是否有效(计数值是否为非0值)。如果有效,则将信号量的计数值减1,然后将信号量的原有计数值返回给调用函数。调用函数需要对该返回值进行检查。如果该值是0,说明该信号量无效。如果该值大于0,说明该信号量有效,同时该值也暗示着该信号量当前可用的资源数。应该注意的是,这些可用资源中,已经被该调用函数自身占用了一个(该计数值已经被减1)。中断服务子程序要请求信号量时,只能用OSSemAccept()而不能用OSSemPend(),因为中断服务子程序是不允许等待的。



评论


相关推荐

技术专区

关闭