)
FreeRTOS介绍一简介在裸机开发中我们所使用的开发板上面搭载的微处理器都是单核的因此当我们想要让单片机同时控制多个外设时据需要花费大量的精力去处理多任务之间的切换以及隔离问题。我们早期使用的编程方法主要是时间片轮转和伪调度器架构两种编程思想来处理这些问题。我们接触到了FreeRTOS之后多任务的处理操作就变得相对简单很多了操作系统的作用是协调系统资源以及处理多任务但是FreeRTOS和我们熟知的操作系统不同它适配资源受限的单片机上用于协调多任务的并发执行我们之前在裸机开发时使用的编程思想和FreeRTOS的底层实现有诸多相似之处后面我们会在FreeRTOS底层实现原理中进行更深入的介绍任务调度器实现原理由于FreeRTOS是运行在单核处理器上的单核处理器同一时刻只能运行一个任务因此我们如果想要让单片机同时处理多个任务首要解决的应该是上下文切换的问题。FreeRTOS的上下文切换主要依赖以下几个机制寄存器程序运行的本质就是CPU对内存、外设寄存器等存储元件的读写与计算但是CPU并不能直接对内存里的数据进行计算实际在进行计算时需要将内存中的数据移动到CPU周边的寄存器中存储运算数据的寄存器是通用寄存器例如在STM32F103中就有R0~R1213个32位通用寄存器当然并非所有的寄存器都是用来保存计算数据的其中有一个在FreeRTOS中发挥着重要作用的寄存器就是程序计数寄存器简称PC寄存器PC寄存器中保存着CPU中将要执行的指令所在的Flash地址每当CPU执行完一条指令之后PC寄存器都会自动指向下一条命令。结合上面的内容我们不难推出CPU执行的操作主要受寄存器控制CPU每次都会根据PC寄存器中保存的地址去内存中取指令然后将对应的数据从内存中放入通用寄存器中对寄存器中的数据进行计算之后再将结果写回到内存中。如果我们能够尝试修改寄存器的工作方式那么就能够让CPU实现多任务处理在任何一个瞬间CPU只能拥有一组寄存器状态这也就决定了它只能执行一条命令时间片在上面的介绍中我们知道了CPU同一时间只能处理一个任务但是在宏观层面上我们又想要达到多任务并行的效果FreeRTOS为了满足我们的需求选择将时间进行切片由于CPU的运行速度快因此我们可以尝试将较长的一段时间切分成多个较短的时间然后将时间片分发给不同的任务CPU按照指定的顺序依次不同任务当该任务的时间片耗尽之后就切换到下一个任务这样就能够实现类似于多任务并行的效果了。大多数情况下我们选择SysTick作为系统的时钟源在FreeRTOS中一个时间片就等于一个Tick系统滴答的长度而系统滴答定时器每秒钟会产生1000次中断因此一个时间片的长度就是1ms任务栈上面的介绍中我们知道了不同任务之间都会有自己的时间片在时间片持续期间CPU会执行当前任务中的指令然后时间片耗尽了CPU又会跳转到下一条指令去执行指令。这种任务切换需要解决数据存储的问题这就像我们平时打游戏一样假设我们正在打一个游戏副本打到一半的时候好友邀请我们去打另一个副本但是我们无法在短期内结束当前副本因此我们就可以将当前的副本内容进行存档和好朋友打新副本打到一半他突然掉线了在等待的过程中我们就可以打开刚才保存的副本从上次保存的进度继续玩。在FreeRTOS中要想在不同的任务之间反复横跳都需要进行上下文切换为了解决上下文切换的问题FreeRTOS选择用任务栈来进行”存档“每一个任务都有自己专属的任务栈每次切换到新任务时都会让对应的任务栈进行出栈操作将对应的数据写入CPU的寄存器中该任务的时间片耗尽之后会又会进行压栈压栈结束之后再跳转到下一个任务中继续执行作为用户我们可以在使用FreeRTOS时自己手动配置任务栈的大小任务状态介绍在FreeRTOS中任何一个任务在任意时刻必定只能处于一下四个核心状态之一分别是运行态、就绪态、阻塞态和挂起态在官方文档中对应的状态转换图如下由于该图是英文版本的看起来比较难受因此我让codex生成一张中文版的状态转换图来帮助记忆作用任务状态的作用主要是为了解决任务中延时的问题假设一个任务中使用了延时函数该任务也会一占用时间片其它任务就无法及时响应如果延时的任务能够老老实实的延时而不占用时间片的话那么系统的时效性还能够再提升我们也就可以放心的在任务中使用延时接下来就让我们详细的了解一下每个状态的作用就绪态当我们使用osThreadNew函数创建任务后任务就会被FreeRTOS认为处于就绪态等待被分配时间片运行当程序运行了osKernelStart系统内核启动FreeRTOS的任务调度器会从正在排队的就绪态任务中取出一个分配时间片然后该任务就可以开始运行运行态上一阶段中处于就绪态的任务获得时间片之后就可以开始运行此时任务状态就叫做运行态当处于运行态的任务时间片耗尽之后FreeRTOS的调度器就又会将其送回就绪态排队并给下一个就绪态的任务分配时间片让其进入运行态运行运行态和就绪态的不断循环就实现了任务依次分配时间片运行阻塞态为了解决我们之前提到的任务调用延时函数会空耗CPU的类似问题FreeRTOS又创建了阻塞态当一个任务处于运行态时如果运行了osDelay函数那么不管当前的时间片有没有耗尽任务都会直接进入阻塞态让出CPU的运行资源调度器便会继续为下一个处于就绪态的任务分配时间片运行处于阻塞态的任务不会再参与时间片的分配直到osDelay的延时时间结束。这就解决了任务在延时时占用CPU资源的问题在这里需要辨析的是想要让任务进入阻塞态就一定要使用osDelay延时函数HAL_Delay函数的底层实现原理和FreeRTOS中的延时函数底层的实现原理并不相同HAL_Delay函数实现延时依靠的是死循环轮询 SysTick 变量这个过程实现需要一直占用CPU挂起态如果某一个任务接下来一段时间不再需要运行了并且也不需要等待任何时间超时或数据时间那就可以通过手动调用osThreadSuspend函数的方式让任务进入挂起态进入挂起态的任务将不再参与任务调度我们后续可以根据需求再唤起对应任务总结本次先介绍这些内容后续的还会更新更多内容