2322 字
12 分钟
课程地图
这套课是什么
| 项 | 内容 |
|---|---|
| 课程 | FreeRTOS 入门与工程实践:由浅入深带你学习 FreeRTOS |
| 讲师 | 韦东山(百问网) |
| 开发板 | DShanMCU-F103,STM32F103 + HAL 库 |
| 工具 | STM32CubeMX、Keil(MDK-ARM)、ST-Link 下载器 |
| 地址 | BV1Jw411i7Fz |
| 规模 | 46 个分P / 约 748 分钟(12.5 小时) |
| 先修 | C 语言、STM32 GPIO/串口/中断、能独立建立一个 HAL 工程 |
| 定位 | 从内核机制讲到队列、信号量、互斥量、事件组,再用游戏机和车辆项目收束 |
前两集是后来追加的宣传视频;真正的课程正文从 p3 的硬件介绍开始。分P编号按当前 B 站页面计算。
这门课的特点
这门课不是“背 API”路线,而是先摆出一个能运行但存在缺陷的做法,再引出 FreeRTOS 的正确机制:
轮询忙等 → 浪费 CPU共享变量裸读写 → 竞态高优先级任务被低优先级任务拖住 → 优先级反转一个消费者从队列取走数据 → 其他任务收不到同一份数据后半程把这些问题放进两个连续项目里:
游戏机项目 红外接收、旋转编码器、按键 → 输入任务 游戏逻辑 → 处理任务 屏幕 / OLED → 显示任务 蜂鸣器 / 音乐 → 声音任务
车辆协同项目 遥控、姿态、里程计等输入 → 队列 / 队列集 中央逻辑 → 分发任务 电机、灯光、显示 → 信号量与事件组协调学习路线
第 1 阶段:先把工程跑起来 p3 ~ p8 硬件、模块、CubeMX、FreeRTOS 工程
第 2 阶段:理解任务为什么能切换 p9 ~ p17 多任务、ARM、栈与堆、源码、内存管理
第 3 阶段:学会任务管理 p18 ~ p26 创建、参数、栈、优先级、状态、调度、空闲任务、Delay
第 4 阶段:解决任务之间的问题 p27 ~ p40 同步、互斥、通信、队列、队列集、游戏机
第 5 阶段:用内核对象组织工程 p41 ~ p46 信号量、互斥量、优先级反转、事件组、车辆协同全目录与章节对照
| 集 | 时长(分) | 标题 | 对应章节 |
|---|---|---|---|
| p1 | 5.0 | 百问网所有课程_链接与学习路线 | 课程导览、硬件准备与工程搭建 |
| p2 | 6.0 | 韦东山1对1嵌入式私教课 | 课程导览、硬件准备与工程搭建 |
| p3 | 4.9 | [0-1] 课程配套硬件介绍 | 课程导览、硬件准备与工程搭建 |
| p4 | 20.7 | [1-1] 单片机工程师的最具性价比升级路线 RTOS | 课程导览、硬件准备与工程搭建 |
| p5 | 9.6 | [1-2] 讲师介绍 课程风格 项目展示 | 课程导览、硬件准备与工程搭建 |
| p6 | 9.6 | [2-1] 开发板使用 | 课程导览、硬件准备与工程搭建 |
| p7 | 5.6 | [2-2] 模块使用说明与 STM32CubeMX 配置 | 课程导览、硬件准备与工程搭建 |
| p8 | 20.3 | [2-3] 自己创建 FreeRTOS 工程 | 课程导览、硬件准备与工程搭建 |
| p9 | 13.0 | [3-1] 创建第 1 个多任务程序 | 第一个多任务程序与底层基础 |
| p10 | 15.0 | [3-2-1] ARM 架构简明教程:硬件架构与汇编指令 | 第一个多任务程序与底层基础 |
| p11 | 17.2 | [3-2-2] ARM 架构简明教程:汇编实例 | 第一个多任务程序与底层基础 |
| p12 | 21.9 | [3-3-1] 堆的概念 | 第一个多任务程序与底层基础 |
| p13 | 22.8 | [3-3-2] 栈的概念:函数调用 | 第一个多任务程序与底层基础 |
| p14 | 9.9 | [3-3-3] 栈的概念:局部变量 | 第一个多任务程序与底层基础 |
| p15 | 16.0 | [3-3-4] 栈的概念:RTOS 如何使用栈 | 第一个多任务程序与底层基础 |
| p16 | 11.6 | [4-1] FreeRTOS 源码概述 | FreeRTOS 源码与内存管理 |
| p17 | 11.5 | [4-2] 内存管理 | FreeRTOS 源码与内存管理 |
| p18 | 33.0 | [5-1-1] 创建任务:声光色影 | 任务的创建、参数与删除 |
| p19 | 10.0 | [5-1-2] 创建任务:估算栈大小 | 任务的创建、参数与删除 |
| p20 | 22.0 | [5-2] 创建任务:使用任务参数 | 任务的创建、参数与删除 |
| p21 | 14.1 | [5-3] 删除任务:用遥控器控制音乐 | 任务的创建、参数与删除 |
| p22 | 4.6 | [5-4] 优先级与阻塞:改善播放效果 | 优先级、任务状态与调度 |
| p23 | 17.3 | [5-5-1] 任务状态:改进播放控制 | 优先级、任务状态与调度 |
| p24 | 33.3 | [5-5-2] 任务管理与调度 | 优先级、任务状态与调度 |
| p25 | 14.4 | [5-5-3] 空闲任务 | 优先级、任务状态与调度 |
| p26 | 16.6 | [5-6] 两个 Delay 函数 | 优先级、任务状态与调度 |
| p27 | 15.8 | [6-1] 同步互斥与通信:有缺陷的同步示例 | 同步、互斥与通信总览 |
| p28 | 15.9 | [6-2] 同步互斥与通信:有缺陷的互斥示例 | 同步、互斥与通信总览 |
| p29 | 4.3 | [6-3] 同步互斥与通信:FreeRTOS 提供的方法 | 同步、互斥与通信总览 |
| p30 | 11.3 | [7] 游戏机项目说明 | 同步、互斥与通信总览 |
| p31 | 17.3 | [8-1-1] 数据传输的方法:环形 buffer | 队列、环形缓冲与多设备输入 |
| p32 | 16.7 | [8-1-2] 数据传输的方法:队列的本质 | 队列、环形缓冲与多设备输入 |
| p33 | 12.2 | [8-2-1] 队列实验:多设备玩游戏(思路) | 队列、环形缓冲与多设备输入 |
| p34 | 21.4 | [8-2-2] 队列实验:多设备玩游戏(红外改造) | 队列、环形缓冲与多设备输入 |
| p35 | 30.4 | [8-2-3] 队列实验:多设备玩游戏(旋转编码器) | 队列、环形缓冲与多设备输入 |
| p36 | 4.8 | [8-2-4] 勘误:解决旋转编码器不好用的问题 | 队列、环形缓冲与多设备输入 |
| p37 | 17.0 | [8-3-1] 队列集实验:改进程序框架(思路) | 队列集、姿态控制与赛车游戏 |
| p38 | 40.5 | [8-3-2] 队列集实验:改进程序框架(编程) | 队列集、姿态控制与赛车游戏 |
| p39 | 32.4 | [8-3-3] 队列集实验:增加姿态控制 | 队列集、姿态控制与赛车游戏 |
| p40 | 46.5 | [8-4] 队列实验:分发数据给多个任务(赛车游戏) | 队列集、姿态控制与赛车游戏 |
| p41 | 10.5 | [9-1] 信号量的本质 | 信号量、互斥量与优先级反转 |
| p42 | 16.2 | [9-2-1] 信号量实验:控制车辆运行 | 信号量、互斥量与优先级反转 |
| p43 | 9.9 | [9-2-2] 信号量实验:优先级反转 | 信号量、互斥量与优先级反转 |
| p44 | 17.7 | [9-3] 互斥量:领导临时提拔你(解决优先级反转) | 信号量、互斥量与优先级反转 |
| p45 | 8.2 | [10-1] 事件组的本质 | 事件组与车辆协同 |
| p46 | 13.7 | [10-2] 事件组实验:车辆协同 | 事件组与车辆协同 |
API 速查
| 目标 | 常用 API | 关键点 |
|---|---|---|
| 创建任务 | xTaskCreate / xTaskCreateStatic | 栈深度是 StackType_t 的数量,不是字节数 |
| 删除任务 | vTaskDelete | 动态任务被删除后,空闲任务回收它的 TCB 和栈 |
| 延时 | vTaskDelay / vTaskDelayUntil | 前者是“再等 N 个 tick”,后者是“固定周期” |
| 队列 | xQueueCreate / xQueueSend / xQueueReceive | 队列传递的是值的副本,不是原变量地址 |
| 队列集 | xQueueCreateSet / xQueueAddToSet / xQueueSelectFromSet | 先选队列,再只从被选中的队列取数据 |
| 二值信号量 | xSemaphoreCreateBinary | 适合“事件发生了一次” |
| 计数信号量 | xSemaphoreCreateCounting | 适合记录资源数量或事件次数 |
| 互斥量 | xSemaphoreCreateMutex | 有优先级继承,专用于互斥,不应在 ISR 中 Give |
| 事件组 | xEventGroupWaitBits / xEventGroupSetBits | 一个位表示一个事件,可等任意位或全部位 |
课程约定
| 约定 | 含义 |
|---|---|
| 优先级 | 数值越大,逻辑优先级越高;tskIDLE_PRIORITY 通常是 0 |
| tick | FreeRTOS 的时间单位,常用 1 tick = 1 ms |
| Block | 阻塞态任务不参与调度,超时或条件满足后回到就绪态 |
| 就绪 | 任务具备运行条件,只是尚未拿到 CPU |
| 挂起 | 任务被移出调度器,不会因为超时自动恢复 |
| ISR 版本 | 中断里只能调用带 FromISR 的接口,并正确传递 pxHigherPriorityTaskWoken |
怎么用这份笔记
每一章对应视频里的一段。建议的阅读顺序不是从 API 表开始,而是先看“为什么需要它”,再看 API 和实验,最后看“坑”。
动手时至少复现四个节点:
① 声光色影四个任务同时跑:确认调度器真的在切换② 用遥控器创建、暂停、删除音乐任务:走一遍任务的四种状态③ 把红外键值从写环形缓冲区改成写队列:确认生产者和消费者解耦④ 三个任务抢一张票:亲手制造优先级反转,再用互斥量解决坑
- 不要把所有逻辑塞进一个“大任务”。任务划分的依据是并发需求和阻塞点,不是函数数量。
- 不要用全局变量在任务之间传数据。普通读写没有原子性,也没有阻塞/唤醒语义。
vTaskDelay(100)不是“绝对延时到某个时刻”,它表示当前时刻之后再等 100 个 tick。- 队列满、队列空都有超时参数。传
0是不等待,传portMAX_DELAY才是永久等待。 xQueueSendFromISR不能调用普通任务版;忘记处理pxHigherPriorityTaskWoken会让高优先级任务晚一轮才运行。- 二值信号量和互斥量看起来都像“一把锁”,但二值信号量没有优先级继承,不能拿它代替互斥量。
- 事件组是“位”的集合,不是消息队列。事件组适合表达状态是否发生,不适合搬运大量数据。
请输入编辑凭据,只有站点所有者可以修改文章。