FreeRTOS的任务创建和删除

FreeRTOS的任务创建和删除

任务创建和删除的API函数解析

1、动态创建任务其内部实现

        1、 申请堆栈内存(返回首地址)

        2、 申请任务控制块内存(返回首地址)

        3、 把前面申请的堆栈地址,赋值给控制块的堆栈成员

        4、 调用prvInitialiseNewTask 初始化任务控制块中的成员

                1、初始化堆栈为0xa5(可选)

                2、记录栈顶,保存在pxTopOfStack

                3、保存任务名字到pxNewTCB->pcTaskName[ x ]中

1,任务创建和删除的API函数

任务的创建和删除本质就是调用FreeRTOS的API函数

API函数

描述

xTaskCreate()

动态方式创建任务

xTaskCreateStatic()

静态方式创建任务

vTaskDelete()

删除任务

动态创建任务:

        任务的任务控制块以及任务的栈空间所需的内存,均由 FreeRTOS 从 FreeRTOS 管理的堆中分配。

静态创建任务:

        任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供

动态创建任务函数:

BaseType_t xTaskCreate ( 
                         TaskFunction_t pxTaskCode, /* 指向任务函数的指针 / 
                         const char * const pcName, / 任务名字,最大长度  configMAX_TASK_NAME_LEN / 
                         const configSTACK_DEPTH_TYPE usStackDepth, / 任务堆栈大小,注意字为单位 / 
                         void * const pvParameters, / 传递给任务函数的参数 / 
                         UBaseType_t uxPriority, / 任务优先级,范围:0 ~configMAX_PRIORITIES - 1 / 
                         TaskHandle_t * const pxCreatedTask / 任务句柄,就是任务的任务控制块 */ 
                        )

返回值

描述

pdPASS

任务创建成功

errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY

任务创建失败

实现动态创建任务流程

        1、将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1。

        2、定义函数入口参数。

        3、编写任务函数。

        此函数创建的任务会立刻进入就绪态,由任务调度器调度运行。

动态创建任务函数内部实现

        1、申请堆栈内存&任务控制块内存。

        2、TCB结构体成员赋值。

        3、添加新任务到就绪列表中。

任务控制块结构体成员介绍

typedef struct tskTaskControlBlock { 
                                        volatile StackType_t * pxTopOfStack; /* 任务栈栈顶,必须为TCB的第一个成员 / 
                                        ListItem_t xStateListItem; / 任务状态列表项 /
                                        ListItem_t xEventListItem; / 任务事件列表项 / 
                                        UBaseType_t uxPriority; / 任务优先级,数值越大,优先级越大 / 
                                        StackType_t * pxStack; / 任务栈起始地址 / 
                                        char pcTaskName[ configMAX_TASK_NAME_LEN ]; / 任务名字 */ 
                                        … 省略很多条件编译的成员 
                                    } tskTCB;

任务栈栈顶,在任务切换时的任务上下文保存、任务恢复息息相关。

注意:每个任务都有属于自己的任务控制块,类似身份证。

静态创建任务函数

TaskHandle_t xTaskCreateStatic ( 
                                    TaskFunction_t pxTaskCode, /* 指向任务函数的指针 / 
                                    const char * const pcName, / 任务函数名 / 
                                    const uint32_t ulStackDepth, / 任务堆栈大小注意字为单位 / 
                                    void * const pvParameters, / 传递的任务函数参数 /     
                                    UBaseType_t uxPriority, / 任务优先级 / 
                                    StackType_t * const puxStackBuffer, / 任务堆栈,一般为数组,由用户分配 / 
                                    StaticTask_t * const pxTaskBuffer / 任务控制块指针,由用户分配 */ 
                                );

返回值

描述

NULL

用户没有提供相应的内存,任务创建失败

其他值

任务句柄,任务创建成功

