FreeRTOS 协同程序

协同程序是一种特殊的多任务编程方式,多个协同程序之间共用调用栈,且正在运行的协同程序不会被其他协程抢占(可以被任务和中断抢占),正在运行的协同程序只能自己主动让出CPU的使用权。要使用协同程序,需要将FreeRTOSConfig.h中的configUSE_CO_ROUTINES设为1

FreeRTOS的协同程序采用switch-case实现,函数定义方式如下:

1void CoRoutineTask(CoRoutineHandle_t handle,UBaseType_t uxIndex)
2{
3    //协同程序中变量如果要保证值在下一次运行时仍有效,则必须为static
4    static const TickType_t delay = 1000 / portTICK_PERIOD_MS;
5 

FreeRTOS 中断处理和中断安全API

FreeRTOS的任务优先级是数值越大,优先级越高,0是最低优先级;而Cortex-M的中断优先级是数值越大,优先级越低,0是最高优先级。

FreeRTOSConfig.h中的宏configLIBRARY_LOWEST_INTERRUPT_PRIORITY表示最低中断优先级,从FreeRTOS的demo中复制出来的这个头文件中这个宏的值是15,即从0到15一共16个优先级。Cortex-M的中断优先级有抢占优先级和子优先级两个,但FreeRTOS中没有提供处理子优先级的功能,只使用抢占优先级。因此需要将STM32的中断优先级组设置为16个抢占优先级、1个子优先级,即第四组中断优先级组。

1//优先级组是STM32中优先级分配方式的选择,"组"这个翻译可能不太合适
2//使用第四组中断优先级组
3NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
4//STM32有0到4共五组优先级组

FreeRTOS 事件标志组

FreeRTOS可以使用事件标志组进行任务同步,一个事件标准组包含多个事件标志位,每一位标志一个事件。当configUSE_16BIT_TICKS为1时,一个事件标志组有8位;当这个宏为0时,一个事件标志组有24位。

创建事件标志组使用xEventGroupCreate

1#include <event_groups.h>
2EventGroupHandle_t xEventGroupCreate(void);
3//返回事件标志组句柄,失败返回NULL

FreeRTOS 内存管理

FreeRTOS的内存管理API定义在heep_1.cheep_2.cheep_3.cheep_4.cheep_5.c中,这五个文件中的内存管理API有所不同。

  • heep_1.c只能分配内存而不能释放内存。
  • heep_2.c可以分配和释放内存但不能合并空闲内存块。
  • heep_3.c简单的封装了线程安全版的标准C语言malloc和free函数。
  • heep_4.c可以合并相邻的空闲内存块。
  • heep_5.c可以合并相邻的空闲内存块,且可以管理地址不连续的物理内存。

分配内存的API是pvPortMalloc,释放内存的API是vPortFree

1undefined

FreeRTOS 信号量和互斥量

信号量(Semaphore)也是一种任务间通信的常用方式,通常用于任务的同步。

1#include <semphr.h>
2 
3BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);
4//产生一个信号,成功返回pdPASS
5//信号量已满则失败,返回errQUEUE_FULL
6
7BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,TickType_t xBlockTime);

FreeRTOS 队列

队列(Queue)是一种数据结构,它是一种特殊的线性表,只允许在队列的首端进行删除,尾端进行插入,具有先入先出的特性。是任务间通信的一种常用方式。

xQueueCreate函数创建一个队列,它的第一个参数是队列的长度(元素的个数),第二个参数是每个元素的大小(byte)。

1#include <queue.h>
2QueueHandle_t xQueueCreate(const UBaseType_t uxQueueLength,const UBaseType_t uxItemSize);
3//成功返回队列句柄,失败返回NULL

FreeRTOS 临界区

在并行编程中,并行存取共享的资源时,常常会导致意外和错误的结果。例如下面代码task1和task2都通过串口打印消息,但由于任务调度,消息被截断了。

1#include <stm32f4xx.h>
2#include <FreeRTOS.h>
3#include <task.h>
4#include <uart.h>
5 
6void task1(void* args);
7void task2(void* args);

FreeRTOS 任务的状态

xTaskCreate函数创建任务时,即为任务赋予了优先级。可以使用vTaskPrioritySet函数来修改任务的优先级,它的第一个参数是任务句柄、第二个参数是优先级,这个函数必须在调度器启动之后才能调用。相应的,uxTaskPriority函数返回一个任务的优先级。

1#include <task.h>
2void vTaskPrioritySet(TaskHandle_t xTask,UBaseType_t uxNewPriority);
3 
4UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask);
5//返回任务的优先级

FreeRTOS 任务的创建与删除

FreeRTOS的任务函数原型为:

1void task(void* args);

使用FreeRTOS的xTaskCreate函数来创建任务:

1#include <task.h>

FreeRTOS 搭建开发环境

本文使用Keil MDK和STM32为例

首先需要下载FreeRTOS的源码:http://www.freertos.org/。当前最新版本为9.0.0,其源码目录如下图 :

Image

FreeRTOS/Demo目录下已经有许多工程可以直接使用,例如FreeRTOS\Demo\CORTEX_STM32F103_Keil就是STM32F103在Keil下的工程。不过这个工程是针对小容量STM32F103的,对于其他型号的STM32芯片,需要自己组织工程。