【STM32】入门(十三):FreeRTOS
创始人
2024-05-30 11:01:51
0

【STM32】STM32单片机总目录

1、FreeRTOS简述

完全免费:FreeRTOS是完全免费的实时操作系统;
源码简单:只需 3 个 RTOS 移植通用的源文件和 1 个微控制器专用的源文件;
镜像较小:具有最小 ROM、RAM 和处理开销。RTOS 内核二进制映像通常介于 6 K 到 12 K 字节之间;
MISRA :源码符合 MISRA 编码标准,MISRA 是由汽车产业软件可靠性协会(MISRA)提出的C语言开发标准;
pc-lint:源码可以使用pc-lint进行合规性检查;https://pclintplus.com/
中文网站:https://www.freertos.org/zh-cn-cmn-s/index.html

2、源码惯例

2.1 命名惯例

RTOS 内核和演示应用程序源代码使用以下惯例:
1)变量

uint32_t 类型变量以 ul 为前缀,其中“u”表示“unsigned” ,“l”表示“long”。
uint16_t 类型变量以 us 为前缀,其中“u”表示“unsigned” , “s”表示“short”。
uint8_t  类型变量以 uc 为前缀,其中“u”表示“unsigned” , “c”表示“char ”。
非 stdint 类型的变量以 x 为前缀。例如,BaseType_t 和 TickType_t,二者分别是可移植层定义的定义类型,主要架构的自然类型或最有效类型,以及用于保存 RTOS ticks 计数的类型。
非 stdint 类型的未签名变量存在附加前缀 u。例如,UBaseType_t(未签名 BaseType_t)类型变量以 ux 为前缀。
size_t 类型变量也带有 x 前缀。
枚举变量以 e 为前缀
指针以附加 p 为前缀,例如,指向 uint16_t 的指针将以 pus 为前缀。
根据 MISRA 指南,未限定标准 char 类型仅可包含 ASCII 字符,并以 c 为前缀。
根据 MISRA 指南,char * 类型变量仅可包含指向 ASCII 字符串的指针,并以 pc 为前缀。

2)函数

文件作用域静态(私有)函数以 prv 为前缀。
根据变量定义的相关规定,API 函数以其返回类型为前缀,并为 void 添加前缀 v。
API 函数名称以定义 API 函数文件的名称开头。例如,在 tasks.c 中定义 vTaskDelete,并且具有 void 返回类型。

3)宏

宏以定义宏的文件为前缀。前缀为小写。例如,在 FreeRTOSConfig.h 中定义 configUSE_PREEMPTION。
除前缀外,所有宏均使用大写字母书写,并使用下划线来分隔单词。

2.2 数据类型

1)仅使用 stdint.h 类型和 RTOS 自带的 typedef,但以下情况除外:
char
根据 MISRA 指南,仅在未限定字符类型包含 ASCII 字符方可使用未限定字符类型。

char *
根据 MISRA 指南,仅在未限定字符指针指向 ASCII 字符串时方可使用未限定字符指针。使用需要 char * 参数的标准库函数时,无需抑制良性编译器警告,此举尤其考虑到将一些编译器默认为未限定 char 类型是签名的,而其他编译器默认未限定 char 类型是未签名的。

2)针对每个移植定义四种类型。
TickType_t
如果 configUSE_16_BIT_TICKS 设置为非零 (true) ,则将 TickType_t 定义为未签名的 16 位类型。如果 configUSE_16_BIT_TICKS 设置为零 (false),则将 TickType_t 定义为未签名的 32 位类型。请参阅 API 文档的自定义章节查看完整信息。
32 位架构应始终将 configUSE_16_BIT_TICKS 设置为 0。

BaseType_t
架构中最有效、最自然的类型。例如,在 32 位架构上,BaseType_t 会被定义为 32 位类型。在 16 位架构上,BaseType_t 会被定义为 16 位类型。如果将 BaseType_t 定义为 char,则须特别注意确保将签名字符用于可能为负的函数返回值来指示错误。

UBaseType_t
未签名的 BaseType_t。

StackType_t
意指架构用于存储堆栈项目的类型。通常是 16 位架构上的 16 位类型和 32 位架构上的 32 位类型,但也有例外情况。供 FreeRTOS 内部使用。

3、概念

3.1 多任务原理

