FreeRTOS 最基本的功能就是任务管理,而任务管理最基本的操作就是创建和删除任务,FreeRTOS 的任务创建和删除API 函数如表6.1.1.1 所示:
1、函数xTaxkCreate()
此函数用来创建一个任务,任务需要RAM 来保存与任务有关的状态信息(任务控制块),任务也需要一定的RAM 来作为任务堆栈。如果使用函数xTaskCreate()来创建任务的话那么这些所需的RAM 就会自动的从FreeRTOS 的堆中分配,因此必须提供内存管理文件,默认我们使用heap_4.c 这个内存管理文件,而且宏configSUPPORT_DYNAMIC_ALLOCATION 必须为1。如果使用函数xTaskCreateStatic()创建的话这些RAM 就需要用户来提供了。新创建的任务默认就是就绪态的,如果当前没有比它更高优先级的任务运行那么此任务就会立即进入运行态开始运行,不管在任务调度器启动前还是启动后,都可以创建任务。此函数也是我们以后经常用到的,本教程所有例程均用此函数来创建任务,函数原型如下:
参数:
pxTaskCode: 任务函数。
pcName: 任务名字,一般用于追踪和调试,任务名字长度不能超过。
configMAX_TASK_NAME_LEN。
usStackDepth: 任务堆栈大小,注意实际申请到的堆栈是usStackDepth 的4 倍。其中空闲任
务的任务堆栈大小为configMINIMAL_STACK_SIZE。
pvParameters: 传递给任务函数的参数。
uxPriotiry: 任务优先级,范围0~ configMAX_PRIORITIES-1。
pxCreatedTask: 任务句柄,任务创建成功以后会返回此任务的任务句柄,这个句柄其实就是
任务的任务堆栈。此参数就用来保存这个任务句柄。其他API 函数可能会使
用到这个句柄。
返回值:
pdPASS: 任务创建成功。
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: 任务创建失败,因为堆内存不足!
2、函数xTaskCreateStatic()
此函数和xTaskCreate()的功能相同,也是用来创建任务的,但是使用此函数创建的任务所需的RAM 需要用用户来提供。如果要使用此函数的话需要将宏configSUPPORT_STATIC_ALLOCATION 定义为1。函数原型如下:
参数:
pxTaskCode: 任务函数。
pcName: 任务名字,一般用于追踪和调试,任务名字长度不能超过。
configMAX_TASK_NAME_LEN。
usStackDepth: 任务堆栈大小,由于本函数是静态方法创建任务,所以任务堆栈由用户给出,
一般是个数组,此参数就是这个数组的大小。
pvParameters: 传递给任务函数的参数。
uxPriotiry: 任务优先级,范围0~ configMAX_PRIORITIES-1。
puxStackBuffer: 任务堆栈,一般为数组,数组类型要为StackType_t 类型。
pxTaskBuffer: 任务控制块。
返回值:
NULL: 任务创建失败,puxStackBuffer 或pxTaskBuffer 为NULL 的时候会导致这个
错误的发生。
其他值: 任务创建成功,返回任务的任务句柄。
3、函数xTaskCreateRestricted()
此函数也是用来创建任务的,只不过此函数要求所使用的MCU 有MPU(内存保护单元),用此函数创建的任务会受到MPU 的保护。其他的功能和函数xTaxkCreate()一样。
参数:
pxTaskDefinition: 指向一个结构体TaskParameters_t,这个结构体描述了任务的任务函数、堆栈大小、优先级等。此结构体在文件task.h 中有定义。
pxCreatedTask: 任务句柄。
返回值:
pdPASS: 任务创建成功。
其他值: 任务未创建成功,很有可能是因为FreeRTOS 的堆太小了。
4、函数vTaskDelete()
删除一个用函数xTaskCreate()或者xTaskCreateStatic()创建的任务,被删除了的任务不再存在,也就是说再也不会进入运行态。任务被删除以后就不能再使用此任务的句柄!如果此任务是使用动态方法创建的,也就是使用函数xTaskCreate()创建的,那么在此任务被删除以后此任务之前申请的堆栈和控制块内存会在空闲任务中被释放掉,因此当调用函数vTaskDelete()删除
任务以后必须给空闲任务一定的运行时间。只有那些由内核分配给任务的内存才会在任务被删除以后自动的释放掉,用户分配给任务的内存需要用户自行释放掉,比如某个任务中用户调用函数pvPortMalloc()分配了500 字节的内存,那么在此任务被删除以后用户也必须调用函数vPortFree()将这500 字节的内存释放掉,否则会导致内存泄露。此函数原型如下:
参数:
xTaskToDelete: 要删除的任务的任务句柄。
返回值:
无
6.2 任务创建和删除实验(动态方法)
6.2.1 实验程序设计
1、实验目的
上一小节讲解了FreeRTOS 的任务创建和删除的API 函数,本小节就来学习如何使用这些API 函数,本小节学习xTaskCreate()和vTaskDelete()这两个函数的使用
2、实验设计
本实验设计三个任务:start_task、task1_task 和task2_task ,这三个任务的任务功能如下:start_task:用来创建其他两个任务。
task1_task :当此任务运行5 此以后就会调用函数vTaskDelete()删除任务task2_task,此任务也会控制LED0 的闪烁,并且周期性的刷新LCD 指定区域的背景颜色。
task2_task :此任务普通的应用任务,此任务也会控制LED1 的闪烁,并且周期性的刷新LCD 指定区域的背景颜色。
3、实验工程
FreeRTOS 实验6-1 FreeRTOS 任务创建和删除实验(动态方法)。
4、实验程序与分析● 任务设置
(1) 、start_task 任务的任务优先级,此处用宏来表示,以后所有的任务优先级都用宏来表示。创建任务设置优先级的时候就用这个宏,当然了也可以直接在创建任务的时候指定任务优先级。
(2)、start_task 任务的任务堆栈大小。
(3)、start_task 任务的任务句柄。
(4)、start_task 任务的任务函数声明。
● main()函数
(1)、调用函数xTaskCreate()创建tart_task 任务,函数中的各个参数就是上面的任务设置中定义的,其他任务的创建也用这种方法。
(2)、调用函数vTaskStartScheduler()开启FreeRTOS 的任务调度器,FreeRTOS 开始运行。
● 任务函数
(1)、start_task 任务的任务函数,在此任务函数中我们创建了另外两个任务task1_task 和task2_task。start_task 任务的职责就是用来创建其他的任务或者信号量、消息队列等的,当创建完成以后就可以删除掉start_task 任务。
(2)、删除start_task 任务,注意函数vTaskDelete()的参数就是start_task 任务的任务句柄StartTask_Handler。
(3)、task1_task 任务函数(任务1),任务比较简单,每隔1 秒钟task1_num 加一并且LED0反转,串口输出任务运行的次数,其实就是task1_num 的值。当task1_task 运行5 次以后就调用函数vTaskDelete()删除任务task2_task。
(4)、任务task1_task 运行了5 次,调用函数vTaskDelete()删除任务task2_task。
(5)、task2_task 任务函数(任务2),和task1_task 差不多。
简单的总结分析一下此例程的流程,因为这是我们使用FreeRTOS 写的第一个程序,很多习惯是我们后面要用到的。比如使用任务宏定义任务优先级,堆栈大小等,一般有关一个任务的东西我们的放到一起,比如任务堆栈、任务句柄、任务函数声明等,这样方便修改。这些东西可以放到一个.h 头文件里面去,只是例程里面任务数比较少,所以就直接放到main.c 文件里面了,要是工程比较大的话最好做一个专用的头文件来管理。在main 函数中一开始肯定是初始化各种硬件外设, 初始化完外设以后调用函数xTaskCreate()创建一个开始任务,注意创建开始任务是在调用函数vTaskStartScheduler()开启任务调度器之前,这样当后面开启任务调度器以后就会直接运行开始任务了。其他任务的创建就放到开始任务的任务函数中,由于开始任务的职责就是创建其他应用任务和信号量、队列等这些内核对象的,所以它只需要执行一次,当这些东西创建完成以后就可以删除掉开始任务了。看过我们的UCOS 教程的话就会发现这个过程和UCOS 里面一样的。
6.2.2 程序运行结果分析
编译程序并下载到开发板中,查看任务1 和任务2 的运行情况,下载完成以后以后LCD 显示如图6.2.2.1 所示:
图6.2.2.1 LCD 默认界面
图中左边的框为任务1 的运行区域,右边的框为任务2 的运行区域,可以看出任务2 运行了5 次就停止了,而任务1 运行了12 次了。打开串口调试助手,显示如图6.2.2.2 所示:
图6.2.2.2 窗口调试助手输出信息
从图6.2.2.2 中可以看出,一开始任务1 和任务2 是同时运行的,由于任务2 的优先级比任务1 的优先级高,所以任务2 先输出信息。当任务1 运行了5 次以后任务1 就删除了任务2,最后只剩下了任务1 在运行了。