系列文章目录
【基于FreeRTOS的STM32F103系统】简介及官方文件移植
【基于FreeRTOS的STM32F103系统】编写FreeRTOS程序
【基于FreeRTOS的STM32F103系统】内存管理及任务调度
【基于FreeRTOS的STM32F103系统】Heap_4内存管理机制程序详解
【基于FreeRTOS的STM32F103系统】移动底盘程序优化
前言
前面简单介绍了FreeRTOS和如何将它简单的移植到STM32F1上,这篇介绍移植完成后,我们如何创建任务,并利用FreeRTOS的多任务机制优化我们的程序。
一、创建任务
创建任务时使用的函数如下:
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, //函数指针,任务函数
const char * const pcName, //任务的名字
const configSTACK_DEPTH_TYPE usStackDepth,//栈大小,单位为word,10表示40字节
void * const pvParameters, //调用任务函数时传入的参数
UBaseType_t uxPriority, //优先级
TaskHandle_t * const pxCreatedTask );//任务句柄,以后使用它来操作这个任务
参数说明:
- pvTaskCode:函数指针,可以简单地认为任务就是一个C函数。它稍微特殊一点:永远不退出,或者退出时要调用"vTaskDelete(NULL)"
- pcName:任务的名字,FreeRTOS内部不使用它,仅仅起调试作用。长度为:confifigMAX_TASK_NAME_LEN
- usStackDepth:每个任务都有自己的栈,这里指定栈大小。
单位是 word ,比如传入 100 ,表示栈大小为 100 word ,也就是 400 字节。最大值为 uint16_t 的最大值。怎么确定栈的大小,并不容易,很多时候是估计。精确的办法是看反汇编码。
-
pvParameters:传入参数,调用 pvTaskCode 函数指针时用到: pvTaskCode(pvParameters)
- uxPriorit:优先级范围:0~(confifigMAX_PRIORITIES – 1) 数值越小优先级越低, 如果传入过大的值,xTaskCreate会把它调整为(confifigMAX_PRIORITIES – 1)
-
pxCreatedTask: 用来保存 xTaskCreate 的输出结果: task handle 。 以后如果想操作这个任务,比如修改它的优先级,就需要这个 handle 。 如果不想使用该 handle ,可以传入 NULL 。
-
返回值:
成功: pdPASS ;失败: errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY( 失败原因只有内存不足 )注意:文档里都说失败时返回值是 pdFAIL ,这不对。pdFAIL 是 0 , errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 是 -1 。
实例:
void Task1Function(void * param)
{
while (1)
{
printf("1");
}
}
void Task2Function(void * param)
{
while (1)
{
printf("2");
}
}
xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
开启任务调度:
vTaskStartScheduler(); //开启任务调度
结果:
二、删除任务
删除任务使用的函数如下:
void vTaskDelete( TaskHandle_t xTaskToDelete );
参数说明:
-
xTaskToDelete:任务句柄,使用 xTaskCreate 创建任务时可以得到一个句柄,也可传入NULL ,这表示删除自己。
-
句柄的实质就是这个任务结构体的指针,在FreeRTOS中任务的创建利用面向对象的思想,创建的一个个任务都是结构体,删除任务的实质就类似于C语言中的free释放内存
实例:
void vTask1( void *pvParameters )
{
const TickType_t xDelay100ms = pdMS_TO_TICKS( 100UL );
BaseType_t ret;
/* 任务函数的主体一般都是无限循环 */
for( ;; )
{
/* 打印任务的信息 */
printf("Task1 is running\r\n");
ret = xTaskCreate( vTask2, "Task 2", 1000, NULL, 2, &xTask2Handle );
if (ret != pdPASS) printf("Create Task2 Failed\r\n");
// 如果不休眠的话, Idle任务无法得到执行
// Idel任务会清理任务2使用的内存
// 如果不休眠则Idle任务无法执行, 最后内存耗尽
vTaskDelay( xDelay100ms );
}
三、任务状态
- 当前正在进行的任务,是running状态;其他所有任务都处于not running状态
-
"not running"状态还可以细分为:ready :就绪,随时可以运行blocked :阻塞,该任务在等待某一事件发生suspended :挂起,该任务暂停休息
当创建任务并开始任务调度后,所有任务都处于Ready就绪状态,系统随机挑选一个任务Running,正在执行的任务可以使用vTaskSuspend函数使自己进入挂起状态(传入参数NULL或自己的句柄),也可以使其他任务进入挂起状态(传入参数为需要挂起任务的句柄),进入暂停状态后,需要在别的任务执行过程中调用vTaskResume函数该任务才会重新进入Ready状态;
在任务执行过程中,需要等待某个函数或事件的发生,则进入挂起状态(Baocked),当等待的事件(可能是中断或某个任务)发生后该任务才会恢复Ready状态。
总结
关于任务简单写这些,后面进行内存管理、堆栈、队列等的介绍