本文参考韦东山RTOS教程及STM32CubeMX
目录
一、概念
对于FreeRTOS而言,我们可以在程序中创建多个任务,就拿上学来说,在上学这个程序里面,上课是一个任务,做作业也是一个任务等等。
这其中可以引入很多概念:
- State任务状态:他可以分为执行(running)和不执行(not running)两种状态,其中,not running还可以分成:
- ready:就绪态,随时可以运行
- blocked:阻塞态,卡住了,需要等待信息才能运行
- suspended:挂起,暂时不理会其他任务
- Priority优先级:
- 高优先级先执行,低优先级后执行,高优先级可以打断低优先级执行
- Stack栈:
- 在任务执行过程中,我们需要记住这次任务切换时当前任务运行到哪里了,这些信息就存放在栈空间里面,每个任务都有自己的栈
- 事件驱动
- 协助式调度
二、任务创建与删除
1.任务是什么:
在FreeRTOS中,任务就是一个函数,原型如下:
void ATaskFunction(void * pvParameters)
有几点需要主要注意:
- 这个函数不能返回
- 同一个函数,可以用来创建多个任务;多个任务可以运行同一个函数
- 函数内部,尽量使用局部变量:
- 每个任务都有自己对应的任务栈
- 每个任务运行此函数时:
- 任务A的局部变量会放在A的任务栈里面,任务B的会放在B的任务栈里面
- 不同任务的任务的局部变量,有自己的副本
- 函数如果使用全局变量或者静态变量的话:
- 只有一个副本,多个任务使用的一个副本
- 需要做措施来防止冲突
2.创建任务
创建任务有两个函数:动态分配内存和静态分配内存
使用动态分配内存的函数如下:
BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务
参数说明:
- pvTaskCode:函数指针,如果将任务理解为一个C函数,那么这个函数将永远不退出,或者在退出时调用<vTaskDelete(NULL)>
- pcName:任务的名字,FreeRTOS内部并不会使用它,仅仅只起调试作用,长度为:configMAX_TASK_NAME_LEN
- usStackDepth:每个任务都有自己的栈空间,此处的作用是指定栈的大小,单位是word,比如传入100word,实际就是400字节,栈最大值为uint16_t的最大值。具体怎么确定栈的大小呢?通常是估计,准确一点的方法是看反汇编码。
- pvParasmeters:调用pvTaskCode函数指针时用到,比如说
pvTaskCode( pvParasmeters)
- uxPriority:优先级参数,优先级的范围在0~ configMAX_PRIORITIES-1,数字越大优先级越高,如果传入数字过大,会自动改为最大值
- pxCreatedTask:任务句柄,用来保存xTaskCreate的输出结果,task handle,如果之后想对此任务进行修改,就需要这个handle,如果不想使用此handle,可以传入NULL
- 返回值:1:pdPASS ;-1:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(失败原因只会是内存不足)
使用静态分配的函数如下:
TaskHandle_t xTaskCreateStatic (
TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const uint32_t ulStackDepth, // 栈大小,单位为word,10表示40字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
StackType_t * const puxStackBuffer, // 静态分配的栈,就是一个buffer
StaticTask_t * const pxTaskBuffer // 静态分配的任务结构体的指针,用它来操作这个任务
);
参数说明:
- pvTaskCode:函数指针,如果将任务理解为一个C函数,那么这个函数将永远不退出,或者在退出时调用<vTaskDelete(NULL)>
- pcName:任务的名字,FreeRTOS内部并不会使用它,仅仅只起调试作用,长度为:configMAX_TASK_NAME_LEN
- usStackDepth:每个任务都有自己的栈空间,此处的作用是指定栈的大小,单位是word,比如传入100word,实际就是400字节,栈最大值为uint16_t的最大值。具体怎么确定栈的大小呢?通常是估计,准确一点的方法是看反汇编码。
- pvParasmeters:调用pvTaskCode函数指针时用到,比如说
pvTaskCode( pvParasmeters)
- uxPriority:优先级参数,优先级的范围在0~ configMAX_PRIORITIES-1,数字越大优先级越高,如果传入数字过大,会自动改为最大值
- puxStackBuffer:静态分配的栈内存,比如如果传入一个数组,大小是usStackDepth*4
- pxTaskBuffer:静态分配的StaticTask_t结构体的指针
- 返回值:1:pdPASS ;-1:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(失败原因只会是内存不足)
在CubeMX中操作如下:
选中Task and Queue选项,按如下情况设置,一般只需要设置任务名称和入口函数两个选项
3.删除任务
任务删除时使用的函数如下:
void vTaskDelete( TaskHandle_t xTaskToDelete );
参数说明:
pvTaskCode:任务句柄,使用xTaskCreate创建任务得到一个句柄,也可以传入NULL表示删除自己
所以,我们可以知道,任务删除分两种情况,杀人,自杀和他杀:
- 自杀:传入NULL参数,自己删除自己
- 他杀:用别的任务传入自己的句柄
- 杀人:在自己的任务中传入别的任务的句柄