首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

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

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

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