UCOS-II任务设计

UCOS-II任务设计

任务函数的结构:

在用户任务函数中,必须包含至少一次对操作系统服务函数的调用,否则比其优先级低的任务将无法得到运行的机会,这是用户任务与普通函数的明显区别。

任务函数按照执行方式分为三类:单次执行、周期执行、事件触发三类。

单次执行的任务:此类任务只执行一次,执行后就自行删除。

void MyTask (void *pdata) //单次执行的任务函数

{

进行准备工作的代码;

任务实体代码;

调用任务删除函数; //调用 OSTaskDel(OS_PRIO_SELF)

}

最常见的单次执行任务“启动任务”,启动任务的结构如下:

void main (void) //主函数

{

OSInit (); //初始化操作系统

OSTaskCreate(TaskStart,(void *)0,&TaskStartStk[TASK_STK_SIZE-1],1);//创建启动任务

OSStart (); //启动操作系统,开始对任务进行调度管理

}

void TaskStart(void *pdata) //启动任务

{

pdata = pdata;

系统硬件初始化; //时钟系统、中断系统、外设等等

创建各个任务; //如键盘任务、显示任务、采样任务、数据处理任务、打印任务等等

创建各种通信工具; //如信号量、消息邮箱、消息队列等等

OSTaskDel (OS_PRIO_SELF); //删除自己

}

注意:

为了保证“启动任务”能够连续运行,必须将“启动任务”的优先级选择为最高。否则,当“启动任务”创建一个优先级高于自己的任务时,刚刚创建的任务就会立即进入运行状态而与这个任务关联的其它任务可能还没有创建,它使用的通信工具也还没有创建,系统必然出错。

用创建任务的方式启动任务,比如通过键盘操作来启动串口通信发送数据。当键盘任务函数检测到发送按键被按下时调用OSTaskCreate来创建串口发送任务,此时串口发送任务被创建得以执行,当串口数据发送完成后串口发送任务自行调用OSTaskDel来删除自己。

采用“任务创建”的方式来启动任务,可以省略用通信手段触发任务的麻烦,还可以通过*pdata 来传递原始参数,使得每次启动任务时可以有不同的工作状态。

虽然用“创建任务”的方式来启动一个任务有以上方便之处,但每次启动任务都要调用“任务创建函数”,需要对“任务控制块”进行全面初始化,并对“任务控制块链表”和“任务就绪表”进行操作,比较耗时,故只适用于实时性要求不高的任务(如键盘操作启动的任务)。采用“创建任务”的方式来启动一个任务除了实时性差外,

还可能在任务自我删除后出现如下后遗症:

1、占用的共享资源尚未被释放,使其它需要使用该资源的任务不能运行。

2、通信关系的“上家”任务(或者ISR)发出的信号量或者消息被积压而得不到响应。

3、通信关系的“下家”任务因为得不到信号量或者消息而被遗弃(永远被挂起)。

4、可能留下未删除干净的废弃变量。

因此:

1、如果该任务使用了共享资源,必须在删除自我之前释放(如释放内存块,释放互斥资源(发送互斥信号量))

2、如果该任务有关联任务(或ISR),必须在自我删除之前将这种关联解除,而解除关联关系任务和通信工具,这是得不偿失而又非常麻烦的事情。

适合采用“创建任务”的方式来启动的任务,通常是“孤立任务”,它们不和其它任务进行通信( ISR 除外),只使用共享资源来获取信息和输出信息。如果不满足这个条件,应该采用下面两种任务函数机构,并在系统启动时创建好。

周期性执行的任务,其任务函数的结构如下:

void MyTask (void *pdata) //周期性执行的任务函数

{

进行准备工作的代码;

for (;;) //无限循环,也可用 while (1)

{

任务实体代码;

调用系统延时函数; //调用 OSTimeDly( )或 OSTimeDlyHMSM( )

}

}

通过合理设置调用 OSTimeDly( ) 或 OSTimeDlyHMSM( )时的参数值可以调整任务的执行周期。当任务执行周期远大于系统时钟节拍时,任务执行周期的相对误差比较小当任务执行周期只有几个时钟节拍时,相邻两次执行的间隔时间抖动不能忽视,任务的执行周期的相对误差比较大,只适用于对周期稳定性要求不高的任务(如键盘任务);当任务执行周期只有一个时钟节拍时,可将该任务的功能放到 OSTimeTickHook( )(时钟节拍函数中的钩子函数)中去执行;当任务执行周期小于一个时钟节拍或者不是时钟节拍的整数倍时,将无法使用延时函数对其进行周期控制,只能采用独立于操作系统的定时中断来触发。采用独立定时器触发的任务具有很高的周期稳定性。

事件触发执行的任务,其任务函数结构如下:

void MyTask (void *pdata) //事件触发执行的任务函数