静态创建任务使用流程

        1、需将宏configSUPPORT_STATIC_ALLOCATION 配置为 1。

        2、定义空闲任务&定时器任务的任务堆栈及TCB。(stm32中的栈时向下生长的,而堆是向上生长的)

        3、实现两个接口函数。

                vApplicationGetIdleTaskMemory( );

                vApplicationGetTimerTaskMemory ( );

        4、定义函数入口参数。

        5、编写任务函数。

        此函数创建的任务会立刻进入就绪态,由任务调度器调度运行。

静态创建内部实现

        1、TCB结构体成员赋值。

        2、添加新任务到就绪列表中。

任务删除函数

void vTaskDelete(TaskHandle_t xTaskToDelete);

形参

描述

xTaskToDelete

待删除任务的任务句柄

用于删除已被创建的任务。

被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除

注意:

        1、当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)。

        2、空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存, 则需要由用户在任务被删除前提前释放,否则将导致内存泄露。

删除任务流程

        1、使用删除任务函数,需将宏INCLUDE_vTaskDelete 配置为 1

        2、入口参数输入需要删除的任务句柄(NULL代表删除本身

内部实现过程

        1、获取所要删除任务的控制块:通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身。

        2、将被删除任务,移除所在列表:将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表

        3、判断所需要删除的任务:

                删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务执行

                删除其他任务,释放内存,任务数量--

        4、更新下个任务的阻塞时间:更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务

2,任务创建和删除(动态方法)

1、实验目的:学会 xTaskCreate( ) 和 vTaskDelete( ) 的使用。

2、实验设计:将设计四个任务:start_task、task1、task2、task3

四个任务的功能如下:

start_task:用来创建其他的三个任务。

task1:实现LED0每500ms闪烁一次。

task2:实现LED1每500ms闪烁一次。

task3:判断按键KEY0是否按下,按下则删掉task1。

#include "FreeRTOS.h"
#include "task.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_usart.h"

//任务占空间大小
#define Start_Task_STACK_SIZE    128
#define Task1_STACK_SIZE    128
#define Task2_STACK_SIZE    128
#define Task3_STACK_SIZE    128

//任务优先级
#define Start_Task_PRIORITY        1
#define Task1_PRIORITY            2
#define Task2_PRIORITY            3
#define Task3_PRIORITY            4

//任务句柄
TaskHandle_t Start_Task_Handle = NULL;
TaskHandle_t Task1_Handle = NULL;
TaskHandle_t Task2_Handle = NULL;
TaskHandle_t Task3_Handle = NULL;

//任务函数声明
void BSP_Init(void);
void start_task( void * pvParameters );
void task1( void * pvParameters );
void task2( void * pvParameters );
void task3( void * pvParameters );

//主函数
int main(void)
{    
    BaseType_t xReturn;
    
    BSP_Init();

    //开始任务的创建
    xReturn = xTaskCreate((TaskFunction_t) start_task,
                (char *        ) "pcName",
                (uint16_t      ) Start_Task_STACK_SIZE,
                (void *        ) NULL,
                (UBaseType_t   ) Start_Task_PRIORITY,
                (TaskHandle_t *) &Start_Task_Handle);
    if(xReturn == pdPASS)
        vTaskStartScheduler(); //开启任务调度
    else
        return -1;
}

//板级硬件初始化
void BSP_Init(void)
{
    //STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    
    //LED 初始化
    LED_GPIO_Config();
    
    //串口初始化
    USART_Config();
    
    //按键初始化
    Key_GPIO_Config();
}

//用来创建其他的三个任务
void start_task( void * pvParameters )
{
    BaseType_t xReturn;
    taskENTER_CRITICAL();           //进入临界区(其实就是关闭中断)
    
    //task1任务创建
    xReturn = xTaskCreate((TaskFunction_t) task1,
                          (char *        ) "task1",
                          (uint16_t      ) Task1_STACK_SIZE,
                          (void *        ) NULL,
                          (UBaseType_t   ) Task1_PRIORITY,
                          (TaskHandle_t *) &Task1_Handle);
    if(xReturn == pdPASS)
        printf("task1创建成功\r\n");
    else
        printf("task1创建失败\r\n");                  
                    
    //task2任务创建
    xReturn = xTaskCreate((TaskFunction_t) task2,
                          (char *        ) "task2",
                          (uint16_t      ) Task2_STACK_SIZE,
                          (void *        ) NULL,
                          (UBaseType_t   ) Task2_PRIORITY,
                          (TaskHandle_t *) &Task2_Handle);
    if(xReturn == pdPASS)
        printf("task2创建成功\r\n");
    else
        printf("task2创建失败\r\n");    

    //task3任务创建
    xReturn = xTaskCreate((TaskFunction_t) task3,
                          (char *        ) "task3",
                          (uint16_t      ) Task2_STACK_SIZE,
                          (void *        ) NULL,
                          (UBaseType_t   ) Task2_PRIORITY,
                          (TaskHandle_t *) &Task2_Handle);                          
    if(xReturn == pdPASS)
        printf("task3创建成功\r\n");
    else
        printf("task3创建失败\r\n");        
    
    vTaskDelete(NULL); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//实现LED1每500ms闪烁一次
void task1( void * pvParameters )
{
    while(1)
    {
        printf("task1正在运行!!!\r\n");
        LED1_TOGGLE;
        vTaskDelay(500);
    }
}

//实现LED2每500ms闪烁一次
void task2( void * pvParameters )
{
    while(1)
    {
        printf("task2正在运行!!!\r\n");
        LED2_TOGGLE;
        vTaskDelay(500);
    }
}

//判断按键KEY1是否按下,按下则删掉task1
void task3( void * pvParameters )
{
    uint8_t key_state;
    while(1)
    {
        printf("task3正在运行!!!\r\n");
        key_state = Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
        if(key_state == KEY_ON)
        {
            if(Task1_Handle != NULL)
            {
                printf("删除task1任务\r\n");
                vTaskDelete(Task1_Handle);
                Task1_Handle = NULL;
            }
        }    
        vTaskDelay(10);
    }
}

3,任务创建和删除(静态方法)

1、实验目的:学会 xTaskCreate( ) 和 vTaskDelete( ) 的使用。

2、实验设计:将设计四个任务:start_task、task1、task2、task3

四个任务的功能如下:

start_task:用来创建其他的三个任务。

task1:实现LED1每500ms闪烁一次。

task2:实现LED2每500ms闪烁一次。

task3:判断按键KEY1是否按下,按下则删掉task1。

#include "FreeRTOS.h"
#include "task.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_usart.h"

//任务占空间大小
#define Start_Task_STACK_SIZE	128
#define Task1_STACK_SIZE	128
#define Task2_STACK_SIZE	128
#define Task3_STACK_SIZE	128

//任务优先级
#define Start_Task_PRIORITY		1
#define Task1_PRIORITY			2
#define Task2_PRIORITY			3
#define Task3_PRIORITY			4

//任务句柄
TaskHandle_t Start_Task_Handle = NULL;
TaskHandle_t Task1_Handle = NULL;
TaskHandle_t Task2_Handle = NULL;
TaskHandle_t Task3_Handle = NULL;

//任务堆栈
StackType_t Start_Task_Stack[Start_Task_STACK_SIZE];
StackType_t Task1_Stack[Task1_STACK_SIZE];
StackType_t Task2_Stack[Task2_STACK_SIZE];
StackType_t Task3_Stack[Task3_STACK_SIZE];


//任务控制块
StaticTask_t Start_Task_TCB;
StaticTask_t Task1_TCB;
StaticTask_t Task2_TCB;
StaticTask_t Task3_TCB;


//空闲任务的内存变量
StaticTask_t IdleTask_TCB;
StackType_t IdleTask_Stack[configMINIMAL_STACK_SIZE];

//定时器任务的内存变量
StaticTask_t TimerTask_TCB;
StackType_t TimerTask_Stack[configTIMER_TASK_STACK_DEPTH];

//任务函数声明
void BSP_Init(void);
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
								   StackType_t **ppxIdleTaskStackBuffer, 
								   uint32_t *pulIdleTaskStackSize);
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, 
									StackType_t **ppxTimerTaskStackBuffer, 
									uint32_t *pulTimerTaskStackSize);
