ostaskcreate(ostaskcreatext)

zhangyang 2022-05-03 阅读:20
  

  1)实验平台:点状原子先锋的FPGA开发板

  2)摘自《开拓者 Nios II开发指南》关注官方微信号微信官方账号获取更多信息:守时原子。

  3)全套实验源代码手册视频下载地址:http://www.openedv.com/docs/index.html

正点原子开拓者Nios  II资料连载第17章uC/OSII任务管理与时间管理

  第十七章uC/OSII任务管理与时间管理

  在前一章中,我们介绍了uCOSII系统以及uCOSII系统的创建方法。让我们学习这一章。

  uCOSII系统中的两个重要概念,uCOSII系统中的任务管理和时间管理。本章包括以下部分:

  17.1任务管理和时间管理介绍

  17.2实验任务

  17.3硬件设计

  17.4软件设计

  17.5下载验证

  任务管理和时间管理简介

  任务管理

  uCOSII系统的主要工作是管理和调度任务,那么什么是任务呢?

  生活中,我们在处理一个大问题的时候,通常会分而治之,把大问题分成几个部分2。

  小问题,小问题逐步解决,大问题相应解决。那么这些小问题也算是很多了。

  一个小任务。

  当我们设计复杂而庞大的程序时,将这些负责任的程序分成许多简单的程序,也是如此。

  程序,这些小程序都是单个任务,所有小任务协调工作,最后完成复杂的功能。生效

  系统中的这些小任务可以并发执行,从而提高了CPU的效率。

  UCOSII是一个可剥夺的多任务系统。我们使用uCOSII的一个重要原因是它的多任务性。

  处理能力。在uCOSII中,任务是程序实体,uCOSII可以管理和调度这些小任务(程序)。

  uCOSII中的任务由三部分组成:任务栈、任务控制块和任务程序代码(任务函数),如

  如图17.1.1所示:

正点原子开拓者Nios  II资料连载第17章uC/OSII任务管理与时间管理

  图17.1.1任务的组成

  任务控制块:用于记录堆栈指针、当前状态、优先级和其他与任务管理相关的属性。

  性别表被称为任务控制块。任务控制块相当于任务的身份证,系统使用任务控制块

  并且没有任务控制块的任务不能被系统识别和管理。

  任务堆栈:当任务切换并响应中断时,CPU寄存器的内容被保存,任务调用其他函数。

  每个任务都有一个独立的任务堆栈。

  任务编码:指任务的执行程序。

  一个任务如何切换回上一个任务,从上次中断的地方继续运行?还原现场

  也就是说,该站点是CPU的内部寄存器。因此,当创建一个新任务时,系统必须启动该任务。

  所需CPU寄存器的初始值预先存储在任务堆栈中。当这样的任务获得使用CPU的权利时,它将被分配为

  堆栈的内容被复制到CPU的寄存器中,这样任务就可以顺利启动和运行。

  将任务的初始数据存入任务栈的工作称为任务栈的初始化,用户一般不会直接操作。

  初始化函数,任务栈初始化函数由任务创建函数OSTaskCreateExt调用。

  接下来,我们来介绍一下uCOSII系统的任务状态。uCOSII的每个任务都是一个无限循环,每个任务

  它们处于以下五种状态之一:睡眠状态、就绪状态、运行状态和等待状态。

  (等待事件发生)并中断服务状态。

  休眠状态:当任务没有配备任务控制块或被剥夺任务控制块时的状态。

  您可以通过调用OSTaskDel()函数使任务休眠。您也可以使用OSTaskCreate()或

  OSTaskCreateExt()函数用于设置任务,以便任务可以运行。

  就绪:系统为该任务配备了一个任务控制块,并登记在任务就绪表中。

  任务准备好了,但是暂时不能运行,因为它的优先级低于正在运行的任务。

  任务此时的状态称为就绪状态。

  运行状态:任务获得了CPU的使用权,正在运行。此时的任务状态称为正在运行。

  状态。

  等待状态(

WAITING):正在运行的任务,需要等待一段时间或需要等待一个事件发生再

  运行时,该任务就会把CPU的使用权让给别的任务而使任务进入等待状态。

  中断服务状态(ISR):一个正在运行的任务一旦响应中断申请就会中止运行而去执行中

  断服务程序,这时任务的状态叫做中断服务状态。

  uCOSII任务的5个状态转换关系如图 17.1.2所示:

