FreeRTOS 学习笔记(持续更新)
抢占式调度:
- 高优先级的可以优先运行,即使以及有低优先级的在运行,会先停止低的再运行高的(优先级按数字大小分大小)
- 高优先级任务不停止,低优先级的任务无法运行
- 被抢占的任务会进入就绪态
时间片调度:
- 同等优先级任务轮流享有相同的CPU占用时间(可设置),叫时间片,在Free RTOS中一个时间片等于SysTick(系统/滴答定时器)中断周期
- 没有用完的时间直接丢掉,不会补偿,永远都是一个时间片
任务状态:运行态,就绪态,阻塞态,挂起态(类似暂停,调用vTaskSuspend()进入挂起态,调用vTaskResume()解除挂起态进入就绪态)

仅就绪态可以直接进入运行态

任务创建与删除:
- 使用xTaskCreate() 动态方法创建任务
- 使用xTaskCreateStatic() 多了一个Static(静态)表示静态方法创建任务
- 使用vTaskDelete() 删除任务
- 动态静态区别在分配内存的方法不同,静态由用户自己分配,动态由Free RTOS自己分配,在它管理的堆中



任务控制块也就是TCB,可以看作是任务的身份证,用于辨识任务。

创建任务具体流程:
一:内存准备
- 申请任务堆栈内存(获取首地址)
- 申请任务控制块TCB内存(获取首地址)
- 将堆栈地址绑定到TCB的栈成员
二:TCB初始化
4. 调用 prvInitialiseNewTask()
1 初始化堆栈(可选填0xA5)
2 记录栈顶地址 → pxTopOfStack
3 保存任务名称 → pcTaskName[]
4 保存任务优先级 → uxPriority
5 绑定状态列表项/事件列表项与TCB关系
三:加入就绪列表
5. 调用 prvAddNewTaskToReadyList()
1 全局操作:
- 任务计数器 uxCurrentNumberOfTasks++
- 若是首个任务 → 初始化任务列表
2 非首任务时:
- 若调度器未启动:比较新任务与当前任务优先级,更高则切换当前TCB指向
- 优先级位图操作:将 uxTopReadyPriority 对应优先级位置1(标记就绪)
- 按优先级升序插入就绪列表末尾(值越小优先级越高)
3 栈与句柄初始化:
- 调用 pxPortInitialiseStack 初始化寄存器上下文空间
- 任务句柄指向TCB地址
四:动态响应
触发任务切换条件:
若调度器已运行 且 新任务优先级 > 当前任务 → 立即执行任务切换
删除任务具体流程:
一:任务定位
- 获取目标TCB
- 通过任务句柄判断删除对象:
- NULL → 删除当前任务(自身)
- 有效句柄 → 删除指定任务
- 通过任务句柄判断删除对象:
二:解除任务关联
- 移除任务所有关联列表
- 将任务从所属队列中移除,包括:
- 就绪列表(Ready List)
- 阻塞列表(Blocked List)
- 挂起列表(Suspended List)
- 事件等待列表(Event List)
- 将任务从所属队列中移除,包括:
三:删除类型分流
- 根据删除类型执行操作
- 情况A:删除自身任务
- 将当前任务加入 等待删除列表
- 内存释放委托:由空闲任务(Idle Task)后续执行 prvDeleteTCB() 释放TCB及栈内存
- 情况B:删除其他任务
- 立即调用 prvDeleteTCB() 直接释放内存
- 全局更新:
○ 任务计数器减一(uxCurrentNumberOfTasks--)
○ 阻塞超时校准:检查被删任务是否为下一个待唤醒的阻塞任务 → 更新超时计时器
- 情况A:删除自身任务
四:调度响应
- 强制切换条件:
- 若 调度器正在运行 且 删除的是自身任务 → 立即触发一次任务切换(上下文切换)

R11-R4寄存器实际是内存,就是存放任务的具体内容,任务要运行就是把任务函数地址赋值给PC寄存器,M4,M7的EXC_RETURN的bit4可以修改,1表示不支持浮点数,0表示支持
每个优先级前有一位,用来判断是不是有任务,有就置
1,方便后续任务切换

挂起与恢复

挂起:类似暂停,可以恢复
FromISP后缀:中断中专用,Free RTOS管理的中断优先级为5-15,要注意中断时调用Free RTOS的API函数要保证中断优先级不高于它管理的最高优先级(数字低为高)