void start_task( void * pvParameters );
void task1( void * pvParameters );
void task2( void * pvParameters );
void task3( void * pvParameters );

//主函数
int main(void)
{		
	BSP_Init();

	//开始任务的创建
	Start_Task_Handle = xTaskCreateStatic((TaskFunction_t) start_task,
										  (char *        ) "start_task",
										  (uint32_t      ) Start_Task_STACK_SIZE,
										  (void *        ) NULL,
										  (UBaseType_t   ) Start_Task_PRIORITY,
										  (StackType_t * ) Start_Task_Stack,
										  (StaticTask_t *) &Start_Task_TCB );
	vTaskStartScheduler(); //开启任务调度
}

//板级硬件初始化
void BSP_Init(void)
{
	//STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	//LED 初始化
	LED_GPIO_Config();
	
	//串口初始化
	USART_Config();
	
	//按键初始化
	Key_GPIO_Config();
}

//空闲任务的内存分配
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
								   StackType_t **ppxIdleTaskStackBuffer, 
								   uint32_t *pulIdleTaskStackSize)
{
	*ppxIdleTaskTCBBuffer = &IdleTask_TCB;
	*ppxIdleTaskStackBuffer = IdleTask_Stack;
	*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

//定时器任务的内存分配
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, 
									StackType_t **ppxTimerTaskStackBuffer, 
									uint32_t *pulTimerTaskStackSize)
{
	*ppxTimerTaskTCBBuffer = &TimerTask_TCB;
	*ppxTimerTaskStackBuffer = TimerTask_Stack;
	*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

//用来创建其他的三个任务
void start_task( void * pvParameters )
{	
	taskENTER_CRITICAL();           //进入临界区(其实就是关闭中断)
	
	//task1任务创建
	Task1_Handle = xTaskCreateStatic((TaskFunction_t) task1,
									 (char *        ) "task1",
									 (uint32_t      ) Task1_STACK_SIZE,
									 (void *        ) NULL,
									 (UBaseType_t   ) Task1_PRIORITY,
									 (StackType_t * ) Task1_Stack,
									 (StaticTask_t *) &Task1_TCB );
		  
					
	//task2任务创建
	Task2_Handle = xTaskCreateStatic((TaskFunction_t) task2,
									 (char *        ) "task2",
									 (uint32_t      ) Task2_STACK_SIZE,
									 (void *        ) NULL,
									 (UBaseType_t   ) Task2_PRIORITY,
									 (StackType_t * ) Task2_Stack,
									 (StaticTask_t *) &Task2_TCB );

	//task3任务创建
	Task3_Handle = xTaskCreateStatic((TaskFunction_t) task3,
									 (char *        ) "task3",
									 (uint32_t      ) Task3_STACK_SIZE,
									 (void *        ) NULL,
									 (UBaseType_t   ) Task3_PRIORITY,
									 (StackType_t * ) Task3_Stack,
									 (StaticTask_t *) &Task3_TCB );				  

	
	vTaskDelete(NULL); //删除开始任务
	taskEXIT_CRITICAL();            //退出临界区
}

//实现LED1每500ms闪烁一次
void task1( void * pvParameters )
{
	while(1)
	{
		printf("task1正在运行!!!\r\n");
		LED1_TOGGLE;
		vTaskDelay(500);
	}
}

//实现LED2每500ms闪烁一次
void task2( void * pvParameters )
{
	while(1)
	{
		printf("task2正在运行!!!\r\n");
		LED2_TOGGLE;
		vTaskDelay(500);
	}
}

//判断按键KEY1是否按下,按下则删掉task1
void task3( void * pvParameters )
{
	uint8_t key_state;
	while(1)
	{
		printf("task3正在运行!!!\r\n");
		key_state = Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
		if(key_state == KEY_ON)
		{
			if(Task1_Handle != NULL)
			{
				printf("删除task1任务\r\n");
				vTaskDelete(Task1_Handle);
				Task1_Handle = NULL;
			}
		}	
		vTaskDelay(10);
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

small陀螺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值