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);
}
}