{

进行准备工作的代码;

for (;;) //无限循环,也可用 while (1)

{

调用获取事件的函数; //如:等待信号量、等待邮箱中的消息等等。

任务实体代码;

}

}

任务的优先级安排:

任务的优先级资源由操作系统提供,以 μC/OS-II 为例,共有 64 个优先级,优先级的高

低按编号从 0(最高)到 63(最低)排序。由于用户实际使用到的优先级总个数通常远小于64,为节约系统资源,可以通过定义系统常量 OS_LOWEST_PRIO 的值来限制优先级编号的范围。

μC/OS-II 实时操作系统总是将最低优先级 OS_LOWEST_PRIO 分配给“空闲任务”,将

次低优先级 OS_LOWEST_PRIO-1 分配给“统计任务”。

μC/OS-II 实时操作系统还保留对最高的四个优先级( 0、 1、 2、 3)和 OS_LOWEST_PRIO

-3 与 OS_LOWEST_PRIO-2 的使用权。

UCOS-II中这些优先级是操作系统保留的:

0、1、2、3、OS_LOWEST_PRIO、OS_LOWEST_PRIO-1、OS_LOWEST_PRIO-2、OS_LOWEST_PRIO-3

优先级安排原则:
中断关联性:与中断服务程序( ISR)有关联的任务应该安排尽可能高的优先级,以便及时处理异步事件,提高系统的实时性。如果优先级安排得比较低, CPU 有可能被优先级高一些的任务长期占用,以致于在第二次中断发生时连第一次中断还没有处理,产生信号丢失现象。

紧迫性:因为紧迫任务对响应时间有严格要求,在所有紧迫任务中,按响应时间要

求排序,越紧迫的任务安排的优先级越高。紧迫任务通常与 ISR 关联。

关键性:任务越关键安排的优先级越高,以保障其执行机会。

频繁性:对于周期性任务,执行越频繁,则周期越短,允许耽误的时间也越短,故应该安排的优先级也越高,以保障及时得到执行。

快捷性:在前面各项条件相近时,越快捷(耗时短)的任务安排的优先级越高,以使其他就绪任务的延时缩短

与其他任务协调:

一个任务的功能往往需要其它任务配合才能完成。在没有操作系统的传统的编程模式下,只要直接调用这些模块就可以了。在操作系统的管理下,不允许任务之间相互调用,必须采用操作系统提供的同步和通信机制来进行任务之间的协调运行。

UCOS-II任务设计


任务函数的结构:
在用户任务函数中,必须包含至少一次对操作系统服务函数的调用,否则比其优先级低的任务将无法得到运行的机会,这是用户任务与普通函数的明显区别。


任务函数按照执行方式分为三类:单次执行、周期执行、事件触发三类。


单次执行的任务:此类任务只执行一次,执行后就自行删除。
void MyTask (void *pdata) //单次执行的任务函数
{
  进行准备工作的代码;
  任务实体代码;
  调用任务删除函数; //调用 OSTaskDel(OS_PRIO_SELF)
}
最常见的单次执行任务“启动任务”,启动任务的结构如下:
void main (void) //主函数
{
  OSInit (); //初始化操作系统
  OSTaskCreate(TaskStart,(void *)0,&TaskStartStk[TASK_STK_SIZE-1],1);//创建启动任务
  OSStart (); //启动操作系统,开始对任务进行调度管理
}
void TaskStart(void *pdata) //启动任务
{
  pdata = pdata;
  系统硬件初始化; //时钟系统、中断系统、外设等等
  创建各个任务; //如键盘任务、显示任务、采样任务、数据处理任务、打印任务等等
  创建各种通信工具; //如信号量、消息邮箱、消息队列等等
  OSTaskDel (OS_PRIO_SELF); //删除自己
}
注意:
  为了保证“启动任务”能够连续运行,必须将“启动任务”的优先级选择为最高。否则,当“启动任务”创建一个优先级高于自己的任务时,刚刚创建的任务就会立即进入运行状态,而与这个任务关联的其它任务可能还没有创建,它使用的通信工具也还没有创建,系统必然出错。
  
  用创建任务的方式启动任务,比如通过键盘操作来启动串口通信发送数据。当键盘任务函数检测到发送按键被按下时调用OSTaskCreate来创建串口发送任务,此时串口发送任务被创建得以执行,当串口数据发送完成后串口发送任务自行调用OSTaskDel来删除自己。
  
采用“任务创建”的方式来启动任务,可以省略用通信手段触发任务的麻烦,还可以通过*pdata 来传递原始参数,使得每次启动任务时可以有不同的工作状态。


虽然用“创建任务”的方式来启动一个任务有以上方便之处,但每次启动任务都要调用“任务创建函数”,需要对“任务控制块”进行全面初始化,并对“任务控制块链表”和“任务就绪表”进行操作,比较耗时,故只适用于实时性要求不高的任务(如键盘操作启动的任务)。采用“创建任务”的方式来启动一个任务除了实时性差外,
还可能在任务自我删除后出现如下后遗症:


