FreeRTOS 操作系统学习(二) 任务
FreeRTOS 操作系统学习
http://wiki.csie.ncku.edu.tw/embedded/FreeRTOS_Melot.pdf
1. 任务
1.1 FreeRTOS 中的任务
只要硬件和内存足够,FreeRTOS 运行的任务数量不受限制,作为一个实时操作系统,FreeRTOS 同时支持循环和非循环任务。在 RTOS 中,任务由一个简单的C函数定义,参数为 void* 类型,无返回值 (void)。
用些函数用于对任务的管理 : 任务创建(vTaskCreate()),任务销毁((vTaskDelete()),优先级管理(uxTaskPriorityGet(), vTaskPrioritySet()) 延迟/恢复((vTaskDelay(), vTaskDelayUntil(),vTaskSuspend(), vTaskResume(),vTaskResumeFromISR())
为了便于调试,用户可以选择很多操作,例如创建关键序列或对任务进行监控。、
1.1.1 任务的生命周期
本节更详细地讲解任务从创建至销毁的整个发展过程。此时,我们假设只有一个内核,在指定的时间内只运行一个任务,每个人物只有“ 运行 (Running) ” “ 不运行 (Not Running) ”两种状态,由于我们假设是单核运行,且任意时刻有且只有一个任务在运行,那么其他的未运行的任务一定是处于“不运行 (Not Running)”状态. 图1 给出了这种情形下生命周期的简单示意图
当一个任务从 非运行状态 进入运行状态,称之为“切入”,反之,成为“切出”。
图1 生命周期示意图
由于存在一些原因导致任务无法运行,由于“未运行”状态可以展开,如图2所示,当任务处于延迟或等待事件触发时,高优先级任务可以抢占低优先级任务(调度在第2节中介绍)。当任务正在处理器资源准的过程中,这个状态称之为“就绪(Ready)”态。当任务处于等待另一个任务完成(例如 等待信号量同步完成或互斥量)被延后执行,处于等待的状态称之为“阻塞。(Blocked)”。总之,调用vTaskSuspend() 、 vTaskResume() 、 xTaskResumeFromISR() 这些函数,可以使任务进入或退出“挂起 (Suspend)”状态。
强调任务能自行退出“运行(Running)”态是非常重要的(即进入延迟、挂起或事件等待),只有调度器能使任务重新“切入”运行状态,当一个任务试图重新进入“运行”态,它的状态应为“就绪(Ready)”,只有任务调度器能决定当前的时间片分配给哪个就绪任务。
图2 任务的生命周期
1.2 创建 和 删除任务
由一个简单的C函数定义的任务,它带有一个void *参数并且不返回任何内容(请参见 文本1)
void ATaskFunction( void *pvParameters );文本1: 一个典型的任务函数 |
一个任务在销毁(Destroy)之前会一直运行。任务通常是一个死循环函数,或在到达最后一个大括号之前调用vTaskDestroy(NULL),由于死循环中的任何代码都可能失败并导致退出此循环,即使是重复性任务,在最后的大括号之前调用vTaskDelete()也更安全。文本3 是一个任务实现的典型例子。
可以使用vTaskCreate()创建任务(文本2)。 此函数参数列表如下:
- pvTaskCode: 一个指向任务实现函数的指针.
- pcName: 任务名. 这对FreeRTOS没用,但仅用于调试目的
- usStackDepth: 以字为单位的此任务的堆栈长度. 堆栈的实际大小取决于微控制器. 如果堆栈为32位(4字节),而usStackDepth的值为100,则将为任务分配400字节(4乘以100).
- pvParameters: 任务的指针参数. 较好的做法是创建一个专用的结构体变量,实例化并赋值,然后将其指针交给任务。.
- uxPriority: 任务优先级, 赋值范围从 0 到 ( MAX_PRIORITIES–1). 在第2节中将对此进行讨论
- pxCreatedTask: 指向可以处理任务标识符的指针. 如果任务标识符将来不会被修改,则可以将其设为NULL。
portBASE_TYPE xTaskCreate ( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void * pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask ); |
void ATaskFunction( void *pvParameters ) { /* 可以按照常规函数声明变量的方法对变量进行声明。. 每个使用此函数创建的任务 ,会重新创建一个iVariableExample 变量. 如果变量是静态变量,所有此任务的实例将共享变量的存储,一个实例修改将导致所有实例的这个变量值都发生改变 */
int iVariableExample = 0;
/* 死循环中为任务的具体实现. */ for( ;; ) { /* 任务功能实现代码. */ }
/* 应该在不打破上述循环的前提下执行任务,然后才能删除该任务。 传递给vTaskDelete()函数的NULL参数表示要删除的任务是当前正在调用的任务。 */
vTaskDelete( NULL ); } |
当任务创建后可以使用xTaskDestroy()例程销毁任务。 参数为pxCreatedTask,例程见文本4中给出,示例参考文本3
void vTaskDelete( xTaskHandle pxTask ); |
删除任务后,空闲任务将释放所有释放所有分配给该任务的内存资源。注意,所有动态分配的内存必须手动释放。