找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12514|回复: 0
收起左侧

uC/OS-II学习笔记—任务的创建

[复制链接]
ID:51773 发表于 2013-7-18 20:09 | 显示全部楼层 |阅读模式
任务是操作系统处理的首要对象,在多任务运行环境,任务的管理需要考虑多方面的因素。最基本的任务管理功能是任务的创建。任务创建函数分两种,一种是基本的创建函数OSTaskCreate,另一种是扩展的任务创建函数OSTaskCreateExt。两个函数都实现了任务的创建,但是OSTaskCreateExt功能更强,带有很多附加的功能。如果不需要使用附加的功能,OSTaskCreate也是可以胜任的,没有哪个更好之说,完全根据需要选择。
OSTaskCreate实现了创建任务最基本的功能,任务在创建之后,就准备好了运行需要的各种数据结构。OSTaskCreate的代码如下所示:
50.png
在创建一个任务的时候,需要给任务分配堆栈空间。堆栈是在操作系统的变量声明中已经分配了空间的,因此要将该空间分配给任务,那么堆栈的地址应该保存在什么地方呢:任务创建后堆栈又应该初始化什么样子呢?
51.png
可以看到,堆栈的初始化不是很好理解。因为opt在这里根本没有使用,因此不需要过多的考虑。这段程序代码出现在os_cpu.h中,说明它是和CPU密切相关的,当使用其他硬件环境时,需要修改该代码。实际上,该代码就是按顺序向堆栈中压入数据,最后返回最新的堆栈栈顶指针。那么在堆栈中都压入了哪些数据呢?如下图所示是处理器的寄存器:
52.png
代码注释部分也提到了,上半部分数据在exception时是自动保存的,下班部分需要手动保存。那么哪些数据是自动保存的呢?如下图所示:
53.png
以空闲任务的创建为例,在堆栈初始化之后,堆栈如下图所示:
54.png
空闲任务的堆栈定义如下所示:
55.png
设置OS_TASK_IDLE_STK_SIZE这个宏的值是32,即:
56.png
STM32F407的堆栈是向低地址增长的,所以最开始堆栈顶的位置在最高地址OSTaskIdleStk[31]。所以将&OSTaskIdleStk[31]作为栈顶地址传递给堆栈初始化函数OSTaskStkInit。
任务调度函数OS_Sched将进行任务的调度, 即选择优先级最高的任务来运行。任务的地址、运行环境等内容都保存于堆栈,OS_Sched将根据堆栈的内容进行相关的操作。在操作系统初始化的时候,由于还没有启动多任务,因此还不会调用OS_Sched。
从前面的基本代码描述,可以清晰了解任务初始化的过程。首先,如果配置了对任务参数进行检查,则检查任务参数的有效性,尤其是对任务的优先级进行判断。当任务的优先级在合适的范围内时,还需要判断指定优先级的任务是否有已经被创建的,因为优先级必须是唯一的。然后进行任务堆栈的初始化、任务控制块的初始化,根据系统是否已经启动多任务,决定是否此时进行一次任务调度。OSTaskCreate的流程如下图所示:

57.png OSTaskCreate实现了创建任务的最基本功能,但是操作系统默认使用的是任务创建函数却是OSTaskCreateExt,那么OSTaskCreateExt比OSTaskCreate多了哪些功能呢?
OSTaskCreateExt的函数参数就有9个,但是并非想象中的那么复杂。相对OSTaskCreate来说,最主要的是增加了堆栈检查的功能,该函数的声明如下所示:

58.png
59.png 这个函数是uC/OS-II的内部函数,用于采用扩展功能创建任务。
参数解析如下:
(#_#)task:任务的地址,操作系统根据该地址找到任务,才能让任务运行。这与OSTaskCreate是完全相同的。
(#_#)p_arg:任务参数,以地址形式传递,可以是任何类型的地址。
(#_#)ptos:任务堆栈的栈顶。需要注意的是,如果OS_STK_GROWTH的值设置为1,堆栈是从高地址向低地址方向增长,栈顶应为高地址,否则堆栈是从低地址向高地址方向增长。栈顶在低地址。
(#_#)prio:任务的优先级。在uC/OS-II中,任务的优先级必须唯一。
(#_#)id:任务的识别号ID,范围为0~65536.
(#_#)pbos:任务堆栈的栈底地址。如果OS_STK_GROWTH设置为1,则堆栈是从高地址向低地址方向增长,pbos应该在低地址端。反之,如果OS_STK_GROWTH设置为0,则堆栈是从低地址向高地址方向增长,pbos应该在高地址端。
(#_#)stk_size:堆栈的大小。stk_size设置为可以压入堆栈的最大数据量,和堆栈的数据类型无关。如果堆栈的类型OS_STK为32位整型,那么堆栈共有stk_size*4字节。如果堆栈的类型OS_STK为8位的整型,那么堆栈共有stk_size字节。
(#_#)pext:扩展块的地址。如果支持浮点数计算,用户内存在上下文切换(任务切换)时需要保存和恢复浮点寄存器的内容,这些内容可以保存在扩展快中。
(#_#)opt:包含任务的附件信息。opt的低8位为uC/OS-II保留,高8位用户可设置。低8位的每一位的含义与OS_TASK_OPT相同,因此系统定义了4个宏,如下所示:

60.png 返回值如下:
(#_#)OS_ERR_NONE:本函数成功运行。
(#_#)OS_PRIO_EXIT:如果任务优先级已经存在了,再创建相同优先级的任务明显是非法的。
(#_#)OS_ERR_PRIO_INVALID:如果优先级参数非法,如大于最高值OS_LOWEST_PRIO。
(#_#)OS_ERR_TASK_CREATE_ISR:如果在中断服务程序ISR中创建任务。
OSTaskCreateExt与OSTaskCreate的主要区别在于是用堆栈清除函数OS_TaskStkClr来清空堆栈。
我们需要知道OS_TaskStkClr是如何进行堆栈的清空的。如下所示:

61.png 它的3个参数分别为堆栈的栈底、堆栈的大小及选项opt,可以看到这3个参数都是传递给OSTaskCreateExt后直接传递给OS_TaskStkClr的。
可见,堆栈清除函数实现的功能就是将整个任务对应的堆栈空间全部清0,这样做是为了符合以后进行堆栈检查的需要。如果不需要进行堆栈检查,当然也不需要进行堆栈的清除操作,这是程序代码第一行条件判断语句存在的原因。另外,如果在堆栈清除函数中,发现opt未设置有OS_TASK_OPT_STK_CLR,就不应执行堆栈清除操作。
任务创建函数是非常重要的函数,在操作系统的初始化中就调用了这个函数来创建了空闲任务和统计任务。OSTaskCreateExt的流程如下所示:

62.png 与OSTaskCreate相比,OSTaskCreateExt比OSTaskCreate增加了堆栈清除的功能,其他并无大的却别。重复以下两点:堆栈清除函数只是为堆栈检查做准备的;操作系统采用的默认的任务创建函数是OS_TaskCreateExt。
任务创建函数执行后,在正常情况下,对应的任务就处于就绪态,因为在创建的过程中, 调用了TCB初始化函数,对就绪表和就绪组进行了操作和处理,标记了任务的就绪状态,而且也在就绪队列插入了一个TCB。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表