前言:本篇笔记参考韦东山老师,B站视频链接放在最后。
Task任务基本概念
在使用FreeRtos的程序中,可以创建多个Task来完成程序功能,Task是轻量级的独立执行单元,被FreeRtos的调度器管理,每个任务有着自己的执行函数还有堆栈用来存放数据,允许操作系统调度不同的任务来实现并发操作。
//并发执行在操作系统中指的是,多个任务在同一段时间内交替切换执行。
Task任务创建
当创建任务的时候,需要确定任务的栈大小,它用来存放切换时的局部变量,返回地址还有程序运行的数据,以保证切换任务过后的正常运行,创建任务分配栈的方式有两种,动态分配,静态分配,前者什么时候用什么时候申请,不用就可以吧内存空间释放,后者在编译时或初始化时分配固定大小的内存,任务结束后栈空间空间被固定不能使用函数释放。
动态分配内存函数原型
BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode, //Task具体执行这个Function
const char *const pcName, //Task name
const configSTACK_DEPTH_TYPE usStackDepth, //分配Stack的大小 单位为word,分配10代表40 Byte
void * const pvParameters,//调用任务传入的参数
UBaseType_t uxpriority,//Task优先级
TaskHandle_t * const pxCreatedTask,//任务句柄用来操作任务,不想使用可以传入NULL
);
函数的最后一个参数 pxCreatedTask 这个位置的参数用来填写Task任务的句柄,如果需要操作这个任务,就需要操作Handle,也就是创建任务填进去的这个句柄。
静态分配内存函数原型
TaskHandle_t xTaskCreateStatic(
TaskFunction_t pxTaskCode,
const char *const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackTypet * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer,
);
创建静态任务跟动态任务不同的是,需要提前确定Buffer的大小,同时需要创建一个TCB结构体,以及一个任务句柄。
动态分配内存调用实例
xTaskCreate(OLED_Test,"Task1",128,NULL,osPriorityAboveNormal5,NULL);
这里的话,任务执行函数是不需要参数的,所以NULL,没有传参,如果执行任务需要参数还需要多个参数,改怎么办,只能在此封装,同时使用结构体的方式穿进去参数。
struct TaskPrintInfo {
uint8_t x;
uint8_t y;
char name[16];
};
static struct TaskPrintInfo g_Task1Info = {0, 0, "Task1"};
static struct TaskPrintInfo g_Task2Info = {0, 3, "Task2"};
static struct TaskPrintInfo g_Task3Info = {0, 6, "Task3"};
static int g_LCDCanUse = 1;
void LcdPrintTask(void *params)
{
struct TaskPrintInfo *pInfo = params;
uint32_t cnt = 0;
int len;
while (1)
{
/* 打印信息 */
if (g_LCDCanUse)
{
g_LCDCanUse = 0;
len = LCD_PrintString(pInfo->x, pInfo->y, pInfo->name);
len += LCD_PrintString(len, pInfo->y, ":");
LCD_PrintSignedVal(len, pInfo->y, cnt++);
g_LCDCanUse = 1;
}
mdelay(500);
}
}
xTaskCreate(LcdPrintTask, "task3", 128, &g_Task3Info, osPriorityNormal, NULL);
静态分配内存调用实例
static StackType_t g_pucStackofTtaticTask[128]; //定义栈大小
static StaticTask_t g_TCBofStatic_Task;//定义结构体
static TaskHandle_t x_Static_Task;//定义句柄
x_Static_Task = xTaskCreateStatic(OLED_Test,"Static_Task1",128,NULL,osPriorityAboveNormal1,g_pucStackofTtaticTask,&g_TCBofStatic_Task);
静态任务在使用的时候,需要提前创建栈的大小和定义TCB结构体,同时定义任务返回句柄,动态任务就不用了,定义的话都是使用,匿名结构体关键字去定义的。
删除Task函数
上面有讲到,Task的创建方式有动态方式跟静态方式,二者都可以被函数删除,但是区别在于动态任务被删除之后,会自动释放栈跟TCB所占用的内存,如果是静态任务,由于给静态任务分配的栈是用户定义和分配的,就导致了在删除静态任务的时候这些栈和内存空间不会被释放,在删除之后可以考虑是否重用这些内存空间。
同时Delete函数还有一个很重要的作用,在Task任务执行完成之后,C语言中是会返回的,但在FreeRtos操作系统的内核中,当任务结束返回的时候,Tick中断会被关闭,同时进入for(;;),死循环,这个时候没有delete这个函数,那么整个系统就会死机,不会切换Task,不会有任何响应。
函数原型
TaskHandle_t xHandle = xTaskCreateStatic(OLED_Test,"Static_Task1",128,NULL,osPriorityAboveNormal1,g_pucStackofTtaticTask,&g_TCBofStatic_Task);
xTaskCreate(PlayMusic, "SoundTask", 128, NULL, osPriorityNormal, &xSoundTaskHandle);
void vTaskDelete( TaskHandle_t xTaskToDelete );
在对Task进行删除的时候,需要一个参数就是句柄,这个任务参数,通常用在,任务删除,任务恢复,挂起,都是通过填写这个参数来,操作对应的Task,创建静态任务的函数参数里面,没有句柄,但是在函数定义一面,其实是句柄返回值的,所以我们需要创建一个句柄,来等于这个静态函数的创建。
删除任务演示
TaskHandle_t xHandle = xTaskCreateStatic(OLED_Test,"Static_Task1",128,NULL,osPriorityAboveNormal1,g_pucStackofTtaticTask,&g_TCBofStatic_Task);//创建静态任务
xTaskCreate(PlayMusic, "SoundTask", 128, NULL, osPriorityNormal, &xSoundTaskHandle);//创建动态任务
vTaskDelete( xSoundTaskHandle); //删除动态任务
vTaskDelete( xHandle); //删除静态任务
这里用句柄就能删除了。
挂起函数恢复函数
在操作系统中Task的状态有四种 Ready(准备)Runing(运行)Block(阻塞)Suspend(挂起)四种状态之间可以相互转换,Suspend函数用来将任务调整为挂起状态,同样的挂起状态的任务使用Resume函数时候进行Ready状态。
在Task从执行状态转换为Suspend状态的时候,会放弃cpu资源,当从Suspend状态Resume为准备状态的时候,在等待cpu资源才能,继续运行。
函数原型
void vTaskResume(TaskHandle_t xTaskToResume);
void vTaskSuspend(TaskHandle_t xTaskToSuspend);
这里挂起,恢复任务,和上面的删除函数是一样的,参数只需要任务的句柄,然后就能对指定任务进行操作。
挂起状态和阻滞状态的区别
这里使用Suspend函数对Task进行挂起,意味着Task被人为停止,只有等到Resume函数才能运行执行,在此期间是不能被调用的,vTaskDelay()这个延时函数会是Task放弃Cpu资源进入阻塞状态,当时间达到之后(满足条件),会自动进入就绪转态。
挂起恢复动态/静态任务
TaskHandle_t xHandle = xTaskCreateStatic(OLED_Test,"Static_Task1",128,NULL,osPriorityAboveNormal1,g_pucStackofTtaticTask,&g_TCBofStatic_Task);//创建静态任务
xTaskCreate(PlayMusic, "SoundTask", 128, NULL, osPriorityNormal, &xSoundTaskHandle);//创建动态任务
vTaskSuspend( xSoundTaskHandle); //挂起动态任务
vTaskResume(xSoundTaskHandle);//恢复动态任务
vTaskSuspend( xHandle); //删除静态任务
vTaskResume( xHandle);//恢复动态任务
Task延时函数
在FreeRtos里面有三种延时函数 Delay( ) vTaskDelay() vTaskDelayUntil() 前者是不同延时,当Task使用 Delay( )的时候,Task会拿着cpu资源等待时间到来,等的时候cpu资源不会分配出去,当Task使用 vTaskDelay() 的时候,执行这个语句的时候,Task会进入阻塞状态,交出CPU资源,等在时间结束,进入就绪状态,按照优先级在此分配CPU资源,当Task使用 vTaskDelayUntil() 的时候,这个延时叫做绝对延时,区别在于,带上Task执行时间一共延时多长时间,当Task执行时间短,vTaskDelayUntil()会多延时,达到固定时间,如果长,vTaskDelayUntil()会短延时,从而达到延时绝对时间的目的。
函数原型
void vTaskDelay( const TickType_t xTicksToDelay );
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement );
[5-3]_删除任务_用遥控器控制音乐_哔哩哔哩_bilibili