建议把所有优先级位指定为抢占优先级位,方便FreeRTOS管理
任务挂起函数流程:
一:任务定位
- 获取目标TCB
- 任务句柄为 NULL → 挂起当前任务(自身)
二:解除任务关联
- 移除任务所有状态列表
- 从以下列表中移除任务:
- 就绪列表(Ready List)
- 阻塞列表(Blocked List)
- 事件列表(Event List)
- 从以下列表中移除任务:
- 加入挂起列表
- 将任务插入 挂起列表(Suspended List) 末尾
三:调度环境判断
- 调度器运行中操作
- 更新下一次阻塞时间(防止被挂起任务阻塞后续任务唤醒)
- 若挂起自身 → 立即触发任务切换
- 调度器未运行操作
- 检查挂起任务数:
- 挂起数 = 总任务数 → 当前控制块置 NULL
- 否则 → 激活下一个最高优先级任务
- 检查挂起任务数:
任务恢复函数流程:
一:恢复条件校验
- 宏 INCLUDE_vTaskSuspend 必须配置为 1
- 禁止恢复运行中的任务
二:恢复操作
- 检查任务状态
- 任务在挂起列表中 → 移出挂起列表
- 加入就绪列表
- 将任务按优先级插入就绪列表末尾
- 触发切换判断
- 恢复任务优先级 > 当前任务 → 触发任务切换
中断恢复函数流程:
一:中断安全操作
- 关闭FreeRTOS管理的中断
- 保存 BASEPRI 寄存器原值
- 防止被其他中断打断
二:恢复操作判断
- 调度器状态检查
- 调度器未挂起:
- 若任务在挂起列表 → 移出并加入就绪列表
- 恢复任务优先级 > 当前任务 → 标记 xYieldRequired = pdTRUE
- 调度器已挂起:
- 将任务插入 等待就绪列表(延后处理)
- 调度器未挂起:
三:环境还原与返回
- 恢复中断状态
- 还原 BASEPRI 寄存器值
- 返回切换标记
- 输出 xYieldRequired 供中断退出时判断是否切换任务

一:系统中断优先级配置寄存器
寄存器组:SHPR1、SHPR2、SHPR3
- 关键操作:
- 通过 SHPR3 配置 PendSV 和 SysTick 中断优先级
- 设定原则:将其设为最低优先级
- 设计目的:
- 确保系统任务切换(PendSV)和心跳调度(SysTick)
- 不阻塞其他高优先级中断的实时响应
二:中断屏蔽寄存器组
|
寄存器 |
功能描述 |
|---|---|
|
PRIMASK |
屏蔽所有可配置优先级的中断 |
|
FAULTMASK |
屏蔽除NMI外的所有异常和中断 |
|
BASEPRI |
核心寄存器:屏蔽优先级低于设定阈值的中断 |
BASEPRI 工作机制
- 阈值控制逻辑:
- 写入值 0xN0(N为十六进制优先级阈值)
- 示例:设定 BASEPRI = 0x50 时:
- 屏蔽范围:优先级值 5~15(值越大优先级越低)
- FreeRTOS依赖:
- 中断管理基石:通过动态调节BASEPRI实现:
- 临界区保护
- 中断嵌套控制
- 中断管理基石:通过动态调节BASEPRI实现:
三:技术实质说明
- 优先级数值规则:
- 数值越小优先级越高(0为最高)
- SHPR3设置最低优先级即赋予最大数值
- 安全隔离设计:
- PendSV/SysTick 低优先级 → 避免抢占关键外设中断
- BASEPRI 阈值屏蔽 → 保障高实时性中断响应
- FreeRTOS应用:
- portDISABLE_INTERRUPTS() 本质是设置BASEPRI阈值
- taskENTER_CRITICAL() 依赖此寄存器构建临界区



FreeRTOS中的列表实质上就是一个双向的环状链表,首尾相连,可以随意添加或删除列表项,有一个变量记录列表项数目,用于遍历,每个列表项有编号用于排序,初始化有一个末尾列表项,,它不计入列表数,编号最大。

两个校验值就是存放确定已知的常量,通过检查它是否变化来判断数据是否受到破坏,一般用于调试。

下面为迷你列表项,它也是列表项,但仅用于标记列表的末尾和挂载其他插入列表中的列 表项,用户是用不到迷你列表项的


