任務創建和刪除的API函數
- xTaskCreate():使用動態方法創建一個任務
- xTaskCreateStatic():使用靜態方法創建一個任務
- xTaskCreateRestricated():創建一個使用MPU進行限制的任務,相關內存使用動態內存分配
- vTaskDelete():刪除一個任務
xTaskCreate
使用該函數,configSUPPORT_DYNAMIC_ALLOCATION要設置為1
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,const char * const pcName,const uint16_t usStackDepth,void * const pvParameters,UBaseType_t uxPriority,TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
#endif
- pxTaskCode:函數名,任務執行的函數,我們可以把一個任務當做一個函數,只不過這個函數可以循環執行
- pcName:任務名字,一般用于追蹤和調試,任務名字不能超過configMAX_TASK_NAME_LEN,configMAX_TASK_NAME_LEN在FreeRTOSConfig.h文件中
- usStackDepth:任務堆棧大小,實際申請到的堆棧是usStackDepth的4倍,其中空閑任務堆棧大小為configMINIMAL_STACK_SIZE,configMINIMAL_STACK_SIZE在FreeRTOSConfig.h文件中定義
- pvParameters:傳遞給任務函數的參數
- uxPriority:任務優先級,范圍是0-configMAX_PRIORITIES-1
- pxCreatedTask:任務句柄,任務創建成功后會返回此任務的任務句柄。
返回值:
pdPASS if the task was successfully created and added to a ready list, otherwise an error code defined in the file projdefs.h
xTaskCreateStatic
使用該函數,configSUPPORT_STATIC_ALLOCATION要等于1
#if( configSUPPORT_STATIC_ALLOCATION == 1 )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 ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
#endif /* configSUPPORT_STATIC_ALLOCATION */
參數的具體函數可以看xTaskCreate,
- ulStackDepth:需要由用戶給出,一般是一個數組,此參數就是這個數組的大小
- puxStackBuffer:Must point to a StackType_t array that has at least ulStackDepth indexes - the array will then be used as the task’s stack,removing the need for the stack to be allocated dynamically.
- pxTaskBuffer:任務控制塊,pxTaskBuffer Must point to a variable of type StaticTask_t, which will then be used to hold the task’s data structures, removing the need for the memory to be allocated dynamically.
返回值:
If neither pxStackBuffer or pxTaskBuffer are NULL, then the task will be created and pdPASS is returned. If either pxStackBuffer or pxTaskBuffer are NULL then the task will not be created and errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned.
xTaskCreateRestricted
使用該函數,portUSING_MPU_WRAPPERS=1
#if( portUSING_MPU_WRAPPERS == 1 )BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION;
#endif
- pxTaskDefinition:是一個結構體,描述任務函數、堆棧大小優先級等,在task.h定義
- pxCreatedTask:任務句柄
vTaskDelete
void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;
- xTaskToDelete:要刪除任務的任務句柄
被刪除的任務不再存在,對于那些有內核自動分配給任務的內存,該函數會自動釋放掉,用戶給任務分配的內存需要用戶自行釋放掉,比如pvPortMalloc()分配了500字節的內存,那么在任務被刪除之后,用戶需要調用vPortFree函數將這些內存刪除,否則會導致內存泄露
設計
一共有三個任務:
- start_task:用來創建其他兩個任務
- task1_task:次任務運行5次以后,調用vTaskDelete刪除任務task2_task,此任務也會控制LED0閃爍,并且周期性刷新LCD指定區域的背景顏色
- task2_task:此任務普通的應用任務,會控制LED1的閃爍,并且周期性的率先LCD指定區域的背景顏色
動態創建
main函數代碼:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "lcd.h"
#include "sdram.h"//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define TASK1_TASK_PRIO 2
//任務堆棧大小
#define TASK1_STK_SIZE 128
//任務句柄
TaskHandle_t Task1Task_Handler;
//任務函數
void task1_task(void *pvParameters);//任務優先級
#define TASK2_TASK_PRIO 3
//任務堆棧大小
#define TASK2_STK_SIZE 128
//任務句柄
TaskHandle_t Task2Task_Handler;
//任務函數
void task2_task(void *pvParameters);//LCD刷屏時使用的顏色
int lcd_discolor[14] = {WHITE ,BLACK,BLUE,BRED,GRED,GBLUE,RED,MAGENTA,GREEN,CYAN,YELLOW,BROWN,BRRED,GRAY};int main(void)
{HAL_Init(); //初始化HAL庫 Stm32_Clock_Init(360,25,2,8); //設置時鐘,180Mhzdelay_init(180); //初始化延時函數LED_Init(); //LED初始化ACR_BYTE0_ADDRESSuart_init(115200);SDRAM_Init();LCD_Init(); POINT_COLOR = RED;LCD_ShowString(30,10,200,16,16,"Apolo STM32F4/F7");LCD_ShowString(30,30,200,16,16,"FreeeRTOS Examples");LCD_ShowString(30,50,200,16,16,"Task create and delete");LCD_ShowString(30,70,200,16,16,"2021/11/20");xTaskCreate(start_task, //任務函數"start_task", //任務名稱START_STK_SIZE, //任務堆棧大小NULL, //傳遞給任務函數的參數START_TASK_PRIO, //任務優先級&StartTask_Handler); //任務句柄 vTaskStartScheduler(); //開啟任務調度}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建TASK1任務xTaskCreate(task1_task, "task1_task", TASK1_STK_SIZE, NULL, TASK1_TASK_PRIO, &Task1Task_Handler); //創建TASK2任務xTaskCreate(task2_task, "task2_task", TASK2_STK_SIZE,NULL,TASK2_TASK_PRIO,&Task2Task_Handler); vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
}
//task1任務函數
void task1_task(void *pvParameters)
{u8 task1_num=0;POINT_COLOR = BLACK;LCD_DrawRectangle(5,110,115,314); //畫一個矩形 LCD_DrawLine(5,130,115,130); //畫線POINT_COLOR = BLUE;LCD_ShowString(6,111,110,16,16,"Task1 Run:000");while(1){task1_num++; //任務執1行次數加1 注意task1_num1加到255的時候會清零!!LED0=!LED0;//printf("任務1已經執行:%d次\r\n",task1_num);if(task1_num==5) {if(Task2Task_Handler != NULL) //任務2是否存在? {vTaskDelete(Task2Task_Handler); //任務1執行5次刪除任務2Task2Task_Handler=NULL; //任務句柄清零//printf("任務1刪除了任務2!\r\n");}}LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充區域LCD_ShowxNum(86,111,task1_num,3,16,0x80); //顯示任務執行次數vTaskDelay(1000); //延時1s,也就是1000個時鐘節拍 }
}//task2任務函數
void task2_task(void *pvParameters)
{u8 task2_num=0;POINT_COLOR = BLACK;LCD_DrawRectangle(125,110,234,314); //畫一個矩形 LCD_DrawLine(125,130,234,130); //畫線POINT_COLOR = BLUE;LCD_ShowString(126,111,110,16,16,"Task2 Run:000");while(1){task2_num++; //任務2執行次數加1 注意task1_num2加到255的時候會清零!!LED1=!LED1;//printf("任務2已經執行:%d次\r\n",task2_num);LCD_ShowxNum(206,111,task2_num,3,16,0x80); //顯示任務執行次數LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充區域vTaskDelay(1000); //延時1s,也就是1000個時鐘節拍 }
}
靜態創建
使用靜態創建任務需要在FreeRTOSConfig.h將宏configSUPPORT_STATIC_ALLOCATION設置為1,配置完成之后還需要實現兩個函數,vApplicationGetIdleTaskMemory和vApplicationGetTimerTaskMemory,通過這兩個來給空閑任務和定時器服務任務的任務堆棧和任務控制塊分配內存,這兩個函數,我們在main.c里面定義:
//空閑任務任務堆棧
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
//空閑任務控制塊
static StaticTask_t IdleTaskTCB;//定時器服務任務堆棧
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
//定時器服務任務控制塊
static StaticTask_t TimerTaskTCB;
//獲取空閑任務地任務堆棧和任務控制塊內存,因為本例程使用的
//靜態內存,因此空閑任務的任務堆棧和任務控制塊的內存就應該
//有用戶來提供,FreeRTOS提供了接口函數vApplicationGetIdleTaskMemory()
//實現此函數即可。
//ppxIdleTaskTCBBuffer:任務控制塊內存
//ppxIdleTaskStackBuffer:任務堆棧內存
//pulIdleTaskStackSize:任務堆棧大小
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
{*ppxIdleTaskTCBBuffer=&IdleTaskTCB;*ppxIdleTaskStackBuffer=IdleTaskStack;*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}
//獲取定時器服務任務的任務堆棧和任務控制塊內存
//ppxTimerTaskTCBBuffer:任務控制塊內存
//ppxTimerTaskStackBuffer:任務堆棧內存
//pulTimerTaskStackSize:任務堆棧大小
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize)
{*ppxTimerTaskTCBBuffer=&TimerTaskTCB;*ppxTimerTaskStackBuffer=TimerTaskStack;*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
}
main函數里面內容為:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "lcd.h"
#include "sdram.h"//空閑任務任務堆棧
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE];
//空閑任務控制塊
static StaticTask_t IdleTaskTCB;//定時器服務任務堆棧
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH];
//定時器服務任務控制塊
static StaticTask_t TimerTaskTCB;//任務優先級
#define START_TASK_PRIO 1
//任務堆棧大小
#define START_STK_SIZE 128
//任務堆棧
StackType_t StartTaskStack[START_STK_SIZE];
//任務控制塊
StaticTask_t StartTaskTCB;
//任務句柄
TaskHandle_t StartTask_Handler;
//任務函數
void start_task(void *pvParameters);//任務優先級
#define TASK1_TASK_PRIO 2
//任務堆棧大小
#define TASK1_STK_SIZE 128
//任務堆棧
StackType_t Task1TaskStack[TASK1_STK_SIZE];
//任務控制塊
StaticTask_t Task1TaskTCB;
//任務句柄
TaskHandle_t Task1Task_Handler;
//任務函數
void task1_task(void *pvParameters);//任務優先級
#define TASK2_TASK_PRIO 3
//任務堆棧大小
#define TASK2_STK_SIZE 128
//任務堆棧
StackType_t Task2TaskStack[TASK2_STK_SIZE];
//任務控制塊
StaticTask_t Task2TaskTCB;
//任務句柄
TaskHandle_t Task2Task_Handler;
//任務函數
void task2_task(void *pvParameters);//獲取空閑任務地任務堆棧和任務控制塊內存,因為本例程使用的
//靜態內存,因此空閑任務的任務堆棧和任務控制塊的內存就應該
//有用戶來提供,FreeRTOS提供了接口函數vApplicationGetIdleTaskMemory()
//實現此函數即可。
//ppxIdleTaskTCBBuffer:任務控制塊內存
//ppxIdleTaskStackBuffer:任務堆棧內存
//pulIdleTaskStackSize:任務堆棧大小
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
{*ppxIdleTaskTCBBuffer=&IdleTaskTCB;*ppxIdleTaskStackBuffer=IdleTaskStack;*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}
//獲取定時器服務任務的任務堆棧和任務控制塊內存
//ppxTimerTaskTCBBuffer:任務控制塊內存
//ppxTimerTaskStackBuffer:任務堆棧內存
//pulTimerTaskStackSize:任務堆棧大小
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize)
{*ppxTimerTaskTCBBuffer=&TimerTaskTCB;*ppxTimerTaskStackBuffer=TimerTaskStack;*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
}//LCD刷屏時使用的顏色
int lcd_discolor[14] = {WHITE ,BLACK,BLUE,BRED,GRED,GBLUE,RED,MAGENTA,GREEN,CYAN,YELLOW,BROWN,BRRED,GRAY};int main(void)
{HAL_Init(); //初始化HAL庫 Stm32_Clock_Init(360,25,2,8); //設置時鐘,180Mhzdelay_init(180); //初始化延時函數LED_Init(); //LED初始化ACR_BYTE0_ADDRESSuart_init(115200);SDRAM_Init();LCD_Init(); POINT_COLOR = RED;LCD_ShowString(30,10,200,16,16,"Apolo STM32F4/F7");LCD_ShowString(30,30,200,16,16,"FreeeRTOS Examples");LCD_ShowString(30,50,200,16,16,"Task create and delete");LCD_ShowString(30,70,200,16,16,"2021/11/20");StartTask_Handler= xTaskCreateStatic(start_task,"start_task",START_STK_SIZE,NULL, START_TASK_PRIO,StartTaskStack,&Task1TaskTCB); vTaskStartScheduler(); //開啟任務調度}//開始任務任務函數
void start_task(void *pvParameters)
{taskENTER_CRITICAL(); //進入臨界區//創建TASK1任務Task1Task_Handler=xTaskCreateStatic((TaskFunction_t )task1_task, (const char* )"task1_task", (uint32_t )TASK1_STK_SIZE, (void* )NULL, (UBaseType_t )TASK1_TASK_PRIO, (StackType_t* )Task1TaskStack, (StaticTask_t* )&Task1TaskTCB); //創建TASK2任務Task2Task_Handler=xTaskCreateStatic(task2_task, "task2_task", TASK2_STK_SIZE,NULL,TASK2_TASK_PRIO,Task2TaskStack,&Task2TaskTCB); vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
}
//task1任務函數
void task1_task(void *pvParameters)
{u8 task1_num=0;POINT_COLOR = BLACK;LCD_DrawRectangle(5,110,115,314); //畫一個矩形 LCD_DrawLine(5,130,115,130); //畫線POINT_COLOR = BLUE;LCD_ShowString(6,111,110,16,16,"Task1 Run:000");while(1){task1_num++; //任務執1行次數加1 注意task1_num1加到255的時候會清零!!LED0=!LED0;//printf("任務1已經執行:%d次\r\n",task1_num);if(task1_num==5) {if(Task2Task_Handler != NULL) //任務2是否存在? {vTaskDelete(Task2Task_Handler); //任務1執行5次刪除任務2Task2Task_Handler=NULL; //任務句柄清零//printf("任務1刪除了任務2!\r\n");}}LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充區域LCD_ShowxNum(86,111,task1_num,3,16,0x80); //顯示任務執行次數vTaskDelay(1000); //延時1s,也就是1000個時鐘節拍 }
}//task2任務函數
void task2_task(void *pvParameters)
{u8 task2_num=0;POINT_COLOR = BLACK;LCD_DrawRectangle(125,110,234,314); //畫一個矩形 LCD_DrawLine(125,130,234,130); //畫線POINT_COLOR = BLUE;LCD_ShowString(126,111,110,16,16,"Task2 Run:000");while(1){task2_num++; //任務2執行次數加1 注意task1_num2加到255的時候會清零!!LED1=!LED1;//printf("任務2已經執行:%d次\r\n",task2_num);LCD_ShowxNum(206,111,task2_num,3,16,0x80); //顯示任務執行次數LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充區域vTaskDelay(1000); //延時1s,也就是1000個時鐘節拍 }
}
編譯即可