一、FreeRTOS简介
Free RTOS(Real Time Operating System,实时操作系统),顾名思义,一款免费的实时操作系统。作为一种专门设计用于处理实时任务的操作系统。与通用计算机上运行的桌面操作系统(如Windows、Linux)不同,RTOS专注于提供对实时性能和响应时间的支持。那么,为什么要学习Free RTOS呢?
之前,所学习的51、32单片机,都是对裸机进行操作编程。即不加入任何 RTOS (Real Time Operating System 实时操作系统)的程序。常用的 RTOS 有国外的FreeRTOS、 μC/OS、RTX 和国内的 RT-Thread 等,其中尤以国外开源且免费的 FreeRTOS 的市场占有率最高。
所谓裸机,通常指的是在没有操作系统(OS)支持的环境中直接运行程序的状态。换句话讲,也就是说裸机开发是一种在没有操作系统或者其他软件中间层的情况下,直接操作硬件的软件开发方式
在裸机开发中,程序员需要编写直接与硬件交互的代码,包括底层初始化、时钟、中断服务程序、外设控制等。与在有操作系统的环境中相比,裸机开发对硬件的了解程度更为深入,同时也需要处理更多的底层细节。
裸机开发的缺点:
(1)实时性差:裸机编程都在一个死循环中,程序轮流执行,所有任务优先级相同,但所有任务可以被中断打断
(2)CPU利用率低:一旦遇到Delay函数,CPU就会进行空等待,没有任务调度器,使CPU利用率低
(3)结构臃肿:所有任务都放在无限循环内
而实时操作系统可以很好的解决这些缺点,提供对实时性能和响应时间的支持,优点如下:
(1)分而治之:实现功能划分为多个任务,而每个任务又是一个独立的无限循环
(2)任务调度:RTOS包含一个任务调度器,能够有效地管理多个任务的执行。它负责按照优先级或其他调度算法,决定哪个任务在何时执行。当遇到阻塞态时,当前任务交出CPU使用权,CPU转去处理下一个任务
(3)抢占式:任务可以有软件指定优先级,高优先级的任务可以抢占低优先级的任务。同样,中断可以打断任一优先级的任务
(4)任务堆栈:每个任务都有自己独立的栈空间,用于保存局部变量以及任务的上下文信息
Free RTOS基于上层优点,同时还拥有其他特点,使得Free RTOS在市场上的占有率很高
(1)免费开源:商业产品中使用,无潜在商业风险,无须担心
(2)可裁剪:FreeRTOS的核心代码9000+行,包含在3个.c文件中
(3)简单:简单易用,可移植性非常好
(4)优先级不限:任务优先级分配没有限制,多任务可同一优先级
(5)任务不限:可创建的实时任务数量没有软件限制(对于硬件层取决于栈空间大小)
(6)抢占/协程/时间片:支持抢占式,协程式、时间片流转任务调度
对于相同优先级的任务而言,在FreeRTOS中有一个“心脏”——滴答定时器,滴答定时器每计时到一个时间单位(时间片),就会触发一次滴答定时器中断,在这个滴答定时器中断中,主要就是执行相同优先级任务的切换
对于不同优先级的任务而言,高优先级的任务可以抢占低优先级的任务。执行过程中如果遇到阻塞态时,当前任务交出CPU使用权,CPU转去处理下一个任务。当高优先级任务执行完成后,开始执行低优先级任务
二、FreeRTOS数据类型和命名规范
2.1 数据类型
每个移植的版本都含有自己的portmacro.h头文件,里面定义了2个数据类型:
TickType_t:
FreeRTOS配置了一个周期性的时钟中断:Tick Interrupt
每发生一次中断,中断次数累加,这被称为tick count
tick count这个变量的类型就是TickType_t
TickType_t可以是16位的,也可以是32位的
FreeRTOSConfig.h中定义configUSE_16_BIT_TICKS时,TickType_t就是uint16_t
否则TickType_t就是uint32_t
对于32位架构,建议把TickType_t配置为uint32_t
BaseType_t:
这是该架构最高效的数据类型
32位架构中,它就是uint32_t
16位架构中,它就是uint16_t
BaseType_t通常用作简单的返回值的类型,还有逻辑值,比如pdTRUE/pdFALSE
2.2 命名规范
2.2.1 变量名
变量名前缀:表示变量名的数据类型
变量名前缀 | 含义 |
uint32_t定义的变量前缀:ul | u:unsigned无符号,l:long、int32_t长整型 |
uint16_t定义的变量前缀:us | u:unsigned无符号,s:short、int16_t短整型 |
uint8_t定义的变量前缀:uc | u:unsigned无符号,c:char、int8_t短整型 |
stdint.h中未定义的变量类型,定义的变量前缀:x | 比如:BaseType_t,TickType_t,其他非标准的类型:结构体、task_handle、queue_handle等定义的变量 |
stdint.h中未定义的无符号变量类型,定义的变量前缀:ux | 比如:UBaseType_t定义的变量 |
size_t定义的变量前缀:ux | size_t定义的变量 |
e | 枚举变量 |
p | 指针变量 |
c | 根据MISRA代码规则,char定义的变量只能用于ASCII字符 |
pc | 根据MISRA代码规则,char*定义的指针变量只能用于ASCII字符串 |
2.2.2 函数名
函数名前缀:返回值类型 + 所定义的文件位置
函数名前缀 | 含义 |
---|---|
vTaskPrioritySet | 返回值类型:void 在task.c中定义 |
xQueueReceive | 返回值类型:BaseType_t 在queue.c中定义 |
pvTimerGetTimerID | 返回值类型:pointer to void 在timer.c中定义 |
prv(private) | 表示私有函数,被static修饰 |
2.2.3 宏
宏的名字是大写,同时用下划线分开,可以添加小写的前缀,表示所定义的文件位置
宏的前缀 | 含义:在哪个文件里定义 |
port (比如portMAX_DELAY) | portable.h或portmacro.h |
task (比如taskENTER_CRITICAL()) | task.h |
config (比如configUSE_PREEMPTION) | FreeRTOSConfig.h |
pd (比如pdTRUE) | projdefs.h |