FreeRtos中Task函数详解

                            前言:本篇笔记参考韦东山老师,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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值