FREERTOS学习三:任务管理

一、什么是任务

任务就是一个函数,一个大循环函数,也可以称之为线程。

以下是一个任务的部分代码:

void myTask01(void *argument)
{/*大循环*/for(;;){/*任务的具体内容*/RLED_TOGGLE();/*任务阻塞*/vTaskDelay(500);}
}

二、创建任务的几大要素

先看下创建任务的函数结构,就知道创建任务的几个要素了

创建任务函数原型

BaseType_t xTaskCreate(    TaskFunction_t pxTaskCode,const char * const pcName,const uint16_t usStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask )

创建任务函数实例

xTaskCreate(    (TaskFunction_t) myTask01,    //任务指针,就是任务的函数名(const char *) "myTask01",    //任务的名字100,                         //任务的栈大小,单位是字(void * ) NULL,               //调用任务时传入的参数(UBaseType_t) 2,              //优先级(TaskHandle_t *) &myTask01_Handle );  //任务句柄

对比一下创建任务原型以及实例的代码

pxTaskCode = myTask01,这个计时函数的指针,假设大家已经知道了函数名就是这个函数的指针;

pcName = "myTask01" ,任务的名字,跟前面的函数名是不是有些类似,其实没什么用,RTOS系统内部基本不使用它,相当于你的小名别一样,国家系统里面是不用的,你的房产证,驾驶证都不用你的小别名,只有某些身边的人聊天的时候可能会用到你的别名。

usStackDepth = 100,就是任务的栈大小,100个字==400个字节,任务的栈用于保存任务的现场和内部的一些变量,怎么确定大小,有点像厨师做菜控制火候,适当就好,什么是适当?自己把握。

pvParameters = NULL,这个实例没有传参数,就用NULL,以后肯定是有任务要传参数的,再说。

uxPriority = 2,任务的优先级,优先级可以从0到configMAX_PRIORITIES -1,越大优先级越高。

pxCreatedTask = &myTask01_Handle,任务句柄。句柄相当于一个演员的代理人,你以后要是有事情要找那个演员,你就直接找代理人就是的,代理人知道演员的一切信息。当然了也可以不用代理人,直接找演员本人,那就把pxCreatedTask = NULL就行了。

三、创建任务

前面都说的差不多了,直接贴上代码;

创建函数,就是调用xTaskCreate函数就行了,不过本人喜欢用动态创建函数,还有一个静态的创建方法,有机会再说了。在xTaskCreate函数中,把任务的几个要素填进去就行了,问题最多的地方就是任务栈的大小了,要看看你给系统配置的堆空间是不是够的,这些问题,代买编译一下就能看出来的。

#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "gpio.h"
#include "usart.h"/*定义任务句柄*/
TaskHandle_t myTask01_Handle;
TaskHandle_t myTask02_Handle;
TaskHandle_t myTask03_Handle;/*声明任务*/
void myTask01(void *argument);
void myTask02(void *argument);
void myTask03(void *argument);void FREERTOS_Init(void); /*** @brief  在FreeRTOS初始化的时候把任务函数创建了*/
void FREERTOS_Init(void) {taskENTER_CRITICAL(); /*creation of myTask01*/xTaskCreate(    (TaskFunction_t) myTask01,    //任务指针,就是任务的函数名(const char *) "myTask01",    //任务的名字100,                         //任务的栈大小,单位是字(void * ) NULL,               //调用任务时传入的参数(UBaseType_t) 2,              //优先级(TaskHandle_t *) &myTask01_Handle );  //任务句柄/* creation of myTask02 */xTaskCreate(    (TaskFunction_t) myTask02,(const char *) "myTask02",50,(void * ) NULL,(UBaseType_t) 3,(TaskHandle_t *) &myTask02_Handle );/* creation of myTask03 */xTaskCreate(    (TaskFunction_t) myTask03,(const char *) "myTask03",50,(void * ) NULL,(UBaseType_t) 2,(TaskHandle_t *) &myTask03_Handle );taskEXIT_CRITICAL();             
}//myTask01函数主体
void myTask01(void *argument)
{/*大循环*/for(;;){/*任务的具体内容*/RLED_TOGGLE();printf("myTask01 is running!!!");/*任务阻塞*/vTaskDelay(500);}
}//myTask02函数主体
void myTask02(void *argument)
{for(;;){GLED_TOGGLE();printf("myTask02 is running!!!");vTaskDelay(1000);}
}//myTask03函数主体
void myTask03(void *argument)
{for(;;){BLED_TOGGLE();printf("myTask03 is running!!!");vTaskDelay(1500);}
}

四、使用任务参数

结合前面的内容知道,创建任务的函数共有6个要素,我想用同一个函数来实现不同的任务怎么办?

所谓同一个函数,就是说函数名是一样的,要区别他们主要就看他们传入的参数和栈了。参数不同,那函数就不相同了,同样叫小明,噶荔枝的小明和没噶荔枝的小明是不一样的;15岁的小明和50岁的小明也是不一样的,湖北的小明和浙江的小明依然是不一样的。

下面用代码来试一下,任务函数就叫Xiaoming,任务内容就是把参数打印出来。

void Xiaoming(void *argument)
{const char  *pcTaskText = argument;for(;;){printf("%s is running\r\n", pcTaskText);vTaskDelay(1000);}
}

创建函数的时候,函数名都是小明,参数和栈不一样

    xTaskCreate(    (TaskFunction_t) Xiaoming,    //任务指针,就是任务的函数名(const char *) "Xiaoming01",    //任务的名字100,                         //任务的栈大小,单位是字(void * ) pcTest1,               //调用任务时传入的参数(UBaseType_t) 2,              //优先级(TaskHandle_t *) &Xiaoming01_Handle );  //任务句柄xTaskCreate(    (TaskFunction_t) Xiaoming,    //任务指针,就是任务的函数名(const char *) "Xiaoming02",    //任务的名字50,                         //任务的栈大小,单位是字(void * ) pcTest2,               //调用任务时传入的参数(UBaseType_t) 2,              //优先级(TaskHandle_t *) &Xiaoming02_Handle );  //任务句柄

传的参数分别是

static const char *pcTest1= "没噶荔枝的小明";
static const char *pcTest2= "噶荔枝的小明";

打印结果肯定是不一样的,结果如下:

五、删除任务

删除任务函数

void vTaskDelete( TaskHandle_t xTaskToDelete )

xTaskToDelete 为NULL,就表示删除自己,也就是自杀;

xTaskToDelete 为其他句柄时就表示删除其他的任务,也就是杀别人;

xTaskToDelete就是一把刀,谁都可以拿,不管优先级的高低;谁都可以删,也不管优先级的高低;

下面的代码是任务1,删除自己后,任务2再重新创建任务1,当然也可以不创建,看看效果

//myTask01函数主体
void myTask01(void *argument)
{/*大循环*/for(;;){/*任务的具体内容*/RLED_TOGGLE();printf("myTask01 is running!!!");//删除自己vTaskDelete(NULL);/*任务阻塞*/vTaskDelay(500);}
}//myTask02函数主体
void myTask02(void *argument)
{for(;;){GLED_TOGGLE();printf("myTask02 is running!!!");
//    xTaskCreate(    (TaskFunction_t) myTask01,
//                (const char *) "myTask01",
//                 50,
//                (void * ) NULL,
//                (UBaseType_t) 2,
//                (TaskHandle_t *) &myTask01_Handle );vTaskDelay(1000);}
}

六、任务的优先级

这个自己去设置优先级的数字,数字越大,优先级越高,但是最高不要超过配置文件的设置的值。

七、任务延迟函数

void vTaskDelay( const TickType_t xTicksToDelay )
void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )

vTaskDelay函数不是很精确;

vTaskDelayUntil函数是精确的延时;

八、空闲任务与钩子函数

空闲任务,字面意思就是系统在空闲时候执行的任务,也就是没有其他任务的时候系统执行的任务。

空闲任务,可以用来释放被删除任务的内存;

空闲任务的优先级最低,为0;毕竟只有其他任务全部阻塞或暂停的时候它才被执行;

空闲任务要么处于就绪态,要么处于运行态;永远不会阻塞;

这么看空闲任务像不像个下人,一家子在吃饭的时候,你不能吃,只有等所有人都吃完了你才能吃;某个人吃完了立场时,你还要去收拾人家的碗筷,你还要24小时随叫随到,不能有自己的脾气,实在是太惨了,关键这一家子还没你不行,不然那些收拾残局的事情没人做。那一桌子的吃剩下的碗筷残羹,没人清理,以后还怎么吃饭。

空闲任务的钩子函数,有点像空闲任务的回调函数,空闲任务每执行一次,钩子函数就跑一次。

但是也只能是一些低优先级的、后台运行的事情;

钩子函数不能导致空闲任务阻塞,前面说了,空闲任务就是个下人,要24小时待命的。

九、调度器

累了,自己看吧,懒得写了。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部