每个执行程序都是受操作系统控制的任务(或线程)。如果一个操作系统能够以这种方式执行多个任务, 则可称其为多任务操作系统。
使用多任务操作系统可以简化原本复杂的软件应用程序的设计 :

操作系统的多任务处理和任务间通信功能允许将复杂的应用程序 分割成一组更小、更易于管理的任务。
通过分割,您可以更轻松地执行软件测试、分解团队内部工作以及复用代码。
复杂的时序和排序细节可以从应用程序代码中移除,由操作系统负责。

常规处理器一次只能执行一个任务,但通过任务间快速切换, 多任务操作系统可以使每个任务看起来像是同时在执行。 如下图所示, 该图展示了与时间相关的三个任务的执行模式。 任务名称采用颜色编码,并写在左手边。 时间从左向右移动, 彩色线条显示了在任何特定时间正在执行的任务。 上方展示了所感知的并发执行模式, 下方展示了实际的多任务执行模式。
在这里插入图片描述

3.2 任务调度

调度器是内核中负责决定在任何特定时间应执行哪些任务的部分。内核可以在任务生命周期内多次挂起并且稍后恢复一个任务。

调度策略是调度器用来决定在任何时间点执行哪个任务的算法。 非实时多用户系统的策略极有可能使每个任务具有"公平"比例的处理时间。

任务除了被迫被内核挂起之外,还可以选择将自己挂起。 如果它想要延迟(睡眠)一段固定时间,或者等待(阻塞)资源 变为可用(例如串行端口)或将要发生的事件(例如按键),它将执行此操作。 阻塞的或正在睡眠的任务无法执行,并且不会分配任何处理时间。
在这里插入图片描述

请参阅上图中的数字:

在 (1) 处,任务 1 正在执行。
在 (2) 处,内核挂起(换出)任务 1......
......在 (3) 处,恢复任务 2。
在 (4) 处,任务 2 正在执行,为独占访问,会锁定一个处理器外围设备。
在 (5) 处,内核挂起任务 2......
......在 (6) 处,恢复任务 3。
任务 3 尝试访问相同的处理器外围设备,发现其被锁定,任务 3 无法继续,因此在 (7) 处挂起。
在 (8) 处,内核恢复任务 1。
等等。
接下来任务 2 执行时 (9),完成对处理器外围设备的访问,因此解锁。
再下来任务 3 执行时 (10),发现现在可以访问处理器外围设备,于是开始执行,直到被内核挂起为止。

3.3 上下文切换

当一个任务执行时,它会利用处理器/微控制器寄存器,并像其他程序一样访问 RAM 和 ROM。这些资源(处理器寄存器,堆栈等)一起组成了任务执行上下文。
在这里插入图片描述

一个任务是一段有顺序的代码——它不知道什么时候会被内核挂起或恢复, 甚至不知道什么时候自己被挂起或恢复过。请参考如下示例: 一个任务在即将执行将两个处理器寄存器内包含的数值相加之前被挂起。 当该任务被挂起时,其他任务会执行,还可能会修改处理器寄存器的数值。恢复时, 该任务不会知道处理器寄存器已经被修改过了——如果它使用经修改过的数值, 那么求和会得到一个错误的数值。

为了防止这种类型的错误,任务在恢复时必须有一个与挂起之前相同的上下文 。通过在任务挂起时保存任务的上下文,操作系统内核负责确保 上下文保持不变。任务恢复时,其保存的上下文在执行之前由操作系统内核 恢复。保存被挂起的任务的上下文和恢复被恢复的任务的上下文的过程被称为 上下文切换。

3.4 实时应用程序

实时操作系统 (RTOS) 也实现了多任务处理—— 但它们的目标与非实时系统有着巨大差异。不同的目标反映在调度策略中。设计实时/嵌入式系统 是为了对现实世界事件作出及时响应。现实世界中发生的事件 存在截止时间,因此实时/嵌入式系统必须在此之前响应, RTOS 调度策略必须确保遵守这些截止时间的要求。
为实现这一目标,软件工程师必须首先为每个任务分配优先级。然后,RTOS 的调度策略 简单地确保能够执行的最高优先级任务,是被给予处理时间的任务。如果同等优先级的任务准备同时运行, 这可能需要在它们之间“公平”分享处理时间。

示例:

