版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、嵌入式操作系统嵌入式操作系统第三章第三章 C/OS-II中的任务中的任务2第第3章章 C/OS-II中的任务中的任务本部分的主要内容包括: 任务的基本概念 任务代码、任务控制块和任务堆栈 任务的优先权 任务就绪表结构及其操作 任务切换及任务调度 任务的创建、删除、挂起、恢复和查询 C/OS-II的初始化和启动33.1 3.1 任务的基本概念任务的基本概念3.1.1 任务及其内存结构 在设计一个较为复杂的应用程序时,通常把一个大型任务分解成多个小任务,然后在计算机中通过运行这些小任务,最终达到完成大任务的目的。实时应用程序的设计过程包括如何把问题分割成多个任务。每个任务都是整个应用程序的一部分,
2、都被赋予一定的优先级,有自己的一套CPU寄存器和栈空间。由于这种方法可以使系统并发地运行多个任务,从而提高处理器的利用率,加快程序的执行速度,因此现代操作系统几乎都是多任务操作系统。 4 一个任务,也称作一个线程,是一个简单的程序,与大任务分割成的小任务对应的程序实体就叫做“任务”,而C/OS-II就是一个能对这些小任务的运行进行管理和调度的多任务操作系统。 从代码上看,C/OS-II的任务就是一个函数。而从任务的存储结构上看,C/OS-II的任务由三个部分组成:任务程序代码(函数)、任务堆栈和任务控制块。其中任务控制块就是关联了任务代码的程序控制块(TCB),它记录了任务的各个属性;任务堆栈
3、则用来保存任务的工作环境;任务程序代码就是任务的执行部分。 5PC6 C/OS-II任务控制块实质上就是2.4.2节中所介绍的具有二级结构的代码控制块,只不过用来指向代码的指针是CPU程序指针(程序计数器)PC的副本。系统可以根据任务控制块来了解代码的相关信息,当然也就是能够找到代码。 注:任务控制块通过任务堆栈和任务代码注:任务控制块通过任务堆栈和任务代码间接的关联起来间接的关联起来7 C/OS-II用任务控制块链表对任务进行管理,如下图所示:8 C/OS-II的任务有两种:用户任务和系统任务。由应用程序设计者编写的任务,叫做用户任务;由系统提供的任务叫做系统任务。用户任务是为了解决应用问题
4、而编写的;系统任务是为应用程序提供某种服务或为系统本身服务的。目前,在C/OS-II中,最多可以含有64个任务(包括用户任务和系统任务)。 9 C/OS II 支持64个任务,每个任务有一个特定的优先级。 任务的优先级别用数字表示,0表示的任务的优先级最高,数字越大表示的优先级越低。 通过常数OS_LOWEST_PRIO (在OS_CFG.H中)定义系统的最低优先级别,同时限定系统能容纳的最多任务数量。 建议用户不要使用优先级为0、1、2、3、OS_LOWEST_PRIO-3、 OS_LOWEST_PRIO-2、 OS_LOWEST_PRIO-1、 OS_LOWEST_PRIO-0的任务。最低
5、的两个已被目前版本的系统占用,将来版本可能会用到其它的。 103.1.2 任务的状态 C/OS-II是按照系统中只有一个CPU来设计的,在这种系统中,一个具体时刻只会有一个任务占用,及处在运行状态,而其他任务只能处在其他状态。C/OS-II系统中的任务共有5种状态: 睡眠态(睡眠态(DORMANT):任务在没有被配备任务控制块或被剥夺了任务控制块时的状态叫作任务的睡眠态。 就绪态(就绪态(READY):如果系统为任务配备了任务控制块且在任务就绪表中进行了就绪登记,则任务就具备了运行的充分条件,这时的任务的状态叫就绪态。11 运行态(运行态(RUNNING):):处于就绪态的任务如果经调度器判断
6、获得了CPU的使用权,则任务就进入运行态。任何时刻只能有一个任务处于运行态。 等待态(等待态(WAITING):):正在运行的任务,需要等待一段时间或需要等待一个事件发生再运行时,该任务就会把CPU的使用权让给其他任务而使任务进入waiting状态。 注:进入waiting的状态有可能是因为延时,有可能是被挂起,有可能是等待的资源未获得,总之,uC/OS将所有的已经注册了的但未就绪的任务归为waiting态。 被中断态(被中断态(ISR):):正在运行的任务是可以被中断的,除非该任务将中断关了,或者uC/OS-将中断关了。被中断了的任务就进入了中断服务态(ISR)。 当所有的任务都在等待事件发
7、生或等待延迟时间结束,uC/OS-执行空闲任务(idle task),执行OSTaskIdle() 函数。 12 在系统的管理下,一个任务可以在5个不同的状态之间发生转换。其转换关系如图所示 13 线上的函数作用:状态迁移依靠这些函数完成143.1.3 用户任务代码的一般结构 1. 用户任务代码的一般结构 根据嵌入式系统任务的工作特点,任务的执行代码通常是一个无限循环结构(对于一些一次性任务例外),并且在这个循环中可以响应中断,这种结构也叫做超循环结构。例3-1就是一个具有超循环结构的任务的示意性代码。 15 例3-1 一个用C语言编写的任务 void MyTask(void * pdata)
8、 for( ; ; )可以被中断的用户代码;OS_ENTER_CRITICAL();/进入临界段(关中断)不可以被中断的用户代码;OS_EXIT_CRITICAL();/退出临界段(开中断)可以被中断的用户代码; 从程序的角度来看,一个C/OS-II任务的代码就是一个C语言函数。之所以把任务的参数定义成一个void类型的指针,是为了传递各种不同类型的数据。16 为了有效的对中断进行控制,在任务的代码里可使用uC/OS-II定义的宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来控制何时响应中断,何时屏蔽中断。这两个宏之间的代码时是不会响应中断的,这种受保护的代码段
9、叫临界段。 代码的临界段也称为临界区,指处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断打入。为确保临界段代码的执行不被中断,在进入临界段之前必须关中断,而临界段代码执行完后,要立即开中断。 17 2用户应用程序的一般结构 从程序代码来看,用户任务就是一个C语言函数,但这个函数不是自主函数main()调用的函数,在系统中它与主函数main()处于平等的地位,它们何时被运行以及何时被终止是由操作系统来调度的。但要注意,main()毕竟是一个应用程序的主函数,是程序运行的入口点,所以虽然它不调用任务,但要负责任务的创建并将它们交给系统,至于何时运行它们,则与主函数无关。 18 用户应
10、用程序的代码大体如下: 例3-2 用户应用程序的结构 void MyTask1(void * pdata)/定义用户任务定义用户任务1 for( ; ; ) void MyTask2(void * pdata)/定义用户任务定义用户任务2 for( ; ; ) 19void MyTask3(void * pdata)/定定义义用用户户任任务务3for( ; ; )void main()OSInit();/初始化初始化 C/OS-IIOSTaskCreate(MyTask1,);/创创建用建用户户任任务务1OSTaskCreate(MyTask2,);/创创建用建用户户任任务务2OSTaskCr
11、eate(MyTask3,);/创创建用建用户户任任务务3OSStart();/启动启动 C/OS-II20 其中,OSTaskCreate()是C/OS-II提供的用来创建任务的函数;OSStart()启动C/OS-II的函数。系统被启动后,任务就由操作系统来管理和调度了。 213.1.4 系统任务 作为管理者,操作系统除了要管理用户任务之外,可能会有一些内部事务需要处理,最起码要有一个没有用户任务可执行时需要做的事情,因为计算机是不能停下来的。为了与用户任务相区别,这种系统自己所需要的任务叫做系统任务。C/OS-II预定义了两个系统任务:空闲任务和统计任务。其中空闲任务是每个应用程序必须使
12、用的,而统计任务则是应用程序可以根据实际需要来选择使用的。 22 1. 空闲任务 C/OS-II总要建立一个空闲任务(idle task),这个任务在没有其他任务进入就绪状态时投入运行。这个空闲任务OSTaskIdle()永远设为最低优先级,即OS_LOWER_PRIO。空闲任务OSTaskIdle()的代码如下: void OSTaskIdle( void * pdata) pdata = pdata; /防止某些编译器报错 for(;) OS_ENTER_CRITICAL(); /关闭中断 OSIdleCtr+; /计数 OS_EXIT_CRITICAL(); /开放中断 C/OS-II规
13、定,一个用户应用程序必须使用这个空闲任务,而且这个任务是不能用程序来删除的。23 2统计任务 C/OS-II提供的另一个系统任务就是统计任务OSTaskStat( ) OSTaskStat( )每秒运行1次,计算CPU利用率,即告诉用户应用程序使用了多少CPU时间,用百分比表示,精确度为1%。 如果将系统头文件OS_CFG.H中的系统配置常数OS_TASK_STAT_EN设置为1,统计任务就会在操作系统初始化函数OSInit( )中调用OS_InitTaskStat()函数创建创建。24 在系统调用多任务启动函数OSStart( )之前,用户初始代码中必须先建立至少一个用户任务(如TaskSt
14、art),如果应用程序打算使用统计任务,需要在TaskStart任务中调用函数 OSStatInit( )对统计任务进行初始化初始化。之后再建立应用程序中的其他任务。 应该在用户任务中(第一个任务)启动时钟节拍。因为用户不希望在多任务还没有开始时就收到时钟节拍中断25void main (void)OSInit(); /初初 始化始化uC/OS-II /* 创建用户起始任务创建用户起始任务(以以TaskStart()作为起始任务,也可以创建多个任务作为起始任务,也可以创建多个任务)*/OSStart(); /开开 始多任务调度始多任务调度void TaskStart (void *pdata)
15、/* 在这里安装并启动在这里安装并启动uC/OS-II的时钟节拍的时钟节拍 */OSStatInit(); / 初始化统计任务初始化统计任务 /* 创建用户应用程序任务创建用户应用程序任务 */for (;) /* 这里是这里是TaskStart()的代码的代码 */ OSTimeDly(10); /调用该函数的任务将自己延时调用该函数的任务将自己延时1010个时钟并执行一次任务调度个时钟并执行一次任务调度 263.1.5 任务的优先权及优先级别 uC/OS-II分为64个优先级别,每一个级别都用一个数字表示。数字0的级别最高,数字越大优先级别越低。 通常,一个应用程序的任务数小于64,用户可
16、根据应用程序的需要,在OS_CFG.H中设置OS_LOWEST_PRIO,即定义了可供使用的优先级别共OS_LOWEST_PRIO +1个。 固定地,系统总是把最低优先级别自动赋给空闲任务,如果系统中还有统计任务,则其优先级别为OS_LOWEST_PRIO -1。因此用户任务可以使用的优先级别是0,1,2,.,OS_LOWEST_PRIO-2,共OS_LOWEST_PRIO-1个 27 例:如果希望应用程序中任务的优先级别为28个,则表示最低优先级别的常数OS_LOWEST_PRIO值应该是多少?如果应用程序中使用了系统提供的空闲任务和统计任务,则该应用程序最多可以安排多少个任务? 28 答:
17、表示最低优先级别的常数OS_LOWEST_PRIO值应该为27,优先级别分别为0,1,2,3,.,27;由于系统空闲任务占用了优先级别27,统计任务占用了优先级别26,则应用程序中最多可以安排优先级别分别为0,1,2,.,25的26个任务。29 给某一个用户任务的定义优先级别,需要在调用系统函数OSTaskCreate()来创建任务时,用该函数的第4个参数prio来指定。 由于每个任务都具有惟一的优先级别,因此C/OS-II通常也用任务的优先级别来作为这个任务的标识。 303.2 3.2 任务堆栈任务堆栈 任务堆栈是任务的重要组成部分。 所谓堆栈,就是在存储器中按数据“后进先出(LIFO)”的
18、原则组织的连续存储空间。为了满足任务切换和响应中断时保存CPU寄存器中的内容及任务调用其他函数时的需要,每个任务都有自己的栈空间。所有C/OS-II任务的任务控制块中都含有一个指向该任务堆栈的指针。31 C/OS-II中堆栈的数据类型为为OS_STK,在文件OS_CPU.H中定义: typedef unsigned int OS_STK; /该类型长度为该类型长度为16位位 这样,在应用程序中定义任务堆栈的栈区就非常简单,即定义一个OS_STK类型的一个数组即可。例如:#define TASK_STK_SIZE 512 /定义堆栈的长度定义堆栈的长度(1024字节字节)OS_STK TaskS
19、tkTASK_STK_SIZE; /定义一个数组来作为任务堆栈定义一个数组来作为任务堆栈 当调用函数OSTaskCreate()来创建一个任务时,把数组的指针传递给函数OSTaskCreate()中的堆栈栈顶参数ptos,就可以把该数组与任务关联起来而成为该任务的任务堆栈。 32 例3-4 创建任务函数OSTaskCreate()的原型如下: INT8U OSTaskCreate( void (*task)(void *pd), /指向任务的指针指向任务的指针 void *pdata, /传递给任务的参数传递给任务的参数 OS_STK *ptos, /任务堆栈栈顶的指针任务堆栈栈顶的指针 IN
20、T8U prio ); /指定任务优先级别的参数指定任务优先级别的参数 ); 使用例3-1的代码来作为任务代码来创建一个任务MyTask,任务堆栈的长度为128字节,优先级别为20,任务参数pdata的实参为MyTaskAgu。试写出main()函数的代码。 33 #define MyTaskStkN 64 OS_STK MyTaskStkMyTaskStkN ; void main(void) OSTaskCreate( MyTask,/任务的指针任务的指针 &MyTaskAgu,/传递给任务的参数传递给任务的参数 &MyTaskStkMyTaskStkN-1, /任务堆栈栈
21、顶地址任务堆栈栈顶地址 20);/任务的优先级别任务的优先级别 34 堆栈的增长方向是随系统所使用的处理器不同而不同。因此在使用函数OSTaskCreate() 创建任务时,一定要注意所使用的处理器对堆栈增长方向的支持是向上的还是向下的。 35 上一练习时假设使用了支持堆栈向下增长方式的处理器设置参数ptos。如果使用的处理器支持堆栈的增长方向向上,则应该为: OSTaskCreate( MyTask, &MytaskAgu, &MyTaskStk0, 20); 为了提高应用程序的移植性,在编写代码时可兼顾两种情况,利用OS_CFG.H文件中的常数OS_STK_GROWTH 作
22、为选择开关,使用户可通过定义该常数的值来选择相应代码段,以适应不同的堆栈增长方向的需要。试改写上一练习代码。36#define MyTaskStkN 64OS_STK MyTaskStkMyTaskStkN ;void main(void) # if OS_STK_GROWTH=1 OSTaskCreate( MyTask, /任务的指针任务的指针 &MyTaskAgu, /传递给任务的参数传递给任务的参数 &MyTaskStkMyTaskStkN-1, /任务堆栈栈顶地址任务堆栈栈顶地址 20); /任务的优先级别任务的优先级别#else OSTaskCreate( MyTa
23、sk, /任务的指针任务的指针 &MyTaskAgu, /传递给任务的参数传递给任务的参数 &MyTaskStk0, /任务堆栈栈顶地址任务堆栈栈顶地址 20); /任务的优先级别任务的优先级别#endif 373.2.2 任务堆栈的初始化 当CPU启动运行一个任务时,CPU的各寄存器总是需要预置一些初始数据,例如指向任务的指针、任务堆栈指针、程序状态字等。那么,系统启动任务时,CPU从何处可以获得这些数据呢?最方便的方法就是让CPU从这个任务的任务堆栈里获得这些数据。 C/OS-II在创建任务函数OSTaskCreat ()中通过调用任务堆栈初始化函数OSTaskStkIni
24、t ()来完成任务堆栈初始化工作的,其原型如下: 38 OS_STK * OSTaskStkInit ( void ( * task)(void * pd), void * pdata, OS_STK * ptos, INIT16U opt ); 通常用户不会直接接触到这个函数,该函数由C/OS-II所提供的任务创建函数OSTaskCreate()来调用。 由于各处理器的寄存器及对堆栈的操作方式不同,因此该函数需要用户在进行C/OS-II的移植时,按所使用的处理器由用户来编写。 393.3任务控制块(TCB)及任务控制块链表 C/OS-II用来记录任务的堆栈指针、任务的当前状态、任务的优先级别
25、等一些与任务管理有关的属性的表就叫做任务控制块。 C/OS-II把系统所有任务的控制块链接为两条链表,并通过它们管理各个任务。40 一旦任务建立,一个任务控制块OS_TCB就被赋值。 任务控制块是一个数据结构,保存该任务的相关参数,包括任务堆栈指针,任务的当前状态,任务的优先级等。 任务CPU使用权被剥夺时,TCB保存该时刻任务状态;任务重新得到CPU控制权时,TCB确保任务从当时被中断的那一点丝毫不差地继续执行。 OS_TCB全部驻留在RAM中。 任务控制块就相当于一个任务的身份证,没有任务控制块的任务是不能被系统承认和管理的。3.3.1 任务控制块的结构41 任务控制块的结构的定义如 p5
26、2所示 任务控制块结构的主要成员(需要熟知): typedef struct os_tcb OS_STK *OSTCBStkPtr; /指向任务堆栈栈顶的指针指向任务堆栈栈顶的指针 struct os_tcb *OSTCBNext; /指向后一个任务控制块的指针指向后一个任务控制块的指针 struct os_tcb *OSTCBPrev; /指向前一个任务控制块的指针指向前一个任务控制块的指针 INT16U OSTCBDly; /任务等待的时限(节拍数)任务等待的时限(节拍数) 当需要把任务延时若干时钟节拍时,或者需要把任务挂起一段时间当需要把任务延时若干时钟节拍时,或者需要把任务挂起一段时间
27、以等待某事件的发生时需要用到这个变量。如果这个变量为以等待某事件的发生时需要用到这个变量。如果这个变量为0,表示,表示任务不延时,或者表示等待事件发生的时间没有限制任务不延时,或者表示等待事件发生的时间没有限制 。 INT8U OSTCBStat; /任务的当前状态标志任务的当前状态标志 INT8U OSTCBPrio; /任务的优先级别任务的优先级别 OS_TCB;42 其中OSTCBStat:任务状态字,可取下列值: OS_STAT_RDY: 处于就绪状态 OS_STAT_SEM: 处于等待信号量状态 OS_STAT_MBOX:处于等待邮箱状态 OS_STAT_Q: 处于等待消息队列状态
28、OS_STAT_SUSPEND:处于被挂起状态 OS_STAT_MUTEX:处于等待互斥信号量状态433.3.2 任务控制块链表两条链表来管理任务控制块: 空任务块链表(所有任务控制块还没有分配给任务),是在应用程序调用函数OSInit( )对系统进行初始化时建立的。 任务块链表(所有任务控制块已经分配给任务),是在调用函数OSTaskCreate( )创建任务时建立的。建立任务控制块链表的具体做法是,从空链表摘取一个空任务控制块,然后填充上任务属性后再形成新的链表。44 系统在调用函数OSInit()对C/OS-II系统进行初始化时,先在RAM中建立一个OS_TCB结构类型的数组OSTCBT
29、bl ,每个数组元素就是一个任务控制块,然后把这些控制块链接成一个如图所示的链表。由于链表中的这些控制块还没有与具体任务相关联,因此这个链表叫做空任务块链表OSTCBFreeList。45 每当应用程序调用系统函数OSTaskCreate()创建一个任务时,系统就会将任务控制块链表头指针OSTCBFreeList指向的任务控制块分配给该任务。在给任务控制块中的各成员赋值后,就按任务控制块链表的头指针OSTCBList将其加入到任务控制块链表中。 下图是在上图空任务控制块链表基础上,应用程序创建了两个用户任务并使用了两个系统任务(空闲任务和统计任务)的情况时,空任务块链表和任务块链表的结构示意图
30、(图中阴影区域为任务块链表)。 46473.3.3 任务控制块初始化 当用户程序调用函数OSTaskCreate() 创建一个任务时,这个函数会调用系统函数OSTCBInit() 来为任务控制块进行初始化。任务控制块初始化函数OSTCBInit()做三件事:1、从空任务控制块链表中获取一个任务控制块;2、用任务的属性值对任务控制块各个成员进行赋值;3、把这个任务控制块链入到任务控制块使用链表的头部。48 初始化任务控制块函数OSTCBInit() 的原型如下:INT8U OSTCBInit(INT8U Prio,/任务的优先级别,保存在任务的优先级别,保存在OSTCBPrio中中OS_STK
31、*ptos, /任务堆栈栈顶指针,保存在任务堆栈栈顶指针,保存在OSTCBStkPtr中中OS_STK *pbos, /任务堆栈栈底指针,保存在任务堆栈栈底指针,保存在OSTCBStkBottom中中INT16U id, /任务的标示符,保存在任务的标示符,保存在OSTCBId中中INT16U stk_size, /任务堆栈的长度,保存在任务堆栈的长度,保存在OSTCBStkSize中中void *pext, /任务控制块的扩展指针,保存在任务控制块的扩展指针,保存在OSTCBExtPtr中中INT16U opt /任务的控制块的选择项,保存在任务的控制块的选择项,保存在OSTCBOpt中中)
32、;493.4 任务就绪表及任务调度 多任务操作系统的核心:任务调度。 调度定义:就是通过一个算法在多个任务中确定哪个任务来运行。做这项工作的就是调度器。 任务调度的思想:总是让优先级最高的就绪任务处于运行状态。 C/OS-II进行任务调度的依据:任务就续表。50 至于什么是任务就绪表?可以这样理解,为了能使系统清楚地知道系统中哪些任务已经就绪,哪些还没有就绪, C/OS-II在RAM中设立了一个记录表,系统中的每个任务都在这个表占据一个位置,并用这个位置的状态( 1或者0)来表示任务是否处于就绪状态。这个表就叫做任务就绪表。 513.4.1 任务就绪表结构 每个就绪的任务都放入就绪表中(rea
33、dy list)中,就绪表用两个变量表示:OSRdyGrp、OSRdyTbl 。在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl 中的相应元素的相应位也置为1。OSRdyGrp和OSRdyTbl 之间的关系见下图,它们之间的关系是按照以下规则给出的:当当OSRdyTbl0中的任何一位是中的任何一位是1时,时,OSRdyGrp的第的第0位置位置1;当当OSRdyTbl1中的任何一位是中的任何一位是1时,时,OSRdyGrp的第的第1位置位置1;当当OSRdyTbl2中的任何一位是
34、中的任何一位是1时,时,OSRdyGrp的第的第2位置位置1;当当OSRdyTbl3中的任何一位是中的任何一位是1时,时,OSRdyGrp的第的第3位置位置1;5253 就绪表OSRdyTbl 数组的大小取决于OS_LOWEST_PR1O(见文件OS_CFG.H)。当用户的应用程序中任务数目比较少时,减少OS_LOWEST_PR1O 的值可以降低C/OS-对RAM(数据空间)的需求量。 那么如何根据任务的优先级别查找任务在就绪表的位置呢? 从图中可以看出,由于优先级别是一个单字节的数字,而且最大值不会超过63,即二进制00111111,因此,可以把优先级别看成是一个6位的二进制数,这样就可以用
35、高3位(Y、Y、Y)来指明变量OSRdyGrp的具体数据位,并用来确定就绪表数组元素的下标;用低3位(X、X、X)来指明该数组元素的具体数据位。 54 例3-5:已知某一个已经就绪的任务优先级别为prio=30,试判断应该在就绪表的哪一位置上置1。 答:30的二进制形式为00011110,其低6位为011110,于是可知应该把变量OSRdyGrp的D3位置1 , 同时要在OSRdyTbl3 的D6位上置1 。55 根据就绪表确定最高优先级两个关键:n优先级数分解为高三位和低三位分别确定;n高优先级有着小的优先级号 。563.4.2 对任务就绪表的操作 系统对于就绪表主要有三个操作:登记、注销和
36、从就绪表的就绪任务中得知具有最高优先级任务的标识(优先级prio)。 57 1. 登记 登记:指的是当某个任务处于就绪状态时,系统将该任务登记在任务就绪表中,即在就续表中将该任务的对应位置1。 在程序中,可用类似于下面的代码把优先级为prio的任务置为就绪态:OSRdyGrp | = OSMapTblprio3;OSRdyTblprio3 | = OSMapTblprio & 0 x07; 其中,OSMapTbl 是C/OS-II为加快运算速度定义的一个数组,各元素为:OSMapTbl0 = 0000 0001BOSMapTbl1 = 0000 0010BOSMapTbl2 = 000
37、0 0100BOSMapTbl3 = 0000 1000BOSMapTbl4 = 0001 0000BOSMapTbl5 = 0010 0000BOSMapTbl6 = 0100 0000BOSMapTbl7 = 1000 0000B58 例1:使优先级为12的任务进入就绪状态,12=1100b, OSRdyGrp|= OSMapTblprio 3 |= OSMapTbl1 |= 00000010OSRdyTblprio 3|= OSMapTblprio & 0 x07 |= OSMapTbl100b |= OSMapTbl4 |= 00010000即OSRdyGrp的第1位置1,OS
38、RdyTbl1的第4位置15960 例2:使优先级为21的任务进入就绪态,21=10 101b,OSRdyGrp|= OSMapTblprio 3 |= OSMapTbl10b= OSMapTbl2 |= 00000100OSRdyTblprio 3|= OSMapTblprio & 0 x07 |= OSMapTbl101b |= OSMapTbl5 |= 00100000即OSRdyGrp的第2位置1,OSRdyTbl2的第5位置16162 2. 注销 注销:指的是当某个任务需要脱离就绪状态时,系统在就绪表中将该任务的对应位置0。 如果要使一个优先级别为prio的任务脱离就绪状态,
39、则可使用如下代码:If(OSRdyTblprio3&= OSMapTblprio & 0 x07)=0)OSRdyGrp&= OSMapTblprio3; 脱离就绪态:将任务就绪表OSRdyTblprio3相应元素的相应位清零,而且当OSRdyTblprio3中的所有位都为零时,即全组任务中没有一个进入就绪态时,OSRdyGrp的相应位才为零。 63 例:使优先级为12的任务脱离就绪表 答: 欲使优先级为12的任务进入就绪态 优先级为12,即00001100BOSRdyGrp | = OSMapTblprio 3 ; (OSMapTbl1 = 0000 0010)OSR
40、dyTbl1 | = OSMapTblprio &0 x07 ; (OSMapTbl4 = 0001 0000) 欲使优先级为12的任务脱离就绪态 OSMapTblprio & 0 x07 = OSMapTbl4 = 11101111 OSMapTblprio 3 = OSMapTbl1 = 11111101如果OSRdyTblprio 3 &= OSMapTblprio & 0 x07 = 0 (该行所有任务都是非就绪态)则OSRdyGrp = OSRdyGrp & OSMapTblprio 3 = 064065 3找出进入就绪态的优先级最高的任务 从
41、任务就绪表中获取优先级别最高的就绪任务可用如下代码:y = OSUnMapTblOSRdyGrp;/获得优先级别的获得优先级别的D5、D4、D3位位x = OSUnMapTblOSRdyTbly;/获得优先级别的获得优先级别的D2、D1、D0位位Prio =(y3)+x;/获得就绪任务的优先级别获得就绪任务的优先级别 或y = OSUnMapTblOSRdyGrp;Prio = (INT8U)(y3)+OSUnMapTblOSRdyTbly);66 该代码执行后,得到的是最高优先级就绪任务的优先级别。其中,OSUnMapTbl同样是C/OS-II为加快运算速度定义的一个数组,共有256个元素,
42、其定义如下:INT8U const OSUnMapTbl = 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x00 to 0 x0F 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x10 to 0 x1F 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x20 to 0 x2F 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x30 to 0 x3F 6, 0, 1, 0, 2
43、, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x40 to 0 x4F 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x50 to 0 x5F 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x60 to 0 x6F 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x70 to 0 x7F 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x80 to
44、 0 x8F 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 x90 to 0 x9F 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 xA0 to 0 xAF 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 xB0 to 0 xBF 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 xC0 to 0 xCF 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2
45、, 0, 1, 0, /0 xD0 to 0 xDF 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /0 xE0 to 0 xEF 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /0 xF0 to 0 xFF; 67 例:已知OSRdyGrp=01101000b, OSRdyTbl3=11100100b,找出进入就绪态的优先级最高的任务 OSRdyGrp=01101000b=0 x68,查OSUnMapTbl0 x68得到的值是3,y=3。 OSRdyTbl3=11100100b=0 xE4,则O
46、SUnMapTbl0 xE4的值是2,x=2。 Prio= (y 3) + x=3*8+2=26。6869 例2 已知OSRdyGrp=00100100b, OSRdyTbl2=00010010b,找出进入就绪态的优先级最高的任务y=OSUnMapTblOSRdyGrp=OSUnMapTbl100100b =OSUnMapTbl0 x24=2x = OSUnMapTblOSRdyTbly= OSUnMapTblOSRdyTbl2 =OSUnMapTbl00010010b =OSUnMapTbl0 x12=1prio = (y 3) + x =(23)+1=17 70713.4.3 任务的调度1
47、. 调度器的主要工作 任务切换:在多任务系统中,令CPU中止当前正在运行的任务而去运行另一个任务的工作。 任务调度:按某种规则进行任务切换的工作。 调度的发生条件:系统或用户任务调用系统函数或者执行中断服务程序结束时。 任务调度由任务调度器完成,调度器主要工作:1)在任务就绪表中查找具有最高优先级别的就绪任务。2)实现任务切换。 C/OS-II有两种调度器:任务级调度器(由OSSched() 实现)、中断级调度器(由OSIntExt ()实现)。 任务切换的两个步骤:1)获得待运行任务的TCB指针。2)进行断点数据的切换。 72 2. 获得待运行任务的TCB指针 由于操作系统是通过任务的任务控
48、制块TCB来管理任务的,因此调度器真正实施任务切换之前的主要工作就是要获得待运行任务的任务控制块指针和当前任务的任务控制块指针。 任务级的调度函数OSSched( )代码如下 :void OSSched (void)INT8U y;OS_ENTER_CRITICAL(); /关中断if (OSLockNesting | OSIntNesting) = 0) /如果调用来自中断服务程序,或者至少调用了一次给任务调度上锁函数,任务调度函数将退出 73y = OSUnMapTblOSRdyGrp;OSPrioHighRdy = (INT8U)(y 0。 75 2)首先从任务就绪表中查得的最高优先级别
49、就绪任务的优先级别OSPrioHighRdy;然后在确认了这个就绪任务不是当前正在运行的任务(OSPrioCur是存放正在运行任务的优先级别的变量)的条件下,用OSPrioHighRdy作为下标去访问数组OSTCBPrioTbl,把数组元素OSTCBPrioTblOSPrioHighRdy的值(即待运行就绪任务的任务控制块指针)付给指针变量OSTCBHighRdy。于是可以依据OSTCBHighRdy和OSTCBCur这两个分别指向待运行任务控制块和当前任务控制块的指针在宏OS_TASK_SW( )中实施任务切换了。 763. 任务切换OS_TASK_SW( )任务级的任务切换需完成以下2步操
50、作: 将被挂起任务的处理器寄存器推入堆栈 将较高优先级任务的寄存器值从堆栈中恢复到寄存器中 任务级的任务切换由OS_TASK_SW( )宏完成. #define OS_TASK_SW( ) OSCtxSw( )77 下图1示意C/OS-II在调用OS_TASK_SW( )之前一些变量和数据结构的状况。为了便于讨论,构造了一个假想的CPU,该CPU有8个寄存器:1个堆栈指针(SP);1个程序计数器(PC);1个处理器状态寄存器(PSW);4个通用寄存器(R1,R2,R3及R4)。 78(1)(3)(2)(5)(4)79 下图2示意调用OS_TASK_SW( )以及保存被挂起任务的CPU寄存器之后
51、,一些变量和数据结构的状况:保存当前任务CPU寄存器的值 80(1) 调用含有中断指令的函数OS_TASK_SW( ),强制处理器保存PSW和PC的当前值(2) 软中断的执行从保存通用寄存器开始,顺序是R1,R2,R3,R4(3) 然后堆栈指针寄存器被保存在当前任务的OS_TCB中。此时,CPU的SP寄存器和OSTCBCurOSTCBStkPtr都指向当前任务堆栈的同一位置81 下图3示意执行任务切换最后一段代码之后变量和数据结构的状况:重新装入要运行的任务82(1) 由于新的当前任务是将要重新开始运行的任务,任务切换代码将OSTCBHighRdy复制到OSTCBCur(2) 从OS_TCB中
52、找出将要重新开始运行的任务的堆栈指针(在OSTCBHighRdyOSTCBStkPtr中),装入CPU的SP寄存器中。此时,SP寄存器指向堆栈中存有寄存器R4值的位置(3) 按相反的方向从堆栈中弹出通用寄存器(4) 通过执行中断返回指令,PC和PSW的值装回到CPU中。此时,由于程序计数器PC的值变了,重新开始运行的任务代码从PC指向的那一点开始运行,于是切换到新任务代码的过程完成了。8384 任务切换OS_TASK_SW()的代码void OSCtxSw(void)将R1,R2,R3及R4推入当前堆栈;/图2(2)OSTCBCur-OSTCBStkPtr = SP;/SP入控制块 /图2(3
53、)OSTCBCur = OSTCBHighRdy;/图3(1)SP = OSTCBHighRdy -OSTCBSTKPtr; /图3(2)将R4,R3,R2及R1从新堆栈中弹出;/图3(3)执行中断返回指令;/图3(4)853.5 任务的创建 uC/OS-II是通过任务控制块来管理任务的; uC/OS-II有两个用来创建任务的函数:OSTaskCreate ( )、OSTaskCreateExt ( ); OSTaskCreate ( )向下兼容,OSTaskCreateExt ( )是前一函数的扩展,提供了一些附加功能; 任务可以在多任务调度开始前建立,也可以在其他任务执行过程中建立; 任务
54、不能由中断服务程序建立。863.5.1 用函数OSTaskCreate( )创建任务 应用程序通过调用函数OSTaskCreate ()来创建一个任务,函数OSTaskCreate ( )源代码如下: INT8U OSTaskCreate (void ( * task)(void * pd), / 指向任务的指针void * pdata, / 传递给任务的参数OS_STK *ptos, / 指向任务堆栈栈顶的指针INT8U prio / 任务的优先级)87void *psp;INT8U err;if (prio OS_LOWEST_PRIO) /任务的优先级必须在0到OS_LOWEST_PRI
55、O/之间检测任务的优先级是否合法 return (OS_PRIO_INVALID);OS_ENTER_CRITICAL();if (OSTCBPrioTblprio = (OS_TCB *)0) / 确认优先级未被使用 OSTCBPrioTblprio = (OS_TCB *)1; / 如果拟分配的优先级是空闲的,通过/在OSTCBPrioTbl 中放置一个非空指针,保留该优先级OS_EXIT_CRITICAL();psp = (void *)OSTaskStkInit(task ,pdata, ptos, 0); / 初始化任务堆栈,建立任务的堆栈,返回新的堆栈 /栈顶psp,并保存在任务控
56、制块OS_TCB中,注意堆栈增长方向err = OSTCBInit( prio,psp, (void *)0, 0, 0,(void *)0, 0); / 获得并初始化任务控制块, 从空闲的OS_TCB池/中获得并初始化一个任务控制块OS_TCB88if (err = OS_NO_ERR) OS_ENTER_CRITICAL();OSTaskCtr+; / 从OS_TCBInit( )返回后,任务计数器加1,/用于跟踪已经建立了的任务数目OS_EXIT_CRITICAL();if ( OSRunning) OSSched(); / 任务调度 /如果OSTaskCreate ()函数是在某个任务
57、的执行过程中被调用(OSRunning=1)/则任务调度函数会被调用来判断是否新建立的任务比原来的任/务有更高的优/先级。如果新任务的优先级更高,内核会进行一次任务切换。else OS_ENTER_CRITICAL();OSTCBPrioTblprio = (OS_TCB *)0; / 放弃任务 /从OSTCBInit()返回后,要检验返回代码,如果成功,就增加OSTaskCtr, /OSTaskCtr用于保存产生的任务数目。如果OSTCBInit()返回失败,就置 /OSTCBPrioTblprio 的入口为0以放弃该任务的优先级。OS_EXIT_CRITICAL();return (err
58、); 89else OS_EXIT_CRITICAL();return (OS_PRIO_EXIST);90 从函数OSTaskCreate( )的源代码中可以看到,函数对待创建任务的优先级别进行一系列判断,确认该优先级别合法且未被使用之后,随即调用函数OSTaskStkInit( )和OSTCBInit( )对任务堆栈和任务控制块进行初始化。初始化成功后,除了把任务计数器加1外,还要进一步判断uC/OS-II的核是否在运行状态(即OSRunning的值是否为1),如果OSRunning的值为1,则调用OSSched( )进行任务调度。 提问:能否调用OSTaskCreate( )函数来创建优
59、先级为OS_LOWEST_PRIO的任务?不能,因为优先级OS_LOWEST_PRIO是为空闲任务保留的。如果这样做,会返回代码出错信息OS_PRIO_EXIST。913.5.2 用函数OSTaskCreateExt( )创建任务 用OSTaskCreateExt( )函数来建立任务会更加灵活,但是会增加一些额外的开销。函数OSTaskCreateExt ()源代码如下:INT8U OSTaskCreateExt(void (*task)(void *pd), / 指向任务的指针void *pdata,/ 传递给任务的参数OS_STK *ptos, / 指向任务堆栈栈顶的指针INT8U pri
60、o, / 任务的优先级INT16U id, / 任务的标示OS_STK *pbos, / 任务堆栈栈底的指针INT32U stk_size, / 任务堆栈的容量void *pext, / 指向附加数据域的指针INT16U opt / 用于设置操作选项); 923.5.3 创建任务的一般方法 可在调用函数OSStart( )启动任务调度之前来创建。 在任务中来创建。 uC/OS-II的规定:在OSStart( )启动任务调度之前必须创建至少一个用户任务。这样,在OSStart ( )之前先创建一个任务,并赋予它最高的优先级,从而使它成为起始任务,然后在这个起始任务中,再创建其它各任务。如果要使用系统提供的统计任务,则统计任务的初始化函数必须在这个起始任务中来调用。 注意:uC/OS-II不允许在中断服务程序中创建任务93 下面是创建任务的示意性
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- T/SILA 007-2022教室照明智能化规范
- T/SHPTA 101-2024车用压缩氢气塑料内胆碳纤维全缠绕气瓶湿法缠绕用环氧树脂
- 音乐制作人工作成果与效果考核表
- 2026年合作合同条款修改说明(8篇范文)
- 智能门锁远程控制故障排查方案指引
- 2026年劳动合同续签期限提醒通知函(4篇范文)
- 多功能家电连接与设置手册
- 跨境电商物流时效评估企业使用手册
- 漆器镶嵌装饰工安全实操竞赛考核试卷含答案
- 客运船舶驾驶员安全规程强化考核试卷含答案
- 中铝宁夏能源集团笔试题库
- 2026统考专升本英语:作文模版20篇
- 日本工业标准JIS-2
- 2026年交通运输局财务审计岗遴选专业知识测试
- 耳部全息铜砭刮痧法
- 麻醉科教研室工作制度
- 医院采购领导小组制度
- 儿童淋巴结肿大诊治共识
- 甘肃省医保政策培训课件
- 舞台灯光调试与安装施工方案
- 23G409先张法预应力混凝土管桩
评论
0/150
提交评论