STM32的FreeRtos初识

FreeRtos就是一个深度绑定Cortex-M内核的操作系统,它是基于systick运行的一个操作系统。

FreeRtos的设计理念就是提高CPU的使用率,利用CPU高频的特性,将一个while(1)的循环切割成多个while(1)的循环,也就是多个任务,
虽然每个任务表面上写的都是while(1),感觉好像只能一直在这里面执行,但是FreeRTOS精髓的地方就在于,它利用了中断机制以及
PSP的管理或者其他什么的,开辟了不止一个栈,每个栈里都存放了不同的PC地址,通过修改PC的值,完成while(1)的跳转。这里有必要讲一下栈,当我们裸机开发的时候,PC指针正常跑,执行完
一条指令,指针数字+4;当中断来的时候,将8个寄存器入栈进MSP,其中就包括了PC寄存器的数值,用于保存现场。然后PC指针修改并跳转
去执行中断服务函数,当执行完之后,收到汇编的跳转指令,硬件就会把MSP中存放的数值重新赋值给寄存器,其中就包括PC寄存器,然后
程序又按照PC的值恢复执行了,这是裸机。FreeRTOS是怎么样的呢,程序正常时也是按照PC指针的位置在跑着,也是跑的while(1)循环,(有必要说明的一点是,
Cortex-M的指令执行是不经过RAM的,也就是说PC中存放的是Flash中的地址,进中断的时候也只是将这个地址在RAM中暂存一下而已),
但是这个PC指针的范围是一小段,也就是这个任务所需要的地址范围,这些是编译器负责的,当我有多个任务的时候,每个任务也就对应
了flash中的一段地址。准备工作完成了,终于可以开启RTOS的切任务了。假设目前正在执行任务A,当有中断或者其他需要打断任务A
的指令到来时,硬件直接将8个寄存器的值压入了当前SP所指的地址,也就是PSP所指的A的栈,然后切换成MSP,去到中断服务程序,
然后在中断中将PENDSV挂起,结束中断。然后进入PENDSV这个优先级最低的中断,这个时候,FREERTOS在这个中断中设置了下一个PC的地址,
并且将任务A的其余的寄存器保存到了A的栈中,然后中断结束,调用PC指针,跳转到任务B。(还是有点模糊,不知道对不对)
上面说的是通过中断的方式切换任务,还有其他的切换任务的方式,当各个任务快速有序地切换的时候,并行的操作系统就完成了,接下来再深入
讨论一下FREERTOS。

FREERTOS的核心思想是希望把一个while循环分割成好多个时间片+任务抢占优先级(跟中断优先级没有任何关系)来决定下一个执行的任务。
按照框架来看,有好几种状态,分别是就绪态,运行态,挂起态,阻塞态,延时态,只有就绪态能够通往运行态,也就是说下一个要执行的任务都在就绪态当中。
但是就绪态的任务要排队:对于任务抢占优先级的规则,数字越大优先级越高,同样优先级的排成一列。只有当高优先级的那一列都没了,才会执行次优先级的任务。
所以说,如果高优先级的任务执行完了其时间片不将它阻塞或者挂起,那么它会直接进入就绪态,等待下一次的执行,低优先级的任务就没有执行的机会。

然后再深入讨论一下FreeRTOS。这个操作系统替我们接管了CPU的寄存器,比如说PC寄存器,自从进入了系统之后,就一直是它在掌控了,我们能做的只是控制任务
在有限的范围内跳转(合理使用)。它定义了一个结构体 TCBx,这个结构体里存放了当前栈顶指针(pxTopOfStack),当前状态链表节点(xStateListItem),
事件链表节点(xEventListItem),当前有效优先级,栈起始地址,任务名。这个结构体里面有两个链表节点,这个节点内部有两个指针,是用于双向链表的。我们所有的
任务都是有这么一个独立的TCB结构体,根据里面的信息,决定将其挂载到哪一个队列,而之所以能挂载,就是前面说的链表节点。回顾上文,可以知道就绪态其实是链表数组,
数组的下标决定了优先级,虽然这个就绪态使用链表有点多此一举,毕竟不能插队,但是其他的状态比如阻塞链表,挂起链表,延时链表,事件链表,那么使用链表的时间复杂度就会
低很多,能够加快整个系统的响应速度。TCB确实是非常重要,当任务切换时,需要在PENDSV中将数据压入PSP的栈,利用的也是TCB,当延时时间到来是,systick查询的也是TCB,
所以可以形象的理解,任务的切换就是将TCB这个块块从一个地方搬到另一个地方,搬到哪儿就在哪儿起作用,搬到运行态的地方任务就开始运行。

下图是TCB
image

posted @ 2026-04-13 17:49  青春猪头青年  阅读(16)  评论(0)    收藏  举报