- vListInitialise()初始化列表就是把列表末尾项编号赋为最大,首尾指向它自己,再初始化两个校验值,传入参数为要初始化的列表。
- vListInitialiseItem()初始化列表项就是把它所属列表项赋值为NULL,同样初始化两个校验值,传入参数为要初始化的列表项。
- vListInsertEnd()列表项末尾插入列表项是一种无序的排列,是把它插入到列表 pxIndex 指向列表项的前面,不管它的编号大小,传入参数为列表和要插入的列表项。
- vListInsert()列表插入列表项是一种有序排列,会根据编号来寻找合适的位置插入(如果最大就插入到末尾项前面,否则就遍历找位置)传入参数同上。
- uxListRemove()列表移除列表项就是跟链表删除一样,传入要删除的列表项,返回值为删除后剩余列表项数目


FreeRTOS任务切换出栈流程详解(严格遵循您提供的寄存器架构图)
任务切换出栈流程如下:首先通过三重指针(TCBTop->R3->R1->R0)获取TCB栈顶地址,这时R0指向R4也就是手动恢复起始点,就开始进行手动出栈,把栈内R4-R11寄存器储存的数据出栈到CPU的R4-R11寄存器,也就是用ldmia r0!, {r4-r11}把数据弹出到CPU,每弹出一个R0地址增加4字节,完成后R0指向xPSR寄存器,然后把R0的地址加载到PSP任务进程指针,这时PSP指向硬件自动恢复区起始点xPSR,就触发硬件自动恢复,最后再把R0清零,把R0的值赋值给basepri开启中断。
|
栈位置 |
寄存器 |
类型 |
作用说明 |
|
|---|---|---|---|---|
|
栈顶 |
R4 |
通用寄存器 |
任务内部变量(手动恢复区起始) |
|
|
↑ |
R5 |
通用寄存器 |
任务内部变量 |
|
|
↑ |
R6 |
通用寄存器 |
任务内部变量 |
|
|
↑ |
R7 |
通用寄存器 |
任务内部变量 |
|
|
↑ |
R8 |
通用寄存器 |
任务内部变量 |
|
|
↑ |
R9 |
通用寄存器 |
任务内部变量 |
|
|
↑ |
R10 |
通用寄存器 |
任务内部变量 |
|
|
↑ |
R11 |
通用寄存器 |
任务内部变量(手动恢复区结束) |
|
|
-------- |
---------- |
--------------------------- |
||
|
↑ |
xPSR |
特殊功能寄存器 |
程序状态寄存器 |
|
|
↑ |
R15(PC) |
特殊功能寄存器 |
程序计数器 |
|
|
↑ |
R14(LR) |
特殊功能寄存器 |
链接寄存器 |
|
|
↑ |
R12 |
通用寄存器 |
临时寄存器(自动恢复) |
|
|
↑ |
R3 |
通用寄存器 |
通用寄存器(自动恢复) |
|
|
↑ |
R2 |
通用寄存器 |
通用寄存器(自动恢复) |
|
|
↑ |
R1 |
通用寄存器 |
通用寄存器(自动恢复) |
|
|
栈底 |
R0 |
通用寄存器 |
任务参数寄存器 |
关键寄存器协同机制表
|
寄存器 |
作用 |
恢复方式 |
协同机制说明 |
|---|---|---|---|
|
R13(PSP) |
任务栈指针 |
软件设置 |
• 通过MSR PSP, R0设置 |
|
R14(LR) |
上下文恢复控制器 |
软件设置 |
• 存储0xFFFFFFFD魔数 |
|
R15(PC) |
执行流切换器 |
硬件自动恢复 |
• 恢复时立即跳转至任务代码 |
|
xPSR |
状态同步器 |
硬件自动恢复 |
• 恢复中断前的程序状态 |
• 压栈操作:地址递减(栈顶向低地址移动)
• 出栈操作:地址递增(栈顶向高地址移动)
• 切换流程:手动恢复(R4-R11)后,指针↑移动到xPSR,触发硬件自动↑恢复关键寄存器
FreeRTOS 学习笔记(持续更新)的更多相关文章
- 数据分析之Pandas和Numpy学习笔记(持续更新)<1>
pandas and numpy notebook 最近工作交接,整理电脑资料时看到了之前的基于Jupyter学习数据分析相关模块学习笔记.想着拿出来分享一下,可是Jupyter导出来h ...
- [读书]10g/11g编程艺术深入体现结构学习笔记(持续更新...)
持续更新...) 第8章 1.在过程性循环中提交更新容易产生ora-01555:snapshot too old错误.P257 (这种情况我觉得应该是在高并发的情况下才会产生) 假设的一个场景是系统一 ...
- Semantic ui 学习笔记 持续更新
这个semantic 更新版本好快~ 首先是代码的标识<code></code> 具体样式就是红框这样的 圈起来代码感觉不错 不过要在semantic.css里在加上如下样式~ ...
- Git学习笔记(持续更新)
1.强制同步为远程的代码 远程仓库回退了commit的情况下(第2条描述之情况),强制同步远程的代码到本地 #更新远程最新的所有代码,但是不merge或者rebase git fetch --all ...
- R语言的学习笔记 (持续更新.....)
1. DATE 处理 1.1 日期格式一个是as.Date(XXX) 和strptime(XXX),前者为Date格式,后者为POSIXlt格式 1.2 用法:as.Date(XXX,"%Y ...
- angularjs1学习笔记--持续更新
angularJS使用的MVC为何不属于二十三种设计模式之一? MVC被GoF (Gang of Four,四人组, <Design Patterns: Elements of Reusable ...
- ggplot2 学习笔记 (持续更新.....)
1. 目前有四种主题 theme_gray(), theme_bw() , theme_minimal(),theme_classic() 2. X轴设置刻度 scale_x_continuous(l ...
- # MongoDB学习笔记(持续更新)
启动mongo服务 sodo mongo 显示数据库(显示数据库名称和大小,单位GB) > show dbs admin (empty) local 0.078GB test 0.078GB t ...
- GOF 的23种JAVA常用设计模式 学习笔记 持续更新中。。。。
前言: 设计模式,前人总结下留给后人更好的设计程序,为我们的程序代码提供一种思想与认知,如何去更好的写出优雅的代码,23种设计模式,是时候需要掌握它了. 1.工厂模式 大白话:比如你需要一辆汽车,你无 ...
- BLE资料应用笔记 -- 持续更新
BLE资料应用笔记 -- 持续更新 BLE 应用笔记 小书匠 简而言之,蓝牙无处不在,易于使用,低耗能和低使用成本.'让我们'更深入地探索这些方面吧. 蓝牙无处不在-,您可以在几乎每一台电话.笔记本电 ...
随机推荐
- datasnap的restful服务器
说真话,这玩意真的简单好用.但你要控制好: 1.内存泄漏和异常处理好: 2.有没有发现,通过服务器对数据库进行读写时,在资源管理器中,如果是sql server,就会看到连接1433的连接一直挂在那里 ...
- 基于AST实现国际化文本提取
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:霜序 前言 在阅读本文之前,需要读者有一些 babel 的 ...
- 在 Ubuntu 上安装 Python 3.11、创建虚拟环境并设置 pip 阿里云源的主要命令
在 Ubuntu 上安装 Python 3.11.创建虚拟环境并设置 pip 阿里云源的主要命令流程如下: 安装 Python 3.11 sudo apt update sudo apt instal ...
- redis-dump教程
1.安装ruby 安装教程:https://www.cnblogs.com/wanyuan/p/11217397.html 安装完成后在DOS窗口输入ruby -v查看当前版本 2.安装redis-d ...
- 爬虫项目之爬取4K高清壁纸
爬虫项目之爬取4K高清壁纸 目标网址:4K壁纸高清图片_电脑桌面手机全面屏壁纸4K超清_高清壁纸4K全屏 - 壁纸汇 使用技术Selenium+Requests 下面是目标网页 思路:由于此网页是通过 ...
- [开源] .NetCore 使用 ORM FreeSql 访问 Sqlite
1.创建项目 我们以 console 类型项目试验 插入.删除.更新.查询 等功能,创建控制台项目,使用命令: dotnet new console dotnet add package FreeSq ...
- Nacos简介—2.Nacos的原理简介
大纲 1.Nacos集群模式的数据写入存储与读取问题 2.基于Distro协议在启动后的运行规则 3.基于Distro协议在处理服务实例注册时的写路由 4.由于写路由造成的数据分片以及随机读问题 5. ...
- MySQL 高可用集群搭建部署
MySQL 高可用集群搭建(GTID 模式 + 自动故障转移) 一.环境规划 角色 IP 地址 说明 主库 (Master) 192.168.1.100 运行 MySQL + Keepalived/M ...
- 36.3K star!开发者专属PPT神器,Markdown秒变炫酷幻灯片!
嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 Slidev 是专为开发者打造的现代化幻灯片制作工具,基于 Markdown + Vue 技 ...
- 2025AI应用全景图谱报告
提供AI咨询+AI项目陪跑服务,有需要回复1 加粉丝群获取报告 模型基础能力的提升加上自媒体的各种活跃,为AI应用提供了成长的温床,所以25年被称为了AI应用爆发的元年,这是有道理的,至少老板们在投钱 ...