FreeRTOS笔记(二)—静态任务
文章目录
一、任务定义
在多任务系统中,我们根据功能的不同,把整个系统分割 成一个个独立的且无法返回的函数,这个函数我们称为任务。
二、任务创建
2.1 定义任务栈
写一个 RTOS,对于全局变量与局部变量这些种种环境参数,我们必须弄清楚他们是如何存储的。
在裸机系统 中,他们统统放在一个叫栈的地方,栈是单片机 RAM 里面一段连续的内存空间,栈的大小一般在启动文件或者链接脚本里面指定,最后由C库函数_main进行初始化。
在多任务系统中,每个任务都是独立的,互不干扰的,所以要为每个任务都分配独立的栈空间,这个栈空间通常是一个预先定义好的全局数组,也可以是动态分配的一段内存空间,但它们都存在于RAM中。
多任务系统中,有多少个任务就需要定义多少个任务栈。
示例 1 定义任务栈
/*
#define portSTACK_TYPE uint32_t
typedef portSTACK_TYPE StackType_t;
*/
#define TASK1_STACK_SIZE 128
StackType_t Task1Stack[TASK1_STACK_SIZE];
#define TASK2_STACK_SIZE 128
StackType_t Task2Stack[TASK2_STACK_SIZE];
2.2 定义任务函数
任务是一个独立的函数,函数主体无限循环且不能返回。
示例 2 任务函数定义
/* 软件延时 */
void delay (uint32_t count)
{
for(; count!=0; count--);
}
/* 任务1 */
void Task1_Entry( void *p_arg )
{
for( ;; )
{
flag1 = 1;
delay( 100 );
flag1 = 0;
delay( 100 );
}
}
/* 任务2 */
void Task2_Entry( void *p_arg )
{
for( ;; )
{
flag2 = 1;
delay( 100 );
flag2 = 0;
delay( 100 );
}
}
2.3 定义任务控制块
-
在裸机系统中,程序的主体是 CPU 按照顺序执行的。而在多任务系统中,任务的执行是由系统调度的。
-
系统为了顺利的调度任务,为每个任务都额外定义了一个任务控制块, 这个任务控制块就相当于任务的身份证,里面存有任务的所有信息,比如任务的栈指针, 任务名称,任务的形参等。
-
有了这个任务控制块之后,以后系统对任务的全部操作都可以通过这个任务控制块来实现。
示例 3 任务控制块数据类型声明
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack; /* 栈顶 */
ListItem_t xStateListItem; /* 任务节点 一个内置在 TCB 控制块中的链表节点,通过 这个节点,可以将任务控制块挂接到各种链表中。这个节点就类似晾衣架的钩子,TCB 就是衣服。*/
StackType_t *pxStack; /* 任务栈起始地址 */
char pcTaskName[ configMAX_TASK_NAME_LEN ]; /* 任务名称,字符串形式 */
} tskTCB;
typedef tskTCB TCB_t;
2.4 实现任务创建函数
示例 4 任务创建函数xTaskCreateStatic()函数
/*
//任务句柄void指针
typedef void * TaskHandle_t;
//TaskFunction_t类型的pxTaskCode为函数指针,指向任务函数的入口。任务永远不会返回(位于死循环内)。
typedef void (*TaskFunction_t)( void * );//参数为void指针类型并返回void类型。
//
#define portSTACK_TYPE uint32_t
typedef portSTACK_TYPE StackType_t;
*/
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, /* 任务入口 */
const char * const pcName, /* 任务名称,字符串形式 ,字符串的最大长度(包括字符串结束字符)由宏configMAX_TASK_NAME_LEN指定,该宏位于FreeRTOSConfig.h文件中。*/
const uint32_t ulStackDepth, /* 任务栈大小,单位为字,不是字节数,在16位宽度的堆栈下,usStackDepth定义为100,则实际使用200字节堆栈存储空间。1字=2字节=16位 */
void * const pvParameters, /* 任务形参,当任务创建时,作为一个参数传递给任务。*/
StackType_t * const puxStackBuffer, /* 任务栈起始地址 */
TCB_t * const pxTaskBuffer ) /* 任务控制块指针 */
{
TCB_t *pxNewTCB;
TaskHandle_t xReturn;//定义一个任务句柄 xReturn,任务句柄用于指向任务的 TCB。
/*任务控制块指针与任务栈起始地址均非空时,形参赋值*/
if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
{
pxNewTCB = ( TCB_t * ) pxTaskBuffer;
pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
/* 创建新的任务 */
prvInitialiseNewTask( pxTaskCode, /* 任务入口 */
pcName, /* 任务名称,字符串形式 */
ulStackDepth, /* 任务栈大小,单位为字 */
pvParameters, /* 任务形参 */
&xReturn, /* 任务句柄 */
pxNewTCB); /* 任务栈起始地址 */
}
else
{
xReturn = NULL;
}
/* 返回任务句柄,如果任务创建成功,此时xReturn应该指向任务控制块 */
return xReturn;
}
示例 5 创建新任务prvInitialiseNewTask()函数
/*
typedef unsigned long UBaseType_t;
*/
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, /* 任务入口 */
const char * const pcName, /* 任务名称,字符串形式 */
const uint32_t ulStackDepth, /* 任务栈大小,单位为字 */
void * const pvParameters, /* 任务形参 */
TaskHandle_t * const pxCreatedTask, /* 任务句柄 */
TCB_t *pxNewTCB ) /* 任务控制块指针 */