uCOSIII以一系列函数的形式为应用程序代码提供服务。用户通过调用这些函数可以完成各种操作。uCOSIII提供的服务函数可以管理信号量、消息队列、互斥信号量等。对于应用程序的开发来说,调用uCOSIII提供的函数和其他函数是完全一样的;换言之,应用程序通过访问一个包含大约70个新函数的函数库就可以使用uCOSIII。
1、单任务的应用程序
一个简单的文件名为app.c的应用程序。其第一部分内容如程序清单
/*
************************************************************************
* INCLUDE FILES
************************************************************************
*/
#include<app_cfg.h> (1)
#include<bsp.h>
#include<os.h>
/*
************************************************************************
* LOCAL GLOBAL VARIABLES
************************************************************************
*/
static OS_TCB AppTaskStartTCB; (2)
static CPU_STK AppTaskStartStk{APP_TASK_START_STK_SIZE]; (3)
/*
************************************************************************
* FUNCTION PROTOTYPES
************************************************************************
*/
static void AppTaskStart(void * p_arg); (4)
(1) 与其它C程序一样,用户在应用程序开头须包含必要的头文件。app_cfg.h是配置应用程序的头文件。
在我们的范例中,app_cfg.h头文件中有一些用#define语句定义的常量,用来设定任务的优先级、栈空间的大小和其他一些应用相关的参数。
bsp.h是板级支持包的头文件,提供一些宏定义以及BSP_Init(),BSP_LED_On()和OS_TS_GET()等函数的原型声明。
os.h是uCOSIII的主头文件,它包含以下头文件:
os_cfg.h;
cpu.h;
cpu_core.h;
lib_def.h;
os_type.h;
os_cpu.h。
(2) 在创建一个任务时,必须为该任务分配一个任务控制块(OS_TCB)。OS_TCB数据类型的介绍见“任务管理”。
(3) 每一个任务都要有属于自己的栈。任务栈空间可以静态分配,如本例所示;也可以使用malloc()函数从堆中动态分配。由于任务不会退出,所以栈会一直处于使用状态,栈空间不需要释放。
(4) 拟创建任务的函数原型声明。
大多数C应用程序都从main()函数开始,如程序所示:
void main(void)
{
OS_ERR err;
BSP_IntDisAll(); (1)
OSInit(&err); (2)
if(err != OS_ERR_NONE)
{
/*Something didn't get initialized correctly... */
/*...Check os.h for the meaning of the err code,see OS_ERR_xxxx */
}
OSTaskCreat((OS_TCB *)&AppTaskStartTCB, (3)
(CPU_CHAR *)"App Task Start", (4)
(OS_TASK_PTR )AppTaskStart, (5)
(void *)0, (6)
(OS_PRIO )APP_TASK_START_PRIO, (7)
(CPU_STK *)&AppTaskStartStk[0], (8)
(CPU_STK_SIZE)APP_TASK_START_STK_SIZE / 10, (9)
(CPU_STK_SIZE)APP_TASK_START_STK_SIZE, (10)
(OS_MSG_QTY )0,
(OS_TICK )0,
(void *)0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (11)
(OS_ERR *)&err); (12)
if(err != OS_ERR_NONE)
{
/* The task didn't get created. Lookup the value of the error code... */
/* ... in os.h for the meaning for the error */
}
OSStart(&err); (13)
if(err != OS_ERR_NONE)
{
/* Your code is NEVER supposed to come back to this point. */
}
}
(1)编译生成的启动代码引导CPU从main()函数开始运行。然后,main()函数会调用BSP函数关闭所有中断。大多数处理器最初启动时中断是关闭的,直到应用程序开中断。不过为了安全起见,这里关一次所有外部中断,确保在系统启动期间中断是关闭的。
(2)调用OSInit()函数初始化uCOSIII。OSInit()会初始化uCOSIII的内部变量和数据结构,并会创建2~5个系统任务。uCOSIII至少需要创建2个系统任务:空闲任务(OS_IdelTask())和时钟节拍任务。空闲任务会在其它任务都不就绪的时候运行。时钟节拍任务负责时间管理。根据#define语句定义常量值,uCOSIII可能还会创建统计任务(OS_StatTask)、定时任务(OS_TmrTask())和中断处理队列管理任务(OS_IntQTask())。详情将在介绍任务管理时讨论。
大多数uCOSIII函数通过一个指向OS_ERR变量的指针返回一个错误码,在本例中该变量为err。如果OSInit()成功返回,则err为OS_ERR_NONE。如果在初始化中OSInit()出错了,则该函数会在检测到错误后立即返回对应的错误类型码。这种情况下,用户可以在os.h文件中查到错误代码的含义。所有的错误类型码都以OS_ERR_为前缀。
main()函数必须在调用其他任何uCOSIII函数之前调用OSInit(),这一点极为重要,需要特别注意。
(3)用户可通过调用OSTaskCreat()函数创建一个任务。此函数包含14个参数。第1个参数为分配给该任务的任务控制块(OS_TCB)的地址。
(4)调用OSTaskCreat()时,可以给任务创建一个名字。系统在任务控制块中放置了一个指向任务名称的指针。任务名可以由任意个ASCII字符构成。
(5)第3个参数是任务代码的起始地址。典型的任务是一个无限循环。
void MyTask(void *p_arg)
{
/* Do sonething with "p_arg". */
while(1)
{
/* Task body */
}
}
任务开始运行时可接受一个参数。就任务函数而言,看起来和其他可以在程序中调用的C函数没有什么不同。然而,用户程序不允许调用MyTask(),调用实际上是通过uCOSIII实现的。
(6)OSTaskCraet()的第4个参数是任务第一次运行时会接收到的参数,即MyTask()的p_arg。本例中,传递的是一个NULL指针,因此AppTaskStart()的p_arg就是一个NULL指针。
传递给任务的参数实际上可以是任意类型的指针。例如,用户可以向任务传递一个指向特定数据结构的指针,该数据结构包含所有需要的参数。
(7)下一个传递给OSTaskCreat()的参数是任务优先级。在应用中,优先级确立了每一个任务相对于其它任务的重要性。数值小的数字代表更高的优先级,或者说更重要的任务。任务的优先级可以设置为1和OS_CFG_PRIO_MAX-2之间的任意数值,含1和OS_CFG_PRIO_MAX-2。要避免使用0和OS_CFG_PRIO_MAX-1,因为这两个优先级是系统的保留优先级。OS_CFG_PRIO_MAX在os_cfg.h中声明,它是一个编译配置常量。
(8)传递给OSTaskCreat()的第6个参数是分配给该任务的栈空间的基地址。基地址总是栈空间的最低地址。
(9)这个参数是该任务栈的深度标记,该尝试标记定义了该任务可用的栈空间深度,该参数的值代表了栈溢出警告之前栈内应该剩余的空间大小,以CPU_STK为单位。换言之,在本例中,当剩余栈空间小于任务栈空间的10%时,就达到了栈的极限深度。
(10)第8个传递的参数定义该任务的栈大小,以CPU_STK的数目(不是byte)表示。例如,若CPU_STK是32位的字(word),用户想分配1kb的栈空间给任务,那么传递的参数应该为256(256 X 4 = 1024byte = 1kb)。
(11)此参数定义任务的可选项。在本例中,我们指定的选项表示系统在运行时要检查任务栈的使用情况,并且在创建任务时要将栈空间全部清零。
(12)最后一个参数指向一个接收错误码的变量。同样的错误码的解释也在os.h中定义。
(13)main()函数的最后一步是调用OSStart(),开始多任务系统的管理。应该特别注意的是,uCOSIII会首先运行在调用OSStart()之前已经创建的优先级最高的任务。
用户要注意,如果已在os_cfg.h中使能OS_IntQTask(),(通过OS_CFG_ISR_POST_DEFERRED_EN常量),那么该任务永远是优先级最高的任务。在这种情况下,OSIntQTask()会先初始化自己,然后uCOSIII会切换到下一个已创建的最重要的任务。
有几个需要关注的点,虽然用户可以在调用OSStart()之前创建任意数量的任务,但是,建议先只创建一个任务,如本例所示。因为只有唯一一个应用任务使得uCOSIII可以确定CPU相对速度。这样,就使uCOSIII可以在系统运行时确定CPU的利用率。同样,如果应用程序需要使用其他内核对象,如信号量
消息队列,那么建议在调用OSSTart()之前就创建它们。最后要注意,此时中断还没有开启。下面将通过分析AppTaskStart()的内容详细讨论这些要点,如程序清单所示。
static void AppTaskStart(void * p_arg) (1)
{
OS_ERR err;
p_arg = p_arg;
BSP_Init(); (2)
CPU_Init(); (3)
BSP_Cfg_Tick(); (4)
BSP_LED_Off(0);
while(1)
{
BSP_LED_Toggle(0);
OSTimeDlyHMSM((CPU_INT16U)0,
(CPU_INT16U)0,
(CPU_INT16U)0,
(CPU_INT32U)100,
(OS_OPT)OS_OPT_TIME_HMSM_STRICT,
(OS_ERR *)&err);
/* Check for 'err' */
}
}
(1)如先前提到的,任务实际上就是一个函数。参数p_arg由OSTaskCreate()传递给AppTaskStart()。
(2)BSP_Init()是一个板级支持包函数,负责初始化评估板或目标板上的硬件。评估板上可能有需要配置的通用输入输出接口,继电器和传感器等。该函数可以在bsp.c这个文件中找到。
(3)CPU_Init()初始化uCOSIII服务,uCOSIII提供测量中断延迟时间、获取时间戳等服务,在使用的处理器没有计算前导零指令的情况下,还会提供该指令的仿真代码。
(4)BSP_Cfg_Tick()建立uCOSIII时钟节拍中断。该函数初始化一个硬件定时器,使之产生一个频率为OSCfg_TickRate_Hz的中断给CPU。OSCfg_TickRate_Hz在os_cfg_app.h文件中定义(见OS_CFG_TICK_RATE_HZ)。

本文介绍了嵌入式实时操作系统uCOSIII的使用,包括如何初始化系统、创建任务以及任务管理。通过示例代码解析了如何调用OSInit()、OSTaskCreate()等函数来初始化系统并创建任务。同时,强调了中断管理和任务栈的配置,为后续的嵌入式应用程序开发打下基础。
241

被折叠的 条评论
为什么被折叠?



