FreeRTOS 教程指南 学习笔记 第一章 简介
本章包含的内容有:
- 帮助用户使用FreeRTOS文件和目录,提供FreeRTOS目录结构的顶级视图。
- 描述任何特定的FreeRTOS项目实际上需要哪些文件。
- 介绍了演示应用程序。
- 提供有关如何创建新项目的信息。
一、了解FreeRTOS
FreeRTOS可以使用大约20种不同的编译器来构建,并且可以在30多种不同的处理器架构上运行。每个受支持的编译器和处理器的组合都被认为是一个单独的FreeRTOS分支。FreeRTOS可以被认为是一个能为裸代码程序提供多任务功能的库文件。
二、了解FreeRTOS版本
FreeRTOSConfig.h头文件是FreeRTOS的主要配置文件,由于FreeRTOSConfig.h包含特定于应用程序的定义,因此它应该位于正在构建的应用程序的一部分的目录中,而不是位于包含FreeRTOS源代码的目录中。
FreeRTOS的目录结构
FreeRTOS
│ │
│ ├─Source 系统内核源文件
│ │
│ └─Demo 各分支的实例代码
│
FreeRTOS-Plus
│
├─Source 第三方库的源文件,如TCP/IP,JASON等
│
└─Demo 实例代码
FreeRTOS内核总,最核心的两个文件是task.c和list.c文件,只有这两个文件是必须的。他们被放在FreeRTOS/Source文件夹下,在相同文件夹下还有:
│
└─Source
│
├─tasks.c FreeRTOS source file - always required
├─list.c FreeRTOS source file - always required
├─queue.c 使系统支持队列和信号量 - nearly always required
├─timers.c 使系统支持软计时器 - optional
├─event_groups.c 使系统支持事件组等 - optional
└─croutine.c 使系统支持协程 - optional
对于分支的支持:如果您在使用编译器“编译器”的具有架构“架构”的处理器上运行FreeRTOS,那么除了核心的FreeRTOS源文件外,您还必须构建位于FreeRTOS/Source/portable/[compiler]/[architecture]目录中的文件
正如将在第2章,堆内存管理中描述的,FreeRTOS还将堆内存分配视为可移植层的一部分。使用早于V9.0.0的FreeRTOS版本的项目必须包含一个堆内存管理器。在FreeRTOS V9.0.0中,只有当configSUPPORT_DYNAMIC_ALLOCATION在FreeRTOSConfig.h中设置为1,或者当configSUPPORT_DYNAMIC_ALLOCATION未定义时,才需要堆内存管理器。FreeRTOS提供了5个堆分配方案示例。这五种方案分别命名为heap_1到heap_5,并分别由源文件heap_1.c到heap_5.c实现。堆分配方案包含在FreeRTOS/Source/portable/MemMang目录中。如果您已将FreeRTOS配置为使用动态内存分配,那么就必须在项目编译中包含这五个源文件中的一个,除非您的应用程序提供了一个替代实现。
FreeRTOS要求在编译器的包含路径中包含三个目录。他们是:
- FreeRTOS内核头文件的路径,它始终是FreeRTOS/Source/include/。
- 特定于正在使用的FreeRTOS分支的源文件的路径。这是FreeRTOS/Source/portable/[compiler]/[architecture]。
- 指向FreeRTOSConfig.h头文件的路径。
- 如果代码文件中使用了FreeRTOS API,则必须包含FreeRTOS.h文件,后面紧跟着task.h,timer.h等。例如:
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timer.h"
#include "event_groups.h"
三、示例程序
int main( void )
{
/* Perform any hardware setup necessary. */
prvSetupHardware();
/* --- APPLICATION TASKS CAN BE CREATED HERE --- */
vUserTask1();
vUserTask2();
vUserTask3();
/* Start the created tasks running. */
vTaskStartScheduler();
/* Execution will only reach here if there was insufficient heap to start the scheduler. */
for( ;; );
return 0;
}
四、从头开始创建项目
建议从现有的演示项目中创建新的项目。如果不需要这样做,则可以使用以下过程创建一个新项目:
- 使用您所选择的工具链,创建一个尚未包含任何FreeRTOS源文件的新项目。
- 确保可以编译新项目,下载到目标硬件并执行。
- 只有当您确定已经有了一个可以正常在目标硬件工作的项目时,才能将FreeRTOS源文件添加到该项目中。
- 将为正在使用的分支提供的演示项目所使用的FreeRTOSConfig.h头文件复制到项目目录中。
- 将以下目录添加到项目将搜索的路径中,以查找头文件:
FreeRTOS/Source/include
FreeRTOS/Source/portable/[compiler]/[architecture]
包含FreeRTOSConfig.h文件的目录 - 从相关的演示项目中复制编译器设置。
- 安装可能是必要的任何FreeRTOS中断处理程序。使用相关资源提供的示例
File | Location |
---|---|
tasks.c | FreeRTOS/Source |
queue.c | FreeRTOS/Source |
list.c | FreeRTOS/Source |
timers.c | FreeRTOS/Source |
event_groups.c | FreeRTOS/Source |
event_groups.c | FreeRTOS/Source |
All C and assembler files | FreeRTOS/Source/portable/[compiler]/[architecture] |
heap_n.c(n是1~5) | FreeRTOS/Source/portable/MemMang |
五、数据类型和代码规范
数据类型:
FreeRTOS的每个分支都有一个唯一的portmacro.h头文件,该文件包含两种端口特定数据类型的定义:TickType_t和BaseType_t。
TickType_t :FreeRTOS配置了一个被称为tick interrupt的周期性中断。自FreeRTOS应用程序启动以来发生的tick interrupt总数数称为tick count。两次tick interrupt之间的时间称为tick period。TickType_t 用于保存周期性中断的tick count,并确定时间的数据类型。
TickType_t可以是unsigned 16-bit ,也可以是unsigned 32-bit ,这取决于在FreeRTOSConfig.h中对configUSE_16_BIT_TICKS的设置。如果configUSE_16_BIT_TICKS被设置为1,则TickType_t被定义为uint16_t。如果configUSE_16_BIT_TICKS被设置为0,则TickType_t被定义为uint32_t。
使用uint16_t类型可以极大地提高8位和16位处理器的效率,但严重限制了可以指定的最大块周期。没有理由在32位处理器上使用uint16_t。
BaseType_t :总是被定义为处理器中最有效的数据类型。通常,这是在32位处理器上的32位类型,在16位体系结构上的16位类型,以及在8位体系结构上的8位类型。BaseType_t通常用于只能取非常有限的值范围的返回类型,以及pdTRUE/pdFALSE类型的布尔类值。
一些编译器把所有所有不合格的字符变量列为无符号,而另一些则使它们列为有符号。出于这个原因,FreeRTOS源代码显式地限定了“有符号”或“无符号”的字符使用,除非字符用于保存ASCII字符,或者指向char的指针用于指向字符串。
变量命名规范:
所有变量命名都有前缀如:
‘c’ for char, ‘s’ for int16_t (short), ‘l’ int32_t (long), and ‘x’ for BaseType_t和其他非标准类型 (structures, task handles, queue handles, etc.)
如果一个变量为无符号,则它也以“u”作为前缀。如果变量是指针,它也以“p”作为前缀。例如,类型为uint8_t的变量将以“uc”为前缀,类型为字符指针的变量将以“pc”为前缀。
函数命名规范:
函数命名的前缀包含了返回类型和它定义在哪里,如:
vTaskPrioritySet() 返回void定义在task.c中。
xQueueReceive() 返回BaseType_t定义在queue.c中。
pvTimerGetTimerID() 返回一个pointer to void定义在timers.c中。
文件范围(private)函数以“prv”为前缀。
宏命名:
大多数宏都是用大写写的,并用小写字母作为前缀,表示宏的位置。表3提供了一个前缀的列表。
Prefix | Location of macro definition |
---|---|
port (for example, portMAX_DELAY) | Location of macro definition |
task (for example, taskENTER_CRITICAL()) | task.h |
pd (for example, pdTRUE) | projdefs.h |
config (for example, configUSE_PREEMPTION) | FreeRTOSConfig.h |
err (for example, errQUEUE_FULL) | projdefs.h |
请注意,信号量API几乎完全是作为一组宏编写的,但它遵循函数命名约定,而不是宏命名约定。
表4中定义的宏在整个FreeRTOS源代码中都在使用
Macro | Value |
---|---|
pdTRUE | 1 |
pdFALSE | 0 |
pdPASS | 1 |
pdFAIL | 0 |