最基本的例子就是包含键盘和 LCD 的实时系统。用户应在合理时间内收到 各按键的视觉反馈——如果用户在此期间无法看到按键已被接受,则该软件产品的使用感会很差。如果最长接受时间为 100 毫秒,则任何介于 0 和 100 毫秒之间的响应都是可接受的。此功能可作为一个具有以下结构体的自主任务来实现:

 void vKeyHandlerTask( void *pvParameters ){// 按键处理是一个连续的过程,因此任务是使用无限循环实现的(就像大多数实时任务一样)。for( ;; ){// 等待键按下// 处理键值}}

现在假设实时系统也在执行数据处理功能。必须对输入进行采样、过滤并每 2 毫秒执行一次控制周期。为使过滤器正确运行,采样时间规则必须精确到 0.5 毫秒。该功能可以实现为一个具有以下结构的自主任务:

 void vControlTask( void *pvParameters ){for( ;; ){// 暂停等待2毫秒,从上一个周期开始// 对输入进行采样// 过滤采样的输入// 执行控制算法// 输出结果}}

软件工程师必须将控制任务的最高优先级分配为:

控制任务的截止时间比按键处理任务的截止日期更严格。
错过截止时间对控制任务的影响要大于对按键处理程序任务的影响。

3.5 实时调度

下图演示了实时操作系统如何调度上一页中定义的任务。RTOS 自身创建了一个任务:空闲任务,该任务仅在没有其他任务执行时才会执行。RTOS 空闲任务总是处于就绪态。

在这里插入图片描述
请参阅上图:

开始时,这两个任务都不能运行:vControlTask 等待合适的时间来开始新的控制周期, vKeyHandlerTask 等待按键操作。处理器时间分配给了 RTOS 空闲任务。
在时间 t1 处,一个按键事件发生。vKeyHandlerTask 可以执行,其优先级高于 RTOS 空闲任务,因此获得了处理器时间。
在时间 t2 处,vKeyHandlerTask 已完成按键处理并更新 LCD。 在按下另一个键之前该任务无法继续执行,因此将自己挂起,RTOS 空闲任务恢复执行。
在时间 t3 处,定时器事件指示执行下一个控制循环的时间到了。vControlTask 现在可以执行,因为优先级最高的任务被立刻分配了处理器时间。
在时间 t3 和 t4 之间,vControlTask 仍在执行时,发生了按键事件。vKeyHandlerTask 可以执行,但由于其优先级低于 vControlTask,因此未获得任何处理器时间。
在 t4 处, vControlTask 完成了控制周期的处理,并且直到下一次定时事件的发生前不能重新开始运行,进入阻塞态 。vKeyHandlerTask 现在成为可以运行的最高优先级的任务,因此获得处理器时间以处理先前的按键事件。
在 t5 处,按键事件处理完成,并且 vKeyHandlerTask 进入阻塞态等待下一次按键事件。再一次,两个任务都未进入就绪态, RTOS 空闲任务获得 处理器时间。
在 t5 与 t6 之间,定时事件发生并处理,没有进一步的按键事件发生。
在 t6 处发生按键事件,但在 vKeyHandlerTask 完成按键处理之前,发生了定时事件。此时两个任务都可以执行。由于 vControlTask 具有更高的优先级,因此 vKeyHandlerTask 在完成按键操作之前被挂起,vControlTask 获得处理器时间。
在 t8 处,vControlTask 完成控制周期的处理,然后进入阻塞态等待下一次事件。vKeyHandlerTask 再次 成为运行的最高优先级任务,因此获得处理器时间,以便完成按键处理。

3.6 滴答

休眠时,RTOS 任务将指定需要“唤醒”的时间。
阻塞时,RTOS 任务可以指定希望等待的最长时间。

FreeRTOS 实时内核通过滴答计数变量测量时间。定时器中断(RTOS 滴答 中断)以严格的时间精度增加滴答数——允许实时内核以所选择的定时器中断频率的分辨率来测量时间 。

每次滴答数增加时,实时内核必须检查是否现在是解除阻塞或唤醒任务的时间。 在滴答 ISR 期间唤醒或解除阻塞的任务的优先级 可能高于被中断任务的优先级。 在这种情况下,滴答 ISR 应该返回到新唤醒/未阻塞任务——有效地中断了一个任务, 但返回到另一个任务。 如下图所示:
在这里插入图片描述

请参阅上图中的数字:

在 (1) 处,RTOS 空闲任务正在执行。
在 (2) 处,RTOS 滴答发生,控制权转移到滴答 ISR (3)。
RTOS 滴答 ISR 使 vControlTask 准备就绪,并且由于 vControlTask 的优先级高于 RTOS 空闲任务, 因此将上下文切换到 vControlTask 的上下文。
由于执行上下文现在是 vControlTask 的上下文,退出 ISR (4) 会将控制权返回给 vControlTask, 后者开始执行 (5)。

以这种方式发生的上下文切换称为抢占式,因为中断的任务被抢占而不是主动挂起。
TODO:

https://www.freertos.org/zh-cn-cmn-s/implementation/main.html

相关内容

热门资讯

以桥为题的高一作文【优选6篇... 以桥为题的高一作文 篇一桥,是连接两岸的纽带,是沟通交流的通道。它不仅仅是一座建筑物,更是一种象征,...
爱在平安夜的高二作文(优选6... 爱在平安夜的高二作文 篇一平安夜,这是一个充满温暖和祝福的夜晚。在这个特别的夜晚里,人们用不同的方式...
空手道馆游高一作文【通用3篇... 空手道馆游高一作文 篇一空手道馆是一个我一直向往前往的地方。终于,在高一的时候,我有机会参观了一家空...
我在等待的作文(优质3篇) 我在等待的作文 篇一等待,是一种不可避免的存在。无论是等待父母的归来,还是等待考试的成绩,亦或是等待...
缺陷美作文 缺陷美作文  在日常的学习、工作、生活中,大家或多或少都会接触过作文吧,作文是人们把记忆中所存储的有...
以英雄为题的高中作文(实用6... 以英雄为题的高中作文 篇一英雄的品质英雄是我们心中最崇高的存在,他们以无私的奉献和勇敢的行动,为社会...
温故与知新高一优秀作文800... 温故与知新高一优秀作文800字 篇一温故与知新温故而知新,可以为师矣。这句话出自《论语·为政》一章,...
互相尊重作文【优秀3篇】 互相尊重作文 篇一互相尊重是一种非常重要的品质,它可以帮助我们建立良好的人际关系,促进社会和谐的发展...
青春期(最新6篇) 青春期 篇一青春期是人生中一个重要的阶段,它标志着从儿童向成年的过渡。在这个时期,我们身心发生了许多...
高中优秀作文(优选6篇) 高中优秀作文 篇一:人生的选择与坚持人生就像一场马拉松比赛,我们每个人都在这条赛道上奋力前行。而在这...
高一作文开学第一课【通用6篇... 高一作文开学第一课 篇一开学第一课,让我明白了“自律”的重要性新学期开始了,我迫不及待地踏入高一的大...
细节决定成败的议论文【精选6... 细节决定成败的议论文 篇一细节决定成败,这是一个被广泛认同的观点。在人们追求成功的道路上,细节往往是...
竹君作文800字左右高二(精... 竹君作文800字左右高二 篇一:探索未知的世界在我们的生活中,有许多未知的领域等待我们去探索。这些未...
山东高考满分作文:丝瓜藤与肉... 山东高考满分作文:丝瓜藤与肉豆须 篇一丝瓜藤与肉豆须丝瓜藤和肉豆须都是我家院子里常见的植物。它们虽然...
冲刺高考的高三励志作文800... 篇一:冲刺高考的高三励志作文800字高三是每个学生都经历的一个重要阶段,也是冲刺高考的关键时期。在这...
上善若水高一作文【精选3篇】 上善若水高一作文 篇一标题:善良的力量善良是一种美德,它如同水一样,温润而宽容,给予人们希望和力量。...
志存高远方能远航高三作文(优... 志存高远方能远航高三作文 篇一在高三这个关键的学习阶段,我们作为学生要有志存高远的目标,才能在未来的...
高中英语作文|Healthy... 高中英语作文|Healthy Diet 健康饮食 篇一Title: The Importance o...
高一剪纸英语作文范文(最新6... 高一剪纸英语作文范文 篇一The Art of Paper Cutting in High Scho...
铁肩担道义【精彩3篇】 铁肩担道义 篇一:守护公平正义的铁肩道义是社会的基石,而铁肩则是守护道义的力量。在现代社会中,铁肩担...