前言
上一次是初步接触实时系统,这次开始认真学习
一、创建一个任务需要注意哪些?
1、任务创建函数xTaskCreate
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, //任务名
const char * const pcName, //任务标签
const configSTACK_DEPTH_TYPE usStackDepth,//栈大小
void * const pvParameters,//传入参数
UBaseType_t uxPriority,//任务优先级
TaskHandle_t * const pxCreatedTask )//任务句柄
这里说一下 任务标签 ,它可以和任务名重名,也可以不重名。
任务优先级值越小,优先级越低。
任务句柄,就是在代码前面需要定义一个
TaskHandle_t Task1_Handler = NULL;
所以传任务句柄参数时可以传NULL。
2、代码分析
#include "sys.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//任务句柄
TaskHandle_t Task1_Handler = NULL;
TaskHandle_t Task2_Handler = NULL;
void *Task1_func (void *param)
{
while(1)
{
printf("AS");
}
}
void *Task2_func (void *param)
{
while(1)
{
printf("BJ");
}
}
int main(void)
{
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init();
//初始化LED
xTaskCreate((TaskFunction_t)Task1_func, "Task1", 52, NULL, 1, &Task1_Handler);
xTaskCreate((TaskFunction_t)Task2_func, "Task2", 52, NULL, 1, NULL);
vTaskStartScheduler();//开始任务调度
}
这里我一下创建2个任务,如果只是一个任务的创建,
只需要对上面代码删除一些东西就好。
我需要说一下实验现象:
ASASASASASASBJBJBJBJBJBJ......
所以任务1和任务2就是交替实行的,就类似于时分复用。
这次是串口打印,如果是用其他实验现象,比如是led的
闪烁,那么我们看见的就是两个任务在同时运行。
二、动态/静态分配
每一个任务都有一个TCB(任务控制块)的结构体TCB_t。
任务控制块里面就有malloc去申请堆空间。
1· 动态分配
xTaskCreate((TaskFunction_t)Task1_func, “Task1”, 52, NULL, 1, &Task1_Handler);
xTaskCreate函数就是动态分配TCB,动态分配栈。
上面代码就是动态分配。
2· 静态分配:
静态分配就是自己分配TCB,自己分配栈。
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer, //传入栈
StaticTask_t * const pxTaskBuffer )//TCB结构体
使用静态配需要打开一些配置:
configSUPPORT_STATIC_ALLOCATION 需要置为1.
在开任务调度的函数里面,如果configSUPPORT_STATIC_ALLOCATION 置为1了需要开一个空闲函数,所以需要提供一个vApplicationGetIdleTaskMemory函数
代码:
#include "sys.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//任务句柄
TaskHandle_t Task1_Handler = NULL;
TaskHandle_t Task2_Handler = NULL;
//--------------------------------------
StackType_t task3stackbuff[100];
StaticTask_t * task3TCB;
//--------------------------------------
StackType_t idelstackbuff[100];
StaticTask_t * idelTCB;
/*---------------任务函数-----------------------------------*/
void *Task1_func (void *param)
{
while(1)
{
printf("AS");
}
}
void *Task2_func (void *param)
{
while(1)
{
printf("BJ");
}
}
void *Task3_func (void *param)
{
while(1)
{
printf("NK");
}
}
/*---------------任务函数-----------------------------------*/
/*---------------创建一个空闲函数函数-----------------------------------*/
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize )
{
* ppxIdleTaskTCBBuffer = idelTCB;
* ppxIdleTaskStackBuffer = idelstackbuff;
* pulIdleTaskStackSize = 100;
}
/*---------------创建一个空闲函数函数-----------------------------------*/
int main(void)
{
//delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
xTaskCreate((TaskFunction_t)Task1_func, "Task1", 52, NULL, 1, &Task1_Handler);
xTaskCreate((TaskFunction_t)Task2_func, "Task2", 52, NULL, 1, &Task2_Handler);
xTaskCreateStatic(Task3_func,"task3",52,NULL,1,task3stackbuff,task3TCB);
vTaskStartScheduler();//开始任务调度
}
注意:一定要configSUPPORT_STATIC_ALLOCATION 置为1.
再说一下关于优先级问题:freeRTOS中的优先级值越大,则程序越先执行。
多个任务的优先级一致,则多个任务时分复用执行(依次轮流循环执行)。
若多个任务的优先级不一致,则优先级高的先执行并且在该任务没有主动
放弃CPU的控制的情况下会一直执行,其他低优先级的任务根本没有把那发执行。
三、删除任务
vTaskDelete 函数传参是任务句柄,如果需要删除某个任务,就把该任务的任务句柄传进去。
【xTaskCreateStatic 静态分配的任务的返回值是该任务的任务句柄,所以需要定义一个变量来存储这个返回值,再把这个返回值传给vTaskDelete 】
四、一个函数创建两个任务
#include "sys.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//任务句柄
TaskHandle_t Task1_Handler = NULL;
TaskHandle_t Task2_Handler = NULL;
StackType_t task3stackbuff[100];
StaticTask_t * task3TCB;
/*--------------------------------------------------*/
void *Task1_func (void *param)
{
while(1)
{
printf("AS");
}
}
void *Task2_func (void *param)
{
while(1)
{
printf("BJ");
}
}
void *Task3_func (void *param)
{
while(1)
{
printf("NK");
}
}
/*--------------------------------------------------*/
/*---------通用函数-----------------------------------------*/
void taskGenericFunction(void *param)
{
int val = (int ) param;
while(1)
{
printf("%d",val);
}
}
/*---------通用函数-----------------------------------------*/
int main(void)
{
//delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
xTaskCreate((TaskFunction_t)Task1_func, "Task1", 52, NULL, 1, &Task1_Handler);
xTaskCreate((TaskFunction_t)Task2_func, "Task2", 52, NULL, 1, NULL);
/*---------多个任务调用一个通用函数-----------------------------------------*/
xTaskCreate((TaskFunction_t)taskGenericFunction, "Task3", 52, NULL, 1, NULL);
xTaskCreate((TaskFunction_t)taskGenericFunction, "Task4", 52, NULL, 1, NULL);
/*---------多个任务调用一个通用函数-----------------------------------------*/
vTaskStartScheduler();//开始任务调度
}
原因:每一个任务都有自己独立的栈。
总结
1·归根结底,实时操作系统和裸机程序的不同就是 时分复用 和 挨个函数执行。
2·创建一个任务的那些参数就是给这个任务营造一种“生存条件”,比如它的栈大小,它的任务控制块TCB等。
3·任务优先级一致与不一致的情况。优先级一致,则时分复用;不一致则高优先级先执行,若高优先级不放弃cpu的控制权,则低优先级没有办法执行。
4·多个任务可以调用一个功能函数时,是因为任务都有独立的栈,这个功能函数只是一个函数而已。【xTaskCreate 只有调用这样的函数才可以给任务分配栈空间】
问题:
1、任务句柄的作用是什么?可以赋值为NULL?
任务句柄 就是指向 任务控制块的指针。
2、为什么要加一个任务调度函数?