1.在前面的文章中介绍了FreeRTOS的动态创建方法,本文介绍一下FreeRTOS的静态任务创建方法xTaskCreateStatic()。相比较动态任务创建过程,静态创创建任务的过程稍显复杂。主要步骤为:
(1)配置相关的宏定义:configSUPPORT_STATIC_ALLOCATION。
(2)实现部分接口函数,用来给空闲任务的任务堆栈和任务控制块分配内存。
(3)配置静态创建任务函数的入口参数。
2.配置相关的宏定义:
将支持静态内存分配的宏定义configSUPPORT_STATIC_ALLOCATION设置为1:
配置静态任务相关的宏定义:
本文开启软件定时器任务,所以需要将软件定时器的宏定义configUSE_TIMERS设置为1:
3.实现接口函数:
(1)重写空闲任务堆栈和任务控制块内存分配的API函数vApplicationGetIdleTaskMemory:
(2)重写软件定时器任务堆栈和任务控制块内存分配的API函数vApplicationGetTimerTaskMemory:
4.配置静态创建任务函数的入口参数:
此处注意的是,静态创建任务时需要用户自己提供任务堆栈,本文自行定义了一个数组作为任务堆栈,堆栈数组为 StackType_t 类型。任务控制块的类型为StaticTask_t。
5.代码:
因为本文和前面动态创建任务实现的功能是相同的,所以本文不再展示所有的代码,仅展示main函数中代码。与前面的动态创建任务相比较,除了上述的宏定义配置外,本文只main函数有修改的地方。
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "sys.h"
static StaticTask_t IdleTaskTCB; //¿ÕÏÐÈÎÎñ¿ØÖÆ¿é
static StackType_t IdleTaskStack[configMINIMAL_STACK_SIZE]; //¿ÕÏÐÈÎÎñ¶ÑÕ»
/*ÖØд¿ÕÏÐÈÎÎñ¶ÑÕ»ºÍÈÎÎñ¿ØÖÆ¿éÄÚ´æ*/
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
*ppxIdleTaskTCBBuffer = &IdleTaskTCB; //ÈÎÎñ¿ØÖÆ¿éÄÚ´æ
*ppxIdleTaskStackBuffer = IdleTaskStack; //ÈÎÎñ¶ÑÄÚ´æ
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; //ÈÎÎñ¶ÑÕ»´óС
}
static StaticTask_t TimerTaskTCB; //¶¨Ê±Æ÷ÈÎÎñ¿ØÖÆ¿é
static StackType_t TimerTaskStack[configTIMER_TASK_STACK_DEPTH]; //¶¨Ê±Æ÷·þÎñº¯Êý¶ÑÕ»
/*ÖØд¶¨Ê±Æ÷·þÎñÈÎÎñµÄ¶ÑÕ»ºÍÈÎÎñ¿ØÖÆ¿éÄÚ´æ*/
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
{
*ppxTimerTaskTCBBuffer = &TimerTaskTCB; //ÈÎÎñ¿ØÖÆ¿éÄÚ´æ
*ppxTimerTaskStackBuffer = TimerTaskStack; //ÈÎÎñ¶ÑÕ»ÄÚ´æ
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; //ÈÎÎñ¶ÑÕ»´óС
}
//¶¨Òåstart_taskµÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 64
StackType_t StartTaskStack[START_TASK_STACK_SIZE]; //ÈÎÎñ¶ÑÕ»
StaticTask_t StartTaskTCB; //ÈÎÎñ¿ØÖÆ¿é
TaskHandle_t start_handler;
void start_task(void);
//¶¨ÒåÈÎÎñ1µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define LED0_TASK_PRIO 2
#define LED0_TASK_STACK_SIZE 64
StackType_t Task1Static[LED0_TASK_STACK_SIZE]; //ÈÎÎñ¶ÑÕ»
StaticTask_t Task1TCB; //ÈÎÎñ¿ØÖÆ¿é
TaskHandle_t led0_handler;
void led0(void);
//¶¨ÒåÈÎÎñ2µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define LED1_TASK_PRIO 3
#define LED1_TASK_STACK_SIZE 64
StackType_t Task2Static[LED1_TASK_STACK_SIZE]; //ÈÎÎñ¶ÑÕ»
StaticTask_t Task2TCB; //ÈÎÎñ¿ØÖÆ¿é
TaskHandle_t led1_handler;
void led1(void);
//¶¨ÒåÈÎÎñ3µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define KEY_TASK_PRIO 4
#define KEY_TASK_STACK_SIZE 64
StackType_t Task3Static[KEY_TASK_STACK_SIZE]; //ÈÎÎñ¶ÑÕ»
StaticTask_t Task3TCB; //ÈÎÎñ¿ØÖÆ¿é
TaskHandle_t key_handler;
void key_task(void);
int flag = 0;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é2
LED_Init();
KEY_Init();
delay_init();
start_handler = xTaskCreateStatic( (TaskFunction_t) start_task, //ÈÎÎñº¯Êý
(const char *) "start_task", //ÈÎÎñÃû³Æ
( uint32_t) START_TASK_STACK_SIZE, //ÈÎÎñ¶ÑÕ»´óС
(void *) NULL, //ÈÎÎñº¯ÊýÈë¿Ú²ÎÊý
(UBaseType_t) START_TASK_PRIO, //ÈÎÎñÓÅÏȼ¶
(StackType_t *) StartTaskStack, //ÈÎÎñ¶ÑÕ»
(StaticTask_t *) &StartTaskTCB ); //ÈÎÎñ¿ØÖÆ¿é
vTaskStartScheduler(); //¿ªÊ¼ÈÎÎñµ÷¶È
}
/*´´½¨¿ªÊ¼ÈÎÎñ£º*/
void start_task(void)
{
// taskENTER_CRITICAL();
/*´´½¨ÈÎÎñ*/
if(flag == 0)
{
led0_handler = xTaskCreateStatic( (TaskFunction_t) led0,
(const char *) "led0",
( uint32_t) LED0_TASK_STACK_SIZE,
(void *) NULL,
(UBaseType_t) LED0_TASK_PRIO,
(StackType_t *) Task1Static,
(StaticTask_t *) &Task1TCB );
led1_handler = xTaskCreateStatic( (TaskFunction_t) led1,
(const char *) "led1",
( uint32_t) LED1_TASK_STACK_SIZE,
(void *) NULL,
(UBaseType_t) LED1_TASK_PRIO,
(StackType_t *) Task2Static,
(StaticTask_t *) &Task2TCB );
key_handler = xTaskCreateStatic( (TaskFunction_t) key_task,
(const char *) "key_task",
( uint32_t) KEY_TASK_STACK_SIZE,
(void *) NULL,
(UBaseType_t) KEY_TASK_PRIO,
(StackType_t *) Task3Static,
(StaticTask_t *) &Task3TCB );
flag = 1;
}
vTaskDelay(500);
vTaskDelete(NULL); //ɾ³ýµ±Ç°ÈÎÎñ
// taskEXIT_CRITICAL();
}
void led0(void)
{
while(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_8); //´ò¿ªLED
vTaskDelay(500);
//delay_ms(500);
GPIO_SetBits(GPIOA,GPIO_Pin_8); //´ò¿ªLED
vTaskDelay(500);
}
}
void led1(void)
{
while(1)
{
GPIO_ResetBits(GPIOD,GPIO_Pin_2); //´ò¿ªLED
vTaskDelay(500);
//delay_ms(500);
GPIO_SetBits(GPIOD,GPIO_Pin_2); //´ò¿ªLED
vTaskDelay(500);
}
}
/*´´½¨°´¼üÈÎÎñ£º*/
void key_task(void)
{
//uint8_t key = 0;
while(1)
{
//printf("task3ÕýÔÚÔËÐУ¡£¡£¡\r\n");
//key = KEY_Scan(0);
if(KEY_0 == 0)
{
if(led0_handler != NULL)
{
delay_us(2000000);
//printf("ɾ³ýtask1ÈÎÎñ\r\n");
vTaskDelete(led0_handler);
led0_handler = NULL;
}
}
vTaskDelay(10);
}
}
6.运行结果:
7.总结:
本文介绍了FreeRTOS的静态创建任务方法xTaskCreateStatic()。在使用静态方法创建任务时,需要配置相关的宏定义,并实现空闲任务的堆栈和任务控制块内存分配函数vApplicationGetIdleTaskMemory()。
静态创建任务需要用户自行提供堆栈,通常用数组来实现。此外,函数xTaskCreateStatic创建任务成功时的返回值即为任务句柄,创建任务失败时返回值为NULL。