正点原子开拓者Nios II资料连载第17章uC/OSII任务管理与时间管理

  图 17.1.2 uCOSII任务状态转换关系

  uCOSII的各个状态可以通过函数进行切换,下面是具体包含函数的状态转换图:

正点原子开拓者Nios II资料连载第17章uC/OSII任务管理与时间管理

  

  图 17.1.3 包含函数的状态转换图

  在多任务系统中,令CPU中止当前正在运行的任务转而去运行另一个任务的工作叫做任务切换,而按某种规则进行任务切换的工作就叫做任务调度。uCOSII的任务调度策略非常简单,

  它只需要检查等待列表中各任务的优先级,谁的优先级高就运行谁。

  这种简单的任务调度策略,虽然可以节省嵌入式系统的资源,但同时也会带来一些问题,

  比如说:如果一个高优先级的任务一直占用CPU,那么低优先级的任务将一直等待,因此我们

  应该合理地分配任务的优先级。

  当有多个任务处于就绪状态时,系统需要在这些任务中选择一个来运行。就绪任务有多个,

  CPU却有一个,所以CPU需要一个规则来进行选择。uCOSII采用优先级抢占规则。系统中的每一

  个任务根据其重要性都配有一个唯一的优先级(uCOSII中,每一个优先级只能有一个任务),优

  先级高的任务先得到执行,优先级低的任务后执行。(数值越小优先级越高)。

  uCOSII中的任务分为两种:系统任务和用户任务;系统任务是指由系统提供并为系统管理

  服务的任务;我们一般可以不用管它。用户任务是指为了解决应用问题由用户编写的任务。

  uCOSII预定义了两个系统任务:空闲任务和统计任务。

  1、空闲任务:uCOSII必须创建的任务,此任务由uCOSII自动创建,不需要用户手动创建。

  2、统计任务:可选任务,用来统计CPU使用率和各个任务的堆栈使用量。此任务是可选任

  务,由宏OS_TASK_STAT_EN控制是否使用此任务。

  接下来,我们看看在uCOSII中,与任务相关的几个函数:

  1)建立任务函数(OSTaskCreateExt)

  如果想让uCOSII管理用户的任务,必须先建立任务。uCOSII给我们提供了2个建立任务的

  函数:OSTaskCreate和OSTaskCreateExt。建立任务函数已经在前一章节进行了讲解,详细讲

  解请查看前一章节的内容。

  2)删除任务函数(OSTaskDel)

  所谓的任务删除,其实就是把任务置于睡眠状态,并不是把任务代码给删除了。uCOSII提

  供的任务删除函数原型为:INT8U OSTaskDel(INT8U prio),其中参数prio就是我们要删除的

  任务的优先级,可见该函数是通过任务优先级来实现任务删除的。

  特别注意:任务不能随便删除,必须在确保被删除任务的资源被释放的前提下才能删除!

  3)请求任务删除函数(OSTaskDelReq)

  前面提到,必须确保被删除任务的资源被释放的前提下才能将其删除,所以我们通过向被

  删除任务发送删除请求,来实现任务释放自身占用资源后再删除。uCOSII提供的请求删除任务函数原型为:INT8U OSTaskDelReq(INT8U prio),同样还是通过优先级来确定被请求删除任务。

  4)改变任务的优先级函数(OSTaskChangePrio)

  uCOSII在建立任务时,会分配给任务一个优先级,但是这个优先级并不是一成不变的,而

  是可以通过调用uCOSII提供的函数修改。uCOSII提供的任务优先级修改函数原型为:INT8U

  OSTaskChangePrio(INT8U oldprio,INT8U newprio)。

  5)任务挂起函数

  任务挂起和任务删除有点类似,但是又有区别,任务挂起只是将被挂起任务的就绪标志删

  除,并做任务挂起记录,并没有将任务控制块任务控制块链表里面删除,也不需要释放其资源,

  而任务删除则必须先释放被删除任务的资源,并将被删除任务的任务控制块也给删了。被挂起

  的任务,在恢复(解挂)后可以继续运行。uCOSII提供的任务挂起函数原型为:INT8U

  OSTaskSuspend(INT8U prio)。

  6)任务恢复函数

  有任务挂起函数,就有任务恢复函数,通过该函数将被挂起的任务恢复,让调度器能够重

  新调度该函数。uCOSII提供的任务恢复函数原型为:INT8U OSTaskResume(INT8U prio)。

  更加详细的任务函数讲解,请参考邵贝贝老师的《嵌入式实时操作系统uCOS-II》一书的

  第四章。

  时间管理

  uCOSII中的任务是一个无限循环并且还是一个抢占式内核,为了使高优先级的任务不至于

  独占CPU,可以给其他优先级较低任务获取CPU使用权的机会,uCOSII中除空闲任务外的所有任

  务必须在合适的位置调用系统提供的延时函数,让当前的任务暂停运行一段时间并进行一个任

  务切换。

  uCOSII规定:除了空闲任务之外的所有任务,必须在任务中合适的位置调用系统提供的任

  务延时函数。

  延时函数使当前任务的运行延时一段时间并进行一次任务调度,以让出 CPU的使用权。该

  函数是以系统时钟节拍为基准的,如果系统时钟节拍延长或缩短了,任务的实际延时时间也跟

  着延长或缩短。

  在这里我们主要介绍五个与时钟节拍相关的系统服务:

  1)任务延时函数OSTimeDly()

  使用该函数后,任务可以延时一段时间(时间的长短由时钟节拍数决),也就是该任务会

  被挂起,并且开始执行处于就绪态中优先级最高的任务。当延时期满或者有别的任务使用

  OSTimeDlyResume()取消了延时,该任务就会立刻进入就绪状态。

  调用该延时函数时,使用的节拍数处于1到65535之间。当设置的节拍数为0时,表示不延

  时;每次时钟节拍发生的时候,OSTCBDly(任务延时挂起的时间)的值都会被减去一,当该值

  为0的时候,内核就会把任务放入就绪队列。

  2)按时分秒延时函数OSTimeDlyHMSM()

  使用OSTimeDlyHMSM()这个函数后,就可以以小时(H)、分(M)、秒(S)和毫秒(m)的形式来

  延时了,使用起来非常简单,其工作原理与OSTimeDly()一致,推荐使用OSTimeDlyHMSM()函数。

  3)让延时期的任务结束延时的函数OSTimeDlyResume()

  用户可以不用等待延时结束,通过使用OSTimeDlyResume()和要恢复的任务的优先级,来

  取消延时,进入就绪状态。

  4)得到系统时间函数OSTimeGet()

  用户调用OSStart()初始化多任务的时候,会有一个32位的计数器开始累加。随着时钟节

  拍的发生,计数器累计数到最大值的时候,会从零开始重新计数。使用OSTimeGet()能够获得

  该计数器的当前值。

  5)修改系统时间函数OSTimeSet()

  使用OSTimeSet()可以改变上面提到的计数器中的值。

  实验任务

  本节通过一个实例,让大家学习和掌握uCOSII系统的任务管理和时间管理功能。

  硬件设计

  Qsys系统搭建的步骤以及使用的IP核和“创建第一个uC/OSII系统”章节中完全一致,顶

  层模块代码除了模块名不一致外,其余也完全一致。如果大家有不明白的地方,可以参考“创

  建第一个uC/OSII系统”章节实验,这里不再赘述。

  软件设计

  uCOSII系统的创建可以参考“创建第一个uC/OSII系统”章节中的软件设计部分。创建完

  uCOSII系统之后,只需修改生成的代码,代码修改如下:

  1 #include <stdio.h>

  2 #include "includes.h"

  3

  4 void time_task(void* pdata);

  5 void CPUInfo_task(void* pdata);

  6

  7 /* Definition of Task Stacks */

  8 #define TASK_STACKSIZE 2048

  9 OS_STK start_stk[TASK_STACKSIZE];

  10 OS_STK time_stk[TASK_STACKSIZE];

  11 OS_STK CPUInfo_stk[TASK_STACKSIZE];

  12

  13 /* Definition of Task Priorities */

  14

  15 #define START_PRIORITY 100

  16 #define TIME_PRIORITY 101

  17 #define CPUINFO_PRIORITY 102

  18

  19 //开始任务

  20 void start_task(void* pdata)

  21 {

  22 OSTaskCreateExt(time_task,

  23 NULL,

  24 (void *)&time_stk[TASK_STACKSIZE-1],

  25 TIME_PRIORITY,

  26 TIME_PRIORITY,

  27 time_stk,

  28 TASK_STACKSIZE,

  29 NULL,

  30 0);

  31

  32

  33 OSTaskCreateExt(CPUInfo_task,

  34 NULL,

  35 (void *)&CPUInfo_stk[TASK_STACKSIZE-1],

  36 CPUINFO_PRIORITY,

  37 CPUINFO_PRIORITY,

  38 CPUInfo_stk,

  39 TASK_STACKSIZE,

  40 NULL,

  41 0);

  42

  43 OSTaskDel(START_PRIORITY);

  44 }

  45

  46 /* 获取系统时间 */

  47 void time_task(void* pdata)

  48 {

  49 while (1)

  50 {

  51 printf("The System Time is %d\n",OSTimeGet());

  52 OSTimeDlyHMSM(0, 0, 0, 500);

  53 }

  54 }

  55 /* 获取CPU使用率 */

  56 void CPUInfo_task(void* pdata)

  57 {

  58 while (1)

  59 {

  60 printf("The CPU Usage is %d\n",OSCPUUsage);

  61 OSTimeDlyHMSM(0, 0, 1, 0);

  62 }

  63 }

  64 /* 创建开始任务 */

  65 int main(void)

  66 {

  67 OSTaskCreateExt(start_task,

  68 NULL,

  69 (void *)&start_stk[TASK_STACKSIZE-1],

  70 START_PRIORITY,

  71 START_PRIORITY,

  72 start_stk,

  73 TASK_STACKSIZE,

  74 NULL,

  75 0);

  76

  77 OSStart();

  78 return 0;

  79 }

  首先main函数创建了一个开始任务(start_task),然后启动uCOSII系统。我们在前面说

  过,任务是一个无限的循环,由于开始任务只需要运行一次,因此开始任务不需要写成while(1)

  的形式。

  除了在main函数创建任务外,在任务中也可以创建任务,如代码的第19行至第44行所示。

  开始任务(start_task)实现的功能是创建了获取系统时间任务(time_task)和获取CPU使用

  率任务(CPUInfo_task)。获取系统时间的函数为OSTimeGet,获取CPU使用率的函数为

  OSCPUUsage,并通过printf函数打印出来;OSTimeDlyHMSM函数用于延时,并交出CPU的使用权,

  以便于其它准备就绪的任务获取CPU的使用权。

  下载验证

  接下来编译工程,稍等片刻后console界面会显示Build Finished,即编译成功,此时就

  可以下载程序了。开发板连接电源线和下载器,并打开电源开关。

  首先下载sof文件,然后下载elf文件。程序下载完成,就会看到Nios II Console界面如

  下图所示:

正点原子开拓者Nios II资料连载第17章uC/OSII任务管理与时间管理

  图 17.5.1 Nios II Console界面

  由打印结果可知,系统时间每500ms打印一次,CPU的使用率每一秒钟打印一次。需要说明

  的是,打印的系统时间不一定从0开始的,可能会有些偏差,这个是正常的。

评论(0)

二维码