FreeRTOS-02_创建静态任务
与动态创建任务的差别
静态与动态的区别在于:静态需要用户自己手动创建堆栈空间,而一般我们通过定义数组来创建一块连续的内存空间,动态则由系统来帮我们分配,因此一般我们选择动态创建任务更为方便简单
创建静态时需要注意:需要对空闲任务以及定时器任务的堆栈以及控制块进行内存创建分配,即对两个相关内存分配函数进行实现,再底层只是对这两个函数进行声明和调用而已,即1.2和1.3两个函数
1、相关API函数
1.1、xTaskCreateStatic()
静态任务创建函数
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 )
功能 :静态创建任务
返回值:TaskHandle_t 任务句柄
参数 :
- pxTaskCode:任务函数
- pcName:任务名称(一般与函数名一致)
- usStackDepth:任务堆栈大小(单位为字,因为STM32是32位的,所以1字=4字节)
- pvParameters:任务函数参数(一般为空NULL)
- uxPriority:任务优先级(越大优先级越高)
- puxStackBuffer:自己创建的任务堆栈首地址
- pxTaskBuffer:TCB任务控制块地址
这里需要注意(任务句柄)和(任务控制块)是不一样的,任务句柄是指向任务控制块的,我们也是通过任务句柄对任务进行控制的
1.2、vApplicationGetIdleTaskMemory()
空闲任务内存分配函数
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
功能:对空闲任务的内存进行手动分配,该函数再开启任务调度器时会自动调用到,因为开启任务调度器中会自动创建一个空闲任务,而此时我们用的是静态创建任务,因此空闲任务的内存分配也需要我们自己创建分配,此函数已经再底层进行声明,因此我们只需要进行函数实现即可。
参数 :
- ppxIdleTaskTCBBuffer:创建的空闲任务的TCB任务控制块地址
- ppxIdleTaskStackBuffer:创建的空闲任务的堆栈首地址
- pulIdleTaskStackSize:空闲任务使用的堆栈大小(再FreeRTOSConfig.h里有宏定义好的(空闲任务堆栈大小宏定义:configMINIMAL_STACK_SIZE)
1.3、vApplicationGetTimerTaskMemory()
软件定时器任务内存分配函数
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
功能:对软件定时器任务的内存进行创建分配,与1.2的函数功能一致,此函数可以根据是否开启软件定时器任务选择实现,如不开定时器任务可以不用进行函数实现(软件定时器开启相关宏定义:configUSE_TIMERS)
无返回值
参数 :
- ppxTimerTaskTCBBuffer:创建的定时器任务的TCB任务控制块地址
- ppxTimerTaskStackBuffer:创建的定时器任务的堆栈首地址
- **pulTimerTaskStackSize **:定时器任务使用的堆栈大小(再FreeRTOSConfig.h里有宏定义好的(空闲任务堆栈大小宏定义:configTIMER_TASK_STACK_DEPTH)
2、操作流程
2.1、相应宏设置开启
- configSUPPORT_STATIC_ALLOCATION 1
功能:静态创建任务相关宏定义,要使用静态内存创建任务该宏需置一 - configUSE_TIMERS 1
功能:软件定时器任务相关宏定义,要开启软件定时器任务该宏需置一
以下宏定义不是开关,是系统定义好的相关数值
- configMINIMAL_STACK_SIZE ((unsigned short)128)
作用:空闲任务使用的堆栈大小 - configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2)
作用:软件定时器任务使用的堆栈大小
2.2、创建相关内存参数
提前宏定义任务所需的参数以及创建相关内存
例如第一个开始任务:
- START_TASK_PRIO 任务优先级
- START_TASK_STACK_SIZE 任务堆栈大小
- start_task_handler 任务句柄
- void start_task(void * pvParameters); 任务执行函数
相较于动态创建任务,静态要多创建以下两个内存
- start_task_stack[START_TASK_STACK_SIZE] 任务堆栈
- start_task_tcb TCB任务控制块
/* START_TASK */
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
StackType_t start_task_stack[START_TASK_STACK_SIZE];
StaticTask_t start_task_tcb;
void start_task(void * pvParameters);
/* TASK1 */
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
StackType_t task1_stack[TASK1_STACK_SIZE];
StaticTask_t task1_tcb;
void task1(void * pvParameters);
/* TASK2 */
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
StackType_t task2_stack[TASK2_STACK_SIZE];
StaticTask_t task2_tcb;
void task2(void * pvParameters);
/* TASK3 */
#define TASK3_PRIO 4
#define TASK3_STACK_SIZE 128
TaskHandle_t task3_handler;
StackType_t task3_stack[TASK3_STACK_SIZE];
StaticTask_t task3_tcb;
void task3(void * pvParameters);
/* 空闲任务内存创建 */
StaticTask_t idle_task_tcb; //TCB空闲任务的控制块
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];//空闲任务的堆栈
/* 软件定时器任务内存创建 */
StaticTask_t time_task_tcb; //TCB软件定时器任务的控制块
StackType_t time_task_stack[configTIMER_TASK_STACK_DEPTH];//软件定时器任务的堆栈
2.3、创建开始任务并开启任务调度器
void freertos_demo(void)
{
start_task_handler = xTaskCreateStatic( (TaskFunction_t) start_task,
(char * ) "start_task",
(uint32_t ) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(StackType_t * ) start_task_stack,
(StaticTask_t *) &start_task_tcb );
if(start_task_handler != NULL)
vTaskStartScheduler();
else
printf("静态创建任务失败\r\n");
}
2.4、在开启任务中创建执行任务
void start_task(void * pvParameters)
{
taskENTER_CRITICAL(); /* 进入临界区 防止创建任务过程被打断 */
task1_handler = xTaskCreateStatic((TaskFunction_t) task1,
(char * ) "task1",
(uint32_t ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(StackType_t * ) task1_stack,
(StaticTask_t *) &task1_tcb );
task2_handler = xTaskCreateStatic((TaskFunction_t) task2,
(char * ) "task2",
(uint32_t ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(StackType_t * ) task2_stack,
(StaticTask_t *) &task2_tcb );
task3_handler = xTaskCreateStatic((TaskFunction_t) task3,
(char * ) "task3",
(uint32_t ) TASK3_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK3_PRIO,
(StackType_t * ) task3_stack,
(StaticTask_t *) &task3_tcb );
vTaskDelete(start_task_handler); //用NULL也一样都是删除自身
taskEXIT_CRITICAL(); /* 退出临界区 */
}
2.5、编写任务函数
void task1(void * pvParameters)
{
while(1)
{
;
}
}
void task2(void * pvParameters)
{
while(1)
{
;
}
}
void task3(void * pvParameters)
{
while(1)
{
;
}
}
3、点灯示例代码
/* START_TASK */
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
StackType_t start_task_stack[START_TASK_STACK_SIZE];
StaticTask_t start_task_tcb;
void start_task(void * pvParameters);
/* TASK1 */
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
StackType_t task1_stack[TASK1_STACK_SIZE];
StaticTask_t task1_tcb;
void task1(void * pvParameters);
/* TASK2 */
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
StackType_t task2_stack[TASK2_STACK_SIZE];
StaticTask_t task2_tcb;
void task2(void * pvParameters);
/* TASK3 */
#define TASK3_PRIO 4
#define TASK3_STACK_SIZE 128
TaskHandle_t task3_handler;
StackType_t task3_stack[TASK3_STACK_SIZE];
StaticTask_t task3_tcb;
void task3(void * pvParameters);
/* 空闲任务内存创建 */
StaticTask_t idle_task_tcb; //TCB空闲任务的控制块
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];//空闲任务的堆栈
/* 软件定时器任务内存创建 */
StaticTask_t time_task_tcb; //TCB软件定时器任务的控制块
StackType_t time_task_stack[configTIMER_TASK_STACK_DEPTH];//软件定时器任务的堆栈
/**************************************************************/
void freertos_demo(void)
{
start_task_handler = xTaskCreateStatic( (TaskFunction_t) start_task,
(char * ) "start_task",
(uint32_t ) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(StackType_t * ) start_task_stack,
(StaticTask_t *) &start_task_tcb );
if(start_task_handler != NULL)
vTaskStartScheduler();
else
printf("静态创建任务失败\r\n");
}
void start_task(void * pvParameters)
{
taskENTER_CRITICAL(); /* 进入临界区 防止创建任务过程被打断 */
task1_handler = xTaskCreateStatic((TaskFunction_t) task1,
(char * ) "task1",
(uint32_t ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(StackType_t * ) task1_stack,
(StaticTask_t *) &task1_tcb );
task2_handler = xTaskCreateStatic((TaskFunction_t) task2,
(char * ) "task2",
(uint32_t ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(StackType_t * ) task2_stack,
(StaticTask_t *) &task2_tcb );
task3_handler = xTaskCreateStatic((TaskFunction_t) task3,
(char * ) "task3",
(uint32_t ) TASK3_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK3_PRIO,
(StackType_t * ) task3_stack,
(StaticTask_t *) &task3_tcb );
vTaskDelete(start_task_handler); //用NULL也一样都是删除自身
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一:LED0每500ms翻转一次 */
void task1(void * pvParameters)
{
while(1)
{
printf("任务一运行中!!!\r\n");
GPIO_SetBits(GPIOB,GPIO_Pin_12);
vTaskDelay(500);
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
vTaskDelay(500);
}
}
/* 任务一:LED1每500ms翻转一次 */
void task2(void * pvParameters)
{
while(1)
{
printf("任务二运行中!!!\r\n");
GPIO_SetBits(GPIOB,GPIO_Pin_13);
vTaskDelay(500);
GPIO_ResetBits(GPIOB,GPIO_Pin_13);
vTaskDelay(500);
}
}
/* 任务三:按下KEY0删除任务1 */
void task3(void * pvParameters)
{
printf("任务三运行中!!!\r\n");
while(1)
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == SET){
vTaskDelay(10);
//while等待松手时加个延迟可以让任务三不会一直抢占线程
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == SET)vTaskDelay(10);
if(task1_handler != NULL){
vTaskDelete(task1_handler);
printf("任务一删除成功!\r\n");
task1_handler = NULL;
}
}
vTaskDelay(10); //按键检测要加个延迟,因为任务三优先级最高,不然任务三会一直霸占线程
}
}
/**************************************************************/