Chinaunix首页 | 论坛 | 博客
  • 博客访问: 94059
  • 博文数量: 19
  • 博客积分: 1455
  • 博客等级: 上尉
  • 技术积分: 210
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-04 14:14
文章分类
文章存档

2010年(14)

2008年(5)

我的朋友

分类:

2010-04-17 15:17:17

 

       任何一个操作系统都会提供大量的API供程序员使用,μC/OS-也不例外。由于μC/OS-面向的是嵌入式开发,并不要求大而全,所以内核提供的API也就大多和多任务息息相关。本文通过分析μC/OS-Ⅱ中提供的API来引出μC/OS-Ⅱ中API的设计思路和实现机制。

 

       API全称Application Programming Interface,中文是应用程序编程接口的意思。API是操作系统提供给用户的一组函数,供用户在编写应用程序时调用,可以完成应用程序对操作系统的各种调用,包括进程调度、存储管理、图形设备接口及文件管理等。μC/OS-Ⅱ作为一个嵌入式操作系统,相对于其他操作系统,有很多自己的特色,在设计思路和实现机制上都和一般操作系统有很大的不同。

 

    1. 简介

 

 任何一个操作系统都会提供大量的API供程序员使用,μC/OS-也不例外。由于μC/OS-面向的是嵌入式开发,并不要求大而全,所以内核提供的API也就大多和多任务息息相关。μC/OS-Ⅱ的API主要分以下几类:(1)任务类、(2)消息类、(3)同步类、(4)时间类、(5)临界区与事件类等。下面分别从这几类API分析各自的设计思路和实现机制。

 

    2. 任务类API的设计思路和实现机制

 

μC/OS-Ⅱ可以管理多达64个任务,并从中保留了四个最高优先级和四个最低优先级的任务供自己使用,所以用户可以使用的只有56个任务。任务类API包括如何在用户的应用程序中建立任务、删除任务、改变任务的优先级、挂起和恢复任务,以及获得有关任务的信息等。

 

     2.1 建立任务API

   

    想让μC/OS-Ⅱ管理用户的任务,用户必须要先建立任务。用户可以通过传递任务地址和其它参数到以下两个函数之一来建立任务:OSTaskCreate() OSTaskCreateExt()

 

    OSTaskCreate()μC/OS是向下兼容的,OSTaskCreateExt()OSTaskCreate()的扩展版本,提供了一些附加的功能。用两个函数中的任何一个都可以建立任务。任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中被建立。在开始多任务调度(即调用OSStart())前,用户必须建立至少一个任务。任务不能由中断服务程序(ISR)来建立。

   

    OSTaskCreate()的函数定义如下。从中可以知道,OSTaskCreate()需要四个参数:task是任务代码的指针,pdata是当任务开始执行时传递给任务的参数的指针,ptos是分配给任务的堆栈的栈顶指针,prio是分配给任务的优先级。

INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)

 

OSTaskCreateExt()函数来建立任务会更加灵活,但会增加一些额外的开销。

 

OSTaskCreateExt()需要九个参数!前四个参数(task,pdata,ptosprio)OSTaskCreate()的四个参数完全相同,连先后顺序都一样。这样做的目的是为了使用户能够更容易地将用户的程序从OSTaskCreate()移植到OSTaskCreateExt()上去。函数的定义如下:

INT8U OSTaskCreateExt (void   (*task)(void *pd),

                       void    *pdata,

                       OS_STK  *ptos,

                       INT8U    prio,

                       INT16U   id,

                       OS_STK  *pbos,

                       INT32U   stk_size,

                       void    *pext,

                       INT16U   opt)

 

    2.2 删除任务API

 

有时候删除任务是很有必要的。删除任务,是说任务将返回并处于休眠状态,并不是说任务的代码被删除了,只是任务的代码不再被μC/OS-Ⅱ调用。通过调用OSTaskDel()就可以完成删除任务的功能。OSTaskDel()一开始应确保用户所要删除的任务并非是空闲任务,因为删除空闲任务是不允许的。不过,用户可以删除statistic任务。接着,OSTaskDel()还应确保用户不是在ISR例程中去试图删除一个任务,因为这也是不被允许的。调用此函数的任务可以通过指定OS_PRIO_SELF参数来删除自己。接下来OSTaskDel()会保证被删除的任务是确实存在的。该函数的入口参数很简单,只需要知道要删除任务的优先级即可。

INT8U OSTaskDel (INT8U prio)

 

    2.3 改变任务优先级API

 

在用户建立任务的时候会分配给任务一个优先级。在程序运行期间,用户可以通过调用OSTaskChangePrio()来改变任务的优先级。换句话说,就是μC/OS-Ⅱ允许用户动态的改变任务的优先级。函数定义如下:

INT8U OSTaskChangePrio (INT8U oldprio, INT8U newprio)

 

用户不能改变空闲任务的优先级,但用户可以改变调用本函数的任务或者其它任务的优先级。为了改变调用本函数的任务的优先级,用户可以指定该任务当前的优先级或OS_PRIO_SELFOSTaskChangePrio()会决定该任务的优先级。用户还必须指定任务的新(即想要的)优先级。因为μC/OS-Ⅱ不允许多个任务具有相同的优先级,所以OSTaskChangePrio()需要检验新优先级是否是合法的(即不存在具有新优先级的任务)。如果新优先级是合法的,μC/OS-Ⅱ通过将某些东西储存到OSTCBPrioTbl[newprio]中保留这个优先级。如此就使得OSTaskChangePrio()可以重新允许中断,因为此时其它任务已经不可能建立拥有该优先级的任务,也不能通过指定相同的新优先级来调用OSTaskChangePrio()。接下来OSTaskChangePrio()可以预先计算新优先级任务的OS_TCB中的某些值。而这些值用来将任务放入就绪表或从该表中移除。

 

    2.4 挂起任务和恢复任务API

 

 有时候将任务挂起是很有用的。挂起任务可通过调用OSTaskSuspend()函数来完成。被挂起的任务只能通过调用OSTaskResume()函数来恢复。任务挂起是一个附加功能。也就是说,如果任务在被挂起的同时也在等待延时的期满,那么,挂起操作需要被取消,而任务继续等待延时期满,并转入就绪状态。任务可以挂起自己或者其它任务。

 

 OSTaskSuspend()函数的函数定义如下:

INT8U OSTaskSuspend (INT8U prio)

 

 恢复任务OSTaskResume()函数定义为:

INT8U OSTaskResume (INT8U prio)

 

被挂起的任务只有通过调用OSTaskResume()才能恢复。因为OSTaskSuspend()不能挂起空闲任务,所以必须得确认用户的应用程序不是在恢复空闲任务。注意,这个测试也可以确保用户不是在恢复优先级为OS_PRIO_SELF的任务(OS_PRIO_SELF被定义为0xFF,它总是比OS_LOWEST_PRIO)

 

  2.5 获得任务信息API

 

用户的应用程序可以通过调用OSTaskQuery()来获得自身或其它应用任务的信息。实际上,OSTaskQuery()获得的是对应任务的OS_TCB中内容的拷贝。用户能访问的OS_TCB的数据域的多少决定于用户的应用程序的配置(参看OS_CFG.H)。由于μC/OS-Ⅱ是可裁剪的,它只包括那些用户的应用程序所要求的属性和功能。

void MyTask (void *pdata)

 

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

 

  3. 消息和同步类API的设计思路和实现机制

 

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

 

μC/OS-II中的信号量由两部分组成:一个是信号量的计数值,它是一个16位的无符号整数(0 65,535之间);另一个是由等待该信号量的任务组成的等待任务表。用户要在OS_CFG.H中将OS_SEM_EN开关量常数置成1,这样μC/OS-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-Ⅱ提供一系列API函数供用户调用,实现各个任务之间的通信和同步功能。下面以信号量为例说明各个API的实现。

 

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

 

阅读(1153) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~