错误
- 别把几节课内容写在一起
- sprintf和printf的不正确使用也会导致 硬件错误
- 推荐按键配上上拉
- 能不开的宏就不开
- 开启软件定时器会导致程序只能执行一个任务
1.freeros介绍
RTOS
-
实时操作系统(RTOS-Real Time Operating System)中实时(Real Time)指的是任务(Task)或者说实现一个功能的线程(Thread)必须在给定的时间(Deadline)内完成。(强调实时性)
-
一个实时操作系统能尽力保障每个任务的运行时间在规定时间内完成,这包括
-
(1)对中断和内部异常的处理
-
(2)对安全相关的事件的处理
-
(3)任务调度机制等
-
-
目前比较流行的实时操作系统包括黑莓QNX,FreeRTOS,uCOS,RT-Thread等
-
特点:
- 分而治之
- delay,任务调度,高优先级中出现delay就会将cpu使用权交给低一级的函数
- 任务堆栈,每个任务都有个自己的栈空间,实现断点(需要注意:中断和任务不一样,中断可以打断任一任务),保存局部变量,以及上下文信息
裸机
- 裸机,又称前后台系统,前台系统指中断服务函数,,后台系统中指主循环
- 特点:
- 实时性差,应用程序轮流执行
- delay,空等待,CPU不执行其他代码
- 结构臃肿
2. 任务调度
- 使用调度算法决定执行哪个任务
- 支持3种任务调度
-
抢占式调度:针对优先级不同,允许更高优先级的任务在任何时刻抢占正在执行的低优先级任务
-
时间片调度:针对优先级相同,当多个任务的优先级相同时,任务调度器会在每个时钟节拍到来的时候切换任务。
-
携程式调度 (了解即可):其实就是轮询,当前执行任务将会一直运行,同时高优先级的任务不会抢占低优先级任务。FreeRTOS现在虽然还在支持,但官方已经明确表示不再更新协程式调度。
-
抢占式调度过程
-
运行过程如下:
-
- 首先Task1在运行中,在这个过程中Task2就绪了,在抢占式调度器的作用下,Task2会抢占Task1的运行。
-
- Task2运行过程中,Task3就绪了,在抢占式调度器的作用下Task3会抢占Task2的运行。
-
- Task3运行过程中,Task3阻塞了(系统延时或者等待信号等),此时就绪中,优先级最高的任务Task2执行。
-
- Task3阻塞解除了(延时到了或者接收到信号量),此时Task3恢复到就绪态中,抢占Task2的运行。
-
-
总结:
-
- 高优先级任务,优先执行。
-
- 高优先级任务不停止,低优先级任务无法执行。
-
- 被抢占的任务将会进入就绪态。
-
时间片调度过程
- 在同等优先级下的任务轮流享有相同的CPU时间,这就叫做时间片,在freertos中,一个时间片等于一个systick周期(可设置滴答定时器中断周期)
-
运行过程如下:
-
- 首先Task1运行完一个时间片后,切换至Task2运行。
-
- Task2运行完一个时间片后,切换至Task3运行。
-
- Task3运行过程中(还不到一个时间片),Task3阻塞了(系统延时或者等待信号量等),此时直接切换到下一个任务Task1执行.
-
- Task1运行完一个时间片后,切换至Task2运行。
-
-
总结:
-
- 同等优先级任务,轮流执行。
-
- 一个时间片大小,取决滴答定时器中断周期。
-
- 没有用完的时间片不会再使用,任务Task3下次得到执行时间还是按照一个时间片的时钟节拍运行。
-
2.Freertos任务状态
- 总共有4种状态
- 运行态 :正在执行的任务,该任务就处于运行状态(注意:在STM32中,同一时间仅一个任务处于运行态)。
- 就绪态 :如果该任务已经能够被执行,但当前还未被执行,那么该任务处于就绪态。
- 阻塞态 :如果一个任务因为延时或者等待外部事件发生,那么这个任务就处于阻塞态。
- 挂起态 :类似于暂停,调用函数vTaskSuspend()进入挂起态,需要调用解挂函数vTaskResume()才可以进入就绪态。
转换关系图
-
总结:
-
- 仅就绪态可以转换成运行态。
-
- 其他状态的任务想要运行,必须先转换成就绪态。
-
任务状态列表
-
任务的四种状态中,除了运行态,其他三种任务状态的任务都有其对应的任务状态列表。(列表类似于链表)
- 就绪列表 : pxReadyTasksLists[x],其中x代表任务优先级数值。
- 阻塞列表 :pxDelayedTaskList
- 挂起列表 :xSuspendedTaskLis
-
调度器总是在所有就绪列表种选择,选取最高优先级的任务执行
-
相同优先级的任务会链接在同一个就绪列表中
3. 任务创建和删除API函数(熟悉)
任务动态创建和静态创建的区别
-
动态创建任务:任务的任务模块,以及任务的栈空间所需要的内存,均从Freertos管理的堆中分配
-
静态创建任务:任务的任务控制块以及任务的栈空间所需的内存,需要用户自己分配
-
一般使用动态创建
-
实现动态创建任务流程
-
- 将FreeRTOSConfig.h文件中宏configSUPPORT_DYNAMIC_ALLOCATION配置为1。
-
- 定义函数入口参数。
-
- 编写任务函数。
-
-
实现静态创建任务流程
-
- 将FreeRTOSConfig.h文件中宏configSUPPORT_STATIC_ALLOCATION配置为1。
-
- 定义空闲任务&定时器任务的任务堆栈以及TCB。
-
- 实现两个接口函数(vAppLicationGetldleTaskMemory() 空闲任务接口函数和vApplicationGetTimerTaskMemory()定时器任务接口函数)。
-
- 定义函数入口参数。
-
- 编写任务函数。
-
任务控制块(TCB)结构体成员介绍
删除任务
-
任务删除函数用于删除已经被创建的任务,被删除的任务将从就绪任务列表、阻塞任务列表、挂起任务列表和事件列表中移除。
-
在FreeRTOS中,
vTaskDelete()删除任务时不会自动释放任务分配的内存。为了避免内存泄漏,您需要在删除任务之前手动释放任何动态分配的内存。对于静态分配的内存,则不需要手动释放。确保在设计任务时考虑内存管理,以保持系统的稳定性和效率。 -
注意:
-
- 当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)。
-
- 空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存空间(静态任务),必须用户在任务被删除前提前释放,否则将会导致内存泄漏。
-
-
如果是删除自己,会先将该任务添加到等待删除列表中,内存释放将在空闲任务执行,不会再任务执行时,删除堆栈空间
5.上下文切换
(中断的底层实现?)
- 当一个任务执行时,它会利用处理器/微控制器寄存器,并像其他程序一样访问 RAM 和 ROM。这些资源(处理器寄存器,堆栈等)一起组成了任务执行上下文。(数据+一些状态)
- 当执行一个任务时想要切换到另外一个任务时,需要先将任务A的寄存器数据保存,在将任务B的寄存器数据恢复。保存被挂起的任务的上下文和恢复被恢复的任务的上下文的过程被称为 上下文切换。
- 在freertos中,每任务都有自己独立的任务栈,寄存器数据便是保每个每个任务对应的任务堆栈之中。
堆栈的概念
- 堆栈是一段连续的存储空间,按照后入先出的方式工作,只能从堆栈的顶部取出或存入数据,即堆栈能够保存数据的顺序性
- 堆:是一个进程开启后,系统分配给他的空间,一般这个空间是全局的,系统上所有动态分配的对象都是在这个空间上分配。堆里的数据是有数据结构的,其空间占用是不连续的。在os系统中常用到堆,其他不常用
- 栈:是一个线程维护的一个先进后出的数据结构,,主要用于静态变量的分配及维护程序各个函数调用时使用,栈里的空间是没有数据结构的,其空间占用是连续的。
空闲任务
-
RTOS 调度器启动时,自动创建空闲任务,以确保始终存在一个能够运行的任务。
-
空闲以最低优先级创建,以确保如果有更高的优先级应用程序任务处于准备就绪状态,空闲任务则不使用任何 CPU 时间。
-
空闲任务负责释放被删除的任务的内存。
6.中断管理
-
FreeRTOS中,将PendSV和SysTick设置最低中断优先级(数值最大,15),保证系统任务切换不会阻塞系统其他中断的响应。 (屏蔽的是中断响应)
- 比如: BASEPRI设置为0x50(只看高四位,也就是5),代表中断优先级在5-15内的均被屏蔽(由freertos管理),0~4的中断优先级正常执行
- 在FreeRTOS中,进入临界段代码时需要关闭中断,在处理完临界段代码后再重新开启中断。(进入临界段会调用disableinterrupt代码,退出同理)
-
在中断服务函数中调用FreeRTOS的API函数需注意:
- 中断服务函数的优先级需在FreeRTOS所管理的范围内,阈值由configMAX_SYSCALL_INTERRUPT_PRIORITY指定。
-
建议将所有优先级位指定为抢占优先级位,方便FreeRTOS管理。
- 在中断服务函数里边需调用FreeRTOS的API函数,必须使用带“FromISR”后缀的函数。
-
/*延时函数底层中会开关中断*/