今天来具体讲一下uC/OS III的一些功能,主要是介绍如何调用它的函数。
上一次我们说过,在裸机编程中,通过while(1)大循环来按顺序执行我们的程序,除了中断之外,后面的程序是不可能打断前面的程序来执行的。而在我们的uC/OS III操作系统中,各个任务是完全独立的,各个任务具有自己的优先级,通常按照优先级高低来依次执行,其他的暂时不多说。今天主要说一下任务的创建与管理,还有消息队列。
一、任务创建
在上一次移植好的工程中,我们可以来创建自己的任务。
①定义任务栈及设置任务栈大小。
由于各个任务是相互独立的,我们得为每一个任务定义一个任务栈,并且根据需要来设置任务栈的大小。
#define START_STK_SIZE 512
CPU_STK START_TASK_STK[START_STK_SIZE];
其中的CPU_STK是一个数据类型,其实本质上就是unsigned int,只不过它用typedef重新定义了一下,在uC/OS III大部分都是这样操作的,这个可以在头文件中去查看,就不多说了。
②定义任务控制块
定义好任务函数和任务栈之后,我们还需要为任务定义一个任务控制块,通常我们称这个任务控制块为任务的身份证。在 C 代码上,任务控制块就是一个结构体,里面有非常多的成员,这些成员共同描述了任务的全部信息。
OS_TCB StartTaskTCB;
③定义错误类型
OS_ERR err;
这是一个枚举类型的结构体,里面保存了发生各种错误时的返回值。
④定义任务主体函数
就是具体要实现的功能函数。比如要写一个led闪烁的程序。
void led1_task(void *p_arg)
{
……
}
任务一般都是死循环并且无返回值的,只执行一次的任务在执行完毕要记得及时删除。任务里面的延时函数必须使用 uCOS 里面提供的阻塞延时函数,并不能使用我们裸机编程中的那种延时。这两种的延时的区别是 uCOS 里面的延时是阻塞延时,即调用 OSTimeDly()函数的时候,当前任务会被挂起,调度器会切换到其它就绪的任务,从而实现多任务。如果还是使用裸机编程中的那种延时,那么整个任务就成为了一个死循环,如果恰好该任务的优先级是最高的,那么系统永远都是在这个任务中运行,比它优先级更低的任务无法运行,根本无法实现多任务,因此任务中必须有能阻塞任务的函数,才能切换到其他任务中。这一点如果无法理解的话,先记住。
⑤创建任务
前面做的这些都是在为这个做准备。在创建任务之前,先对系统初始化,调用OSInit(&err);接着我们调用 OSTaskCreate()这个函数来创建任务,所以,来看一下这个函数是怎么样的。
这个函数的输入参数特别多。
⑤启动任务
OSStart(&err);
这大概就完成了一个任务的创建过程。其实最主要的无非就是调用OSTaskCreate()这个函数,前面的那些定义也是根据这个函数的输入参数来的,当你看到它的输入参数的时候,你自然就会知道要去定义前面那些东西了。然后就编写任务函数。
这是创建一个任务。如果创建多个任务,那么,我们是在main函数里先创建一个起始任务,然后在它的起始任务函数里再创建其他的任务,同时删除或者挂起这个起始任务。当然,我们得为每一个任务定义好任务堆栈,任务控制块这些。
一、任务管理
从系统的角度看,任务是竞争系统资源的最小运行单元。uCOS 是一个支持多任务的操作系统。在 uCOS 中,任务可以使用或等待 CPU、使用内存空间等系统资源,并独立于其它任务运行,任何数量的任务可以共享同一个优先级,处于就绪态的多个相同优级任务将会以时间片切换的方式共享处理器。uCOS 中的任务是抢占式调度机制,高优先级的任务可打断低优先级任务,低优先级任务必须在高优先级任务阻塞或结束后才能得到调度。同时 uCOS 也支持时间片轮转调度方式,只不过时间片的调度是不允许抢占任务的 CPU使用权。
uCOS 系统中的每一个任务都有多种运行状态:
下面说一下任务管理的几个函数
①任务挂起函数 OS_TaskSuspend()
挂起指定任务。被挂起的任务绝不会得到 CPU 的使用权,不管该任务具有什么优先级。任务的挂起与恢复函数在很多时候都是很有用的,比如我们想暂停某个任务运行一段时间,但是我们又需要在其恢复的时候继续工作,那么删除任务是不可能的,因为删除了任务的话,任务的所有的信息都是不可能恢复的了,删除是完完全全删除了,里面的资源都被系统释放掉,但是挂起任务就不会这样子,调用挂起任务函数,仅仅是将任务进入挂起态,其内部的资源都会保留下来,同时也不会参与系统中任务的调度,当调用恢复函数的时候,整个任务立即从挂起态进入就绪态,并且参与任务的调度。
②任务恢复函数 OSTaskResume()
既然有任务的挂起,那么当然一样有恢复,不然任务怎么恢复呢,任务恢复就是让挂起的任务重新进入就绪状态,恢复的任务会保留挂起前的状态信息,在恢复的时候根据挂起时的状态继续运行。
③删除任务函数 OSTaskDel()
OSTaskDel()用于删除一个任务。当一个任务删除另外一个任务时,形参为要删除任务创建时返回的任务句柄,如果是删除自身,则形参为 NULL。
④任务延时函数
OSTimeDly()
OSTimeDlyHMSM()
总结:需要初步掌握任务创建的格式,输入参数的含义,以及调用函数来管理这些任务,比如将任务挂起、恢复、删除等等。另外还需注意一下中断服务函数是一种需要特别注意的上下文环境,它运行在非任务的执行环境下(一般为芯片的一种特殊运行模式(也被称作特权模式)),在这个上下文环境中不能使用挂起当前任务的操作,不允许调用任何会阻塞运行的 API 函数接口。
*注:部分资料参考自[野火]《uCOS-III内核实现与应用开发实战指南》