占用的共享资源尚未被释放,使其它需要使用该资源的任务不能运行。
通信关系的“上家”任务(或者ISR)发出的信号量或者消息被积压而得不到响应。
通信关系的“下家”任务因为得不到信号量或者消息而被遗弃(永远被挂起)。
可能留下未删除干净的废弃变量。
因此:
如果该任务使用了共享资源,必须在删除自我之前释放(如释放内存块,释放互斥资源(发送互斥信号量))
如果该任务有关联任务(或ISR),必须在自我删除之前将这种关联解除,而解除关联关系任务和通信工具,这是得不偿失而又非常麻烦的事情。


适合采用“创建任务”的方式来启动的任务,通常是“孤立任务”,它们不和其它任务进行通信( ISR 除外),只使用共享资源来获取信息和输出信息。如果不满足这个条件,应该采用下面两种任务函数机构,并在系统启动时创建好。




周期性执行的任务,其任务函数的结构如下:
void MyTask (void *pdata) //周期性执行的任务函数
{
  进行准备工作的代码;
  for (;;) //无限循环,也可用 while (1)
  {
  任务实体代码;
  调用系统延时函数; //调用 OSTimeDly( )或 OSTimeDlyHMSM( )
  }
}


通过合理设置调用 OSTimeDly( ) 或 OSTimeDlyHMSM( )时的参数值可以调整任务的执行周期。当任务执行周期远大于系统时钟节拍时,任务执行周期的相对误差比较小;当任务执行周期只有几个时钟节拍时,相邻两次执行的间隔时间抖动不能忽视,任务的执行周期的相对误差比较大,只适用于对周期稳定性要求不高的任务(如键盘任务);当任务执行周期只有一个时钟节拍时,可将该任务的功能放到 OSTimeTickHook( )(时钟节拍函数中的钩子函数)中去执行;当任务执行周期小于一个时钟节拍或者不是时钟节拍的整数倍时,将无法使用延时函数对其进行周期控制,只能采用独立于操作系统的定时中断来触发。采用独立定时器触发的任务具有很高的周期稳定性。


事件触发执行的任务,其任务函数结构如下:
void MyTask (void *pdata) //事件触发执行的任务函数
{
  进行准备工作的代码;
  for (;;) //无限循环,也可用 while (1)
  {
  调用获取事件的函数; //如:等待信号量、等待邮箱中的消息等等。
  任务实体代码;
  }
}


任务的优先级安排:
任务的优先级资源由操作系统提供,以 μC/OS-II 为例,共有 64 个优先级,优先级的高
低按编号从 0(最高)到 63(最低)排序。由于用户实际使用到的优先级总个数通常远小于64,为节约系统资源,可以通过定义系统常量 OS_LOWEST_PRIO 的值来限制优先级编号的范围。
μC/OS-II 实时操作系统总是将最低优先级 OS_LOWEST_PRIO 分配给“空闲任务”,将
次低优先级 OS_LOWEST_PRIO-1 分配给“统计任务”。
μC/OS-II 实时操作系统还保留对最高的四个优先级( 0、 1、 2、 3)和 OS_LOWEST_PRIO
-3 与 OS_LOWEST_PRIO-2 的使用权。
即UCOS-II中这些优先级是操作系统保留的:
0、1、2、3、OS_LOWEST_PRIO、OS_LOWEST_PRIO-1、OS_LOWEST_PRIO-2、OS_LOWEST_PRIO-3


优先级安排原则:中断关联性:与中断服务程序( ISR)有关联的任务应该安排尽可能高的优先级,以便及时处理异步事件,提高系统的实时性。如果优先级安排得比较低, CPU 有可能被优先级高一些的任务长期占用,以致于在第二次中断发生时连第一次中断还没有处理,产生信号丢失现象。


紧迫性:因为紧迫任务对响应时间有严格要求,在所有紧迫任务中,按响应时间要


求排序,越紧迫的任务安排的优先级越高。紧迫任务通常与 ISR 关联。


关键性:任务越关键安排的优先级越高,以保障其执行机会。


频繁性:对于周期性任务,执行越频繁,则周期越短,允许耽误的时间也越短,故应该安排的优先级也越高,以保障及时得到执行。


快捷性:在前面各项条件相近时,越快捷(耗时短)的任务安排的优先级越高,以使其他就绪任务的延时缩短


与其他任务协调:
一个任务的功能往往需要其它任务配合才能完成。在没有操作系统的传统的编程模式下,只要直接调用这些模块就可以了。在操作系统的管理下,不允许任务之间相互调用,必须采用操作系统提供的同步和通信机制来进行任务之间的协调运行。

你可能感兴趣的:(UCOS)