# 尚硅谷 FreeRTOS 笔记重构实现计划 > **目标**:将尚硅谷 FreeRTOS 教程 V1.0.3(17 章笔记 + 22 个代码项目 + 48 张图片)转换为 16 篇结构化 Markdown 笔记 > **目标目录**:`X-Knowledge-Base/raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/` > **设计规范**:`docs/superpowers/specs/2026-07-17-freertos-silicon-valley-ingest-design.md` > **工作流参考**:`docs/如何将他人文档整理为LLM-Wiki笔记.md` ## 前置准备 ### 需要删除的旧文件 - `X-Knowledge-Base/raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/assets/` 下的旧图片(全部删除后重建) ### 源文件路径 | 内容 | 路径 | |------|------| | 完整笔记 | `F:\Baidu\尚硅谷\尚硅谷嵌入式技术之FreeRTOS实时操作系统\01_笔记\尚硅谷嵌入式技术之FreeRTOS实时操作系统1.0.3.md` | | 原始图片 | `F:\Baidu\尚硅谷\尚硅谷嵌入式技术之FreeRTOS实时操作系统\01_笔记\images\media\`(48 张 PNG) | | 代码项目 | `F:\Baidu\尚硅谷\尚硅谷嵌入式技术之FreeRTOS实时操作系统\03_代码\代码\`(解压到临时目录) | | 原理图 | `F:\Baidu\尚硅谷\尚硅谷嵌入式技术之FreeRTOS实时操作系统\02_资料\02_按键案例\SCH_ZET6开发板_1_2024-07-01.pdf` | ### 提取代码项目到临时目录 ```powershell Expand-Archive -LiteralPath "F:\Baidu\尚硅谷\尚硅谷嵌入式技术之FreeRTOS实时操作系统\03_代码\代码.zip" -DestinationPath "C:\Users\Administrator\AppData\Local\Temp\opencode\freertos_code" -Force ``` --- ## 每篇笔记通用操作步骤 每个笔记的撰写流程如下: 1. **读取源笔记对应章节**:从 `尚硅谷嵌入式技术之FreeRTOS实时操作系统1.0.3.md` 读取相关章节内容 2. **读取配套代码项目**:读取对应项目的 `Core/Src/freertos_demo.c` 和 `Core/Inc/FreeRTOSConfig.h` 3. **筛选图片**:从 `images/media/` 中找出与该笔记相关的图片,筛选保留有用的,重命名后复制到 `assets/` 4. **撰写笔记**:按照设计文档中的模板撰写 Markdown 文件 5. **写入目标路径**:保存到 `X-Knowledge-Base/raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/` **图片视觉验证命令模板**(用于验证图片内容): ```powershell # 调用视觉 API 验证图片内容 function Test-Img { param($path, $question) $b64 = [Convert]::ToBase64String([IO.File]::ReadAllBytes($path)) $body = @{ model = "qwen3.5-9b-uncensored-nothink" messages = @(@{ role = "user"; content = @( @{ type = "text"; text = $question } @{ type = "image_url"; image_url = @{ url = "data:image/png;base64,$b64" } } )}) max_tokens = 60 } | ConvertTo-Json -Depth 10 $r = Invoke-RestMethod -Uri "https://api.1808366.xyz/v1/chat/completions" ... return $r.choices[0].message.content } ``` --- ## 文件产出清单 ### 目标:`X-Knowledge-Base/raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/` | 编号 | 文件名 | 来源章节 | 代码项目 | |------|--------|---------|---------| | 01 | `01-实时操作系统基础.md` | 第 1 章 | — | | 02 | `02-任务调度与状态管理.md` | 第 2 章 | — | | 03 | `03-FreeRTOS移植指南.md` | 第 3 章(移植 + 源码结构) | 00_HAL_Key | | 04 | `04-数据类型命名与配置详解.md` | 第 3 章(数据类型 + 命名 + 配置) | — | | 05 | `05-任务创建与删除.md` | 第 4 章 | 01, 02 | | 06 | `06-任务挂起与恢复.md` | 第 5 章 | 03 | | 07 | `07-中断管理与临界段.md` | 第 6 章 | 04 | | 08 | `08-时间片调度与延时管理.md` | 第 7 章 + 第 9 章 | 05, 08 | | 09 | `09-任务状态查询与运行时统计.md` | 第 8 章 | 06, 07 | | 10 | `10-消息队列.md` | 第 10 章 | 09 | | 11 | `11-信号量机制.md` | 第 11 章 | 10, 11, 12, 13 | | 12 | `12-队列集.md` | 第 12 章 | 14 | | 13 | `13-事件标志组.md` | 第 13 章 | 15 | | 14 | `14-任务通知.md` | 第 14 章 | 16, 17, 18 | | 15 | `15-软件定时器与Tickless低功耗.md` | 第 15 章 + 第 16 章 | 19, 20 | | 16 | `16-内存管理.md` | 第 17 章 | 21 | ### 附加产出 - `X-Knowledge-Base/raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/assets/` — 精选图片(15~25 张) - `wiki/source-freertos.md` — 重写资料摘要页 - `wiki/index.md` — 更新 FreeRTOS 章节 - `wiki/log.md` — 追加变更日志 --- ## 任务 1:准备图片 ### 1.1 复制全部图片到临时目录 ```powershell $srcImages = "F:\Baidu\尚硅谷\尚硅谷嵌入式技术之FreeRTOS实时操作系统\01_笔记\images\media" $tmp = "C:\Users\Administrator\AppData\Local\Temp\opencode\freertos_images" New-Item -ItemType Directory -Path $tmp -Force Copy-Item "$srcImages\*.png" $tmp ``` ### 1.2 识别并筛选图片 使用视觉 API 验证每张图片内容。48 张图片的预期内容分类: | 图片编号 | 预期内容 | 保留? | 建议文件名 | |---------|---------|--------|-----------| | image1 | 感知并发 vs 实际多任务图 | 保留 | multitasking_concurrent_vs_actual.png | | image2 | 抢占式调度示意图 | 保留 | scheduling_preemption.png | | image3 | 时间片轮转调度图 | 保留 | scheduling_timeslice.png | | image4 | 任务状态转换图(运行/就绪/阻塞/挂起) | 保留 | task_state_diagram.png | | image5 | 就绪列表位图 | 保留 | ready_list_bitmap.png | | image6 | 同优先级就绪列表 | 保留 | ready_list_same_priority.png | | image7 | 上下文切换步骤图(保存上下文) | 保留 | context_switch_save.png | | image8 | 上下文切换步骤图(恢复上下文) | 保留 | context_switch_restore.png | | image9 | FreeRTOS 官网下载页面截图 | 删除 | — | | image10 | GitHub 下载页面截图 | 删除 | — | | image11 | RVDS 文件夹结构截图 | 删除(可文字描述) | — | | image12 | heap 文件列表截图 | 删除(可文字描述) | — | | image13~image27 | Keil 工程添加文件步骤截图 | 全部删除(IDE 操作截图) | — | | image28~image29 | 寄存器版 Keil 添加截图 | 全部删除(IDE 操作截图) | — | | image30~image43 | 配置截图/CubeMX 截图 | 全部删除(IDE 操作截图) | — | | image44 | 队列结构图 | 保留 | queue_structure.png | | image45 | 事件标志组位结构图 | 保留 | event_group_bits.png | | image46 | 定时器状态切换图 | 保留 | timer_state_diagram.png | | image47 | STM32 低功耗模式图 | 保留 | stm32_low_power_modes.png | | image48 | 三种 heap 算法结构对比 | 保留 | heap_comparison.png | 筛选后预计保留约 **14 张**图片,其余 34 张删除。 ### 1.3 重命名并复制到 assets ```powershell $target = "X-Knowledge-Base/raw/Joplin/嵌入式+Linux/FreeRTOS学习笔记/assets" New-Item -ItemType Directory -Path $target -Force # 保留的图片按映射命名复制 Copy-Item "$tmp\image1.png" "$target\multitasking_concurrent_vs_actual.png" Copy-Item "$tmp\image2.png" "$target\scheduling_preemption.png" Copy-Item "$tmp\image3.png" "$target\scheduling_timeslice.png" Copy-Item "$tmp\image4.png" "$target\task_state_diagram.png" Copy-Item "$tmp\image5.png" "$target\ready_list_bitmap.png" Copy-Item "$tmp\image6.png" "$target\ready_list_same_priority.png" Copy-Item "$tmp\image7.png" "$target\context_switch_save.png" Copy-Item "$tmp\image8.png" "$target\context_switch_restore.png" Copy-Item "$tmp\image44.png" "$target\queue_structure.png" Copy-Item "$tmp\image45.png" "$target\event_group_bits.png" Copy-Item "$tmp\image46.png" "$target\timer_state_diagram.png" Copy-Item "$tmp\image47.png" "$target\stm32_low_power_modes.png" Copy-Item "$tmp\image48.png" "$target\heap_comparison.png" ``` --- ## 任务 2:笔记 01 — 实时操作系统基础.md **来源章节**:源笔记第 1 章(操作系统介绍 = 什么是裸机开发/什么是操作系统/通用OS/RTOS/FreeRTOS简介/发展历史/优势/特点) **代码项目**:无 **图片**:无 ### 撰写要点 - 解释裸机开发的局限性:所有代码在 while(1) 循环中顺序执行,实时性无法保证 - 对比通用 OS(Linux/Windows)与 RTOS(FreeRTOS/uCOS)的核心区别 - FreeRTOS 的七个特点:任务调度、任务通信、内存管理、定时器、社区、可移植性 - 用安全气囊 30ms 响应时间的例子说明"强大计算能力 ≠ 实时性" - FreeRTOS 发展历史:2003 Richard Barry → 2017 AWS 收购 - 开源免费 ≠ 免费用于商业产品 ### 模板参考 ```markdown --- tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — 第1章:操作系统介绍 + FreeRTOS简介" author: "尚硅谷研究院" date: 2026-07-17 created: 2026-07-17 --- # 实时操作系统基础 > **用生活理解**:如果把单片机比作一个厨师——裸机开发就像厨师必须自己记住每道菜的所有步骤,亲力亲为;RTOS 就像是给厨师配了一个帮厨团队——帮厨(操作系统)负责管理炒菜顺序、准备材料、分配时间,厨师(应用程序)只需专注于做菜本身。 ## 什么是裸机开发 ### 基本概念 ... ``` ### 速查表内容 无 API 速查表。本笔记以概念为主。 --- ## 任务 3:笔记 02 — 任务调度与状态管理.md **来源章节**:源笔记第 2 章(多任务处理/任务调度/任务状态/滴答/上下文切换/空闲任务) **代码项目**:无(概念篇) **图片**:image1~image8 ### 撰写要点 - 多任务处理:单核处理器的"并发假象"——任务间快速切换 - 调度策略三要素:抢占式(高优先级抢占低)、时间片轮询(同优先级轮流)、协程式(任务主动让出) - 四任务状态详解:运行、就绪、阻塞、挂起,以及转换关系 - 阻塞态 vs 挂起态的本质区别:阻塞态等待事件自动恢复,挂起态需手动恢复 - 滴答计数器:系统时基,SysTick 定时器产生 - 上下文切换流程: 1. TaskA 上下文保存到堆栈(R0-R12, SP, LR, PC, xPSR) 2. 选择下一个任务 3. TaskB 上下文从堆栈恢复到寄存器 4. PendSV 异常处理(最低优先级,避免影响其他 ISR) - 触发上下文切换的三种情况:Tick 中断、任务执行完毕、任务主动挂起 - 空闲任务:自动创建(最低优先级),三个作用(释放已删除任务内存、提供 CPU 空闲计数、进入低功耗模式) - 就绪列表:`pxReadyTasksLists[x]` 位图索引,32 位变量代表 0-31 优先级 ### 图片引用 ```markdown ![感知并发 vs 实际多任务](assets/multitasking_concurrent_vs_actual.png) ![抢占式调度](assets/scheduling_preemption.png) ![时间片轮转](assets/scheduling_timeslice.png) ![任务状态转换图](assets/task_state_diagram.png) ![就绪列表位图](assets/ready_list_bitmap.png) ![同优先级就绪列表](assets/ready_list_same_priority.png) ![上下文切换 — 保存](assets/context_switch_save.png) ![上下文切换 — 恢复](assets/context_switch_restore.png) ``` --- ## 任务 4:笔记 03 — FreeRTOS移植指南.md **来源章节**:源笔记第 3 章(源码结构 + HAL 库移植 + 寄存器移植) **代码项目**:`00_HAL_Key`(无 FreeRTOS 的纯 HAL 基础工程) ### 撰写要点 - 源码结构总览:FreeRTOS 内核(Source 7 个 .c + include + portable) - Source 目录 7 个核心文件:tasks.c、queue.c、timers.c、event_groups.c、croutine.c、list.c、stream_buffer.c - Portable 目录:不同编译器+内核的移植层,ARM_CM3 = port.c + portmacro.h - MemMang 5 种 heap:各有适用场景,初学用 heap_4 - HAL 库移植步骤(逐条说明): 1. 新建 FreeRTOS 文件夹 2. 拷贝 7 个 .c 到 source 3. 拷贝 portable 中 Keil/RVDS/MemMang 4. 拷贝 include 头文件 5. 拷贝 FreeRTOSConfig.h 并修改 6. Keil 添加两个 Group(Source + Portable),添加 .c 文件 7. 添加头文件路径 8. 修改 FreeRTOSConfig.h(xPortPendSVHandler、vPortSVCHandler、INCLUDE_xTaskGetSchedulerState) 9. 修改 stm32f1xx_it.c:注释 SVC_Handler 和 PendSV_Handler,添加 SysTick_Handler 回调 10. 解决 HAL+SysTick 冲突问题(SYS 选择其他时钟源,中断优先级设为 1) - 寄存器移植:步骤类似,在 main.c 添加 SysTick_Handler - 配置文件说明:INCLUDE_ 前缀(函数使能)、config 前缀(功能配置)、其他 ### 图片引用 使用文字描述代替 IDE 操作截图。可引用一张源码结构示意图(如有),但大多数 IDE 截图删除。 ### 速查表 移植检查清单: | 步骤 | 检查项 | 是否完成 | |------|--------|---------| | 1 | FreeRTOS/Source 包含 7 个 .c | □ | | 2 | FreeRTOS/portable/RVDS/ARM_CM3 有 port.c + portmacro.h | □ | | 3 | MemMang 包含 heap_4.c | □ | | 4 | FreeRTOS/include 全部头文件 | □ | | 5 | FreeRTOSConfig.h 已修改 | □ | | 6 | stm32f1xx_it.c 中 SVC/PendSV 已注释 | □ | | 7 | SysTick_Handler 已添加 xPortSysTickHandler 调用 | □ | | 8 | HAL 定时器源已切换(避免与 FreeRTOS 冲突) | □ | --- ## 任务 5:笔记 04 — 数据类型命名与配置详解.md **来源章节**:源笔记第 3 章后半(数据类型/命名规范/FreeRTOSConfig.h 配置说明) **代码项目**:无 ### 撰写要点 - 数据类型表: | 类型 | 描述 | 默认定义 | 配置决定 | |------|------|---------|---------| | TickType_t | 滴答计数值 | uint32_t | configUSE_16_BIT_TICKS | | BaseType_t | 最自然类型 | uint32_t(Cortex-M3) | 架构相关 | | StackType_t | 堆栈单位 | uint32_t | 架构相关 | - 命名前缀表: | 前缀 | 含义 | 示例 | |------|------|------| | v | 返回 void | vTaskDelete | | x | 返回 BaseType_t 或非 void 结构体 | xQueueCreate | | ux | 返回 UBaseType_t | uxTaskGetNumberOfTasks | | pv | 返回 void* | pvPortMalloc | | h | 句柄类型后缀 | TaskHandle_t | | pd | 协议定义(projdefs.h) | pdTRUE, pdPASS | - FreeRTOSConfig.h 全配置项参考(分组列出所有项,标注默认值和课程常用值) --- ## 任务 6:笔记 05 — 任务创建与删除.md **来源章节**:源笔记第 4 章(任务创建和删除) **代码项目**:01(动态创建删除)、02(静态创建删除) ### 撰写要点 - 任务 = 无限循环函数 + 堆栈 + TCB - 动态创建 vs 静态创建:`xTaskCreate` 自动分配 vs `xTaskCreateStatic` 预先分配 - 完整代码展示 01 项目的 `freertos_demo.c`(作为通用模板参考) - 静态创建需要 `vApplicationGetIdleTaskMemory` 和 `vApplicationGetTimerTaskMemory` 钩子 ### 代码提取(项目 01 — 动态创建删除) 从 `03_代码/01_动态创建任务和删除/Core/Src/freertos_demo.c` 提取: - `freertos_start()` 函数(创建 start_task + vTaskStartScheduler) - `start_task()` 函数(taskENTER_CRITICAL → 创建 3 个任务 → vTaskDelete(NULL) → taskEXIT_CRITICAL) - `task1()` LED 切换 + `task2()` LED 切换 + `task3()` 按键检测删除 task1 ### 代码提取(项目 02 — 静态创建删除) 从 `03_代码/02_静态创建任务和删除/Core/Src/freertos_demo.c` 提取: - 使用 `xTaskCreateStatic` 的差异点 - `vApplicationGetIdleTaskMemory` 和 `vApplicationGetTimerTaskMemory` 钩子实现 ### 关键配置 ```c // 静态分配需要开启 #define configSUPPORT_STATIC_ALLOCATION 1 // 软件定时器任务配置(静态创建需要) #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 4 #define configTIMER_QUEUE_LENGTH 5 #define configTIMER_TASK_STACK_DEPTH 256 ``` --- ## 任务 7:笔记 06 — 任务挂起与恢复.md **来源章节**:源笔记第 5 章(任务挂起与恢复) **代码项目**:03(任务挂起与恢复) ### 撰写要点 - 挂起态:任务暂停,不参与调度,需要手动恢复 - 单任务控制:`vTaskSuspend()` / `vTaskResume()` - 调度器控制:`vTaskSuspendAll()` / `xTaskResumeAll()` - 挂起 vs 阻塞 vs 删除深度对比 ### 代码提取(项目 03) 提取 `03_代码/03_任务挂起与恢复/Core/Src/freertos_demo.c`: - KEY1 = vTaskSuspend(task1) - KEY2 = vTaskResume(task1) - KEY3 = vTaskSuspendAll() - KEY4 = xTaskResumeAll() - vTaskList() 打印当前任务状态 --- ## 任务 8:笔记 07 — 中断管理与临界段.md **来源章节**:源笔记第 6 章(中断管理) **代码项目**:04(中断管理) ### 撰写要点 - FreeRTOS 中断管理策略:关中断(临界区)/ BASEPRI(屏蔽低于阈值的中断) - `taskENTER_CRITICAL()` / `taskEXIT_CRITICAL()` — 嵌套计数器 - `portDISABLE_INTERRUPTS()` / `portENABLE_INTERRUPTS()` - 中断安全 API 后缀:`FromISR` 版本(如 `xQueueSendFromISR`) - `configMAX_SYSCALL_INTERRUPT_PRIORITY`:FreeRTOS 可管理的中断优先级阈值 - 延迟中断处理(Deferred Interrupt Processing):ISR 中发信号通知任务处理 ### 代码提取(项目 04) 提取 `03_代码/04_中断管理/Core/Src/freertos_demo.c`: - KEY1 = portDISABLE_INTERRUPTS() - KEY2 = portENABLE_INTERRUPTS() ### 关键配置 ```c #define configKERNEL_INTERRUPT_PRIORITY (15 << 4) #define configMAX_SYSCALL_INTERRUPT_PRIORITY (5 << 4) ``` --- ## 任务 9:笔记 08 — 时间片调度与延时管理.md **来源章节**:源笔记第 7 章(时间片调度)+ 第 9 章(时间管理/延时函数) **代码项目**:05(时间片调度)、08(延时函数对比) ### 撰写要点 - 时间片调度:同优先级任务轮流执行一个 Tick 时间 - `configUSE_TIME_SLICING` 控制开关 - `vTaskDelay()` — 相对延时(从调用开始算,可能漂移) - `vTaskDelayUntil()` — 绝对延时(从上次唤醒算,固定周期) - `HAL_Delay()` vs `vTaskDelay()` 区别:前者忙等(不释放 CPU),后者阻塞(让出 CPU) ### 代码提取(项目 05) 提取 `03_代码/05_时间片调度/Core/Src/freertos_demo.c`: - 2 个同优先级任务进入临界区 → 打印计数 → HAL_Delay(10) → 退出临界区 - 演示时间片轮转效果 ### 代码提取(项目 08) 提取 `03_代码/08_时间延时函数/Core/Src/freertos_demo.c`: - task1 使用 vTaskDelay(500) 切换 LED1(漂移) - task2 使用 vTaskDelayUntil(&pxPreviousWakeTime, 500) 切换 LED2(固定周期) - 两者都额外使用 HAL_Delay(20) 模拟工作负载,观察漂移差异 ### 关键配置 ```c // 项目 05 将滴答频率降低到 50ms 方便观察时间片 #define configTICK_RATE_HZ 20 #define configUSE_TIME_SLICING 1 ``` --- ## 任务 10:笔记 09 — 任务状态查询与运行时统计.md **来源章节**:源笔记第 8 章(任务相关 API 函数) **代码项目**:06(任务状态查询)、07(运行时统计) ### 撰写要点 - 任务查询 API 全家桶: - 优先级:`uxTaskPriorityGet()` / `vTaskPrioritySet()` - 数量:`uxTaskGetNumberOfTasks()` - 系统状态:`uxTaskGetSystemState()` / `vTaskGetInfo()` - 句柄:`xTaskGetCurrentTaskHandle()` / `xTaskGetHandle()` - 栈余量:`uxTaskGetStackHighWaterMark()` - 状态:`eTaskGetState()` - 列表:`vTaskList()` - 运行时统计需要额外硬件定时器提供高精度时钟源 ### 代码提取(项目 06) 提取 `03_代码/06_任务状态查询/Core/Src/freertos_demo.c`: - task2 中一次性调用所有查询 API 并打印结果 ### 代码提取(项目 07) 提取 `03_代码/07_任务时间统计/Core/Src/freertos_demo.c`: - task2 周期打印 `vTaskGetRunTimeStats()` ### 关键配置 ```c #define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 #define configGENERATE_RUN_TIME_STATS 1 ``` --- ## 任务 11:笔记 10 — 消息队列.md **来源章节**:源笔记第 10 章(消息队列) **代码项目**:09(消息队列) ### 撰写要点 - 队列本质:内核对象,任务间传递数据的 FIFO 缓冲区 - 写时拷贝(Copy by Value)而非引用传递 - 队列内部结构:环形缓冲区 + 发送等待列表 + 接收等待列表 - 阻塞机制:队列入队/出队时可选阻塞时间 - `xQueueCreate()` 参数说明 ### 代码提取(项目 09) 提取 `03_代码/09_消息队列/Core/Src/freertos_demo.c`: - `queue1 = xQueueCreate(2, sizeof(uint8_t))` — 按键值队列 - `big_queue = xQueueCreate(1, sizeof(char*))` — 大字符串指针队列 - task1:KEY1/KEY2 → xQueueSend(queue1, &key, portMAX_DELAY) - task1:KEY3 → xQueueSend(big_queue, &big_data, portMAX_DELAY) - task2:xQueueReceive(queue1, &receive, portMAX_DELAY) - task3:xQueueReceive(big_queue, &receive_buff, portMAX_DELAY) ### 关键配置 ```c #define configQUEUE_REGISTRY_SIZE 8 ``` --- ## 任务 12:笔记 11 — 信号量机制.md **来源章节**:源笔记第 11 章(信号量 — 二值/计数/优先级翻转/互斥) **代码项目**:10(二值信号量)、11(计数信号量)、12(优先级反转)、13(互斥信号量) ### 撰写要点 - 信号量本质:基于队列实现,队列长度为 1(二值)或 N(计数) - 二值信号量:vSemaphoreCreateBinary → xSemaphoreGive → xSemaphoreTake - 计数信号量:xSemaphoreCreateCounting(max, init) → 每次 Give 计数值 +1 - 优先级反转:低优先级任务持有信号量 → 高优先级等待 → 中优先级抢断 → 高优先级被阻塞 - 类比"倒反天罡":低级任务反而"压"着高级任务 - 互斥信号量:内置优先级继承机制,解决优先级反转 - 当高优先级等待时,低优先级临时提升到高优先级(继承),完成后再降回原优先级 - 区别对比表: | 特性 | 二值信号量 | 计数信号量 | 互斥量 | |------|-----------|-----------|--------| | 初始值 | 0 | 用户指定 | 1 | | 最大值 | 1 | 用户指定 | 1 | | 优先级继承 | 无 | 无 | 有 | | 递归获取 | 否 | 否 | 可配置 | | 适用场景 | 事件通知 | 资源计数 | 互斥访问 | ### 代码提取(项目 10 — 二值信号量) 提取 `03_代码/10_二值信号量/Core/Src/freertos_demo.c`: - task1:KEY1 → xSemaphoreGive - task2:xSemaphoreTake(sem_handle, portMAX_DELAY) 阻塞等待 ### 代码提取(项目 12 — 优先级反转) 提取 `03_代码/12_优先级翻转/Core/Src/freertos_demo.c`: - task1(prio 2):持有信号量 → HAL_Delay(3000) - task2(prio 3):中等优先级持续运行 - task3(prio 4):尝试获取信号量 → 被 task1 持有,等待 ### 代码提取(项目 13 — 互斥信号量) 提取 `03_代码/13_互斥信号量/Core/Src/freertos_demo.c`: - 与项目 12 相同结构,但使用 `xSemaphoreCreateMutex()` 替代 `vSemaphoreCreateBinary()` ### 关键配置 ```c #define configUSE_COUNTING_SEMAPHORES 1 #define configUSE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 1 ``` --- ## 任务 13:笔记 12 — 队列集.md **来源章节**:源笔记第 12 章(队列集) **代码项目**:14(队列集) ### 撰写要点 - 队列集解决"同时等待多个队列/信号量"的问题 - 工作原理:将队列/信号量注册到集合 → 集合中任一成员有数据即通知 - 限制:队列集中的队列/信号量不能被独立删除 ### 代码提取(项目 14) 提取 `03_代码/14_队列集/Core/Src/freertos_demo.c`: - `xQueueCreateSet(queue_set_size)` — 集合大小 = 成员项数之和 - `xQueueAddToSet(queue1, queue_set_handle)` — 注册队列 - `xQueueAddToSet(sem_handle, queue_set_handle)` — 注册信号量 - `xQueueSelectFromSet(queue_set_handle, portMAX_DELAY)` — 等待任一成员 - KEY1 → 加入队列,KEY2 → 给出信号量 ### 关键配置 ```c #define configUSE_QUEUE_SETS 1 ``` --- ## 任务 14:笔记 13 — 事件标志组.md **来源章节**:源笔记第 13 章(事件标志组) **代码项目**:15(事件标志组) ### 撰写要点 - 事件标志组 = 24 位可用的位集合(RTOS 保留高 8 位) - `xEventGroupWaitBits()` 中的等待逻辑:AND(全部满足)vs OR(任一满足) - 清除模式:退出时自动清除(pdTRUE)或手动清除(pdFALSE) ### 代码提取(项目 15) 提取 `03_代码/15_事件标志组/Core/Src/freertos_demo.c`: - `event_group_handle = xEventGroupCreate()` - task1:KEY1 → `xEventGroupSetBits(event_group_handle, EVENTBIT_0)` - task1:KEY2 → `xEventGroupSetBits(event_group_handle, EVENTBIT_1)` - task2:`xEventGroupWaitBits(handle, BIT0|BIT1, pdTRUE, pdTRUE, portMAX_DELAY)` — 等两个位都置1 ### 图片引用 ```markdown ![事件标志组位结构](assets/event_group_bits.png) ``` --- ## 任务 15:笔记 14 — 任务通知.md **来源章节**:源笔记第 14 章(任务通知) **代码项目**:16(通知模拟信号量)、17(通知模拟消息队列)、18(通知模拟事件标志组) ### 撰写要点 - 任务通知:每个 TCB 内置 32 位通知值 + 8 位通知状态 - 三种模式: 1. 模拟信号量:`xTaskNotifyGive()` / `ulTaskNotifyTake()` — 计数值累加/递减 2. 模拟消息队列:`xTaskNotify(handle, value, eSetValueWithOverwrite)` — 覆写通知值 3. 模拟事件标志组:`xTaskNotify(handle, bits, eSetBits)` — 按位或置位 - 优势:比独立 IPC 快 ~45%(无额外内核对象创建) - 限制:只能一对一(一个任务通知另一个),不能一对多 ### 代码提取(项目 16 — 模拟信号量) 提取 `03_代码/16_任务通知模拟信号量/Core/Src/freertos_demo.c`: - task1:KEY1 → `xTaskNotifyGive(task2_handle)` - task2:`ulTaskNotifyTake(pdFALSE, portMAX_DELAY)` — 计数值递减 ### 代码提取(项目 17 — 模拟消息队列) 提取 `03_代码/17_任务通知模拟消息队列/Core/Src/freertos_demo.c`: - task1:KEY1/KEY2 → `xTaskNotify(task2_handle, key_value, eSetValueWithOverwrite)` - task2:`xTaskNotifyWait(ulBitsToClearOnEntry, ulBitsToClearOnExit, ¬ification_value, portMAX_DELAY)` ### 代码提取(项目 18 — 模拟事件标志组) 提取 `03_代码/18_任务通知模拟事件标志组/Core/Src/freertos_demo.c`: - task1:KEY1 → `xTaskNotify(task2_handle, EVENTBIT_0, eSetBits)` - task1:KEY2 → `xTaskNotify(task2_handle, EVENTBIT_1, eSetBits)` - task2:`xTaskNotifyWait(0, ULONG_MAX, ¬ify_val, portMAX_DELAY)` 并检查位 --- ## 任务 16:笔记 15 — 软件定时器与Tickless低功耗.md **来源章节**:源笔记第 15 章(软件定时器)+ 第 16 章(Tickless 低功耗模式) **代码项目**:19(软件定时器)、20(Tickless 低功耗) ### 软件定时器部分 - 软件定时器基于 Tick 计数(非硬件定时器) - 状态机:休眠 → 运行 → 暂停 - 一次性(AutoReload = pdFALSE)vs 周期性(AutoReload = pdTRUE) - 定时器命令队列:所有 API 通过队列向定时器服务任务发送命令 - 定时器服务任务:一个标准 FreeRTOS 任务,处理所有定时器回调 ### Tickless 部分 - Tickless 模式:空闲任务进入低功耗模式,暂停 SysTick 中断以省电 - `configUSE_TICKLESS_IDLE`:开启/关闭 - `configPRE_SLEEP_PROCESSING(x)` 和 `configPOST_SLEEP_PROCESSING(x)` — 用户在休眠前后执行的自定义操作 - 最小空闲时间:`configEXPECTED_IDLE_TIME_BEFORE_SLEEP`(太短则不休眠) ### 代码提取(项目 19 — 软件定时器) 提取 `03_代码/19_软件定时器/Core/Src/freertos_demo.c`: - `timer1 = xTimerCreate("timer1", 500, pdFALSE, NULL, timer1_callback)` — 一次性 - `timer2 = xTimerCreate("timer2", 1000, pdTRUE, NULL, timer2_callback)` — 周期性 - task1:KEY1 → `xTimerStart()`,KEY2 → `xTimerStop()` ### 代码提取(项目 20 — Tickless) 提取 `03_代码/20_低功耗模式/Core/Src/freertos_demo.c`: - 信号量驱动:task1 KEY1 → xSemaphoreGive → task2 接收 - `configPRE_SLEEP_PROCESSING(x)` → 休眠前关 GPIO 时钟 - `configPOST_SLEEP_PROCESSING(x)` → 唤醒后开 GPIO 时钟 ### 关键配置 ```c // 软件定时器 #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 4 #define configTIMER_QUEUE_LENGTH 5 #define configTIMER_TASK_STACK_DEPTH 256 // Tickless #define configUSE_TICKLESS_IDLE 1 ``` ### 图片引用 ```markdown ![定时器状态切换图](assets/timer_state_diagram.png) ![STM32 低功耗模式](assets/stm32_low_power_modes.png) ``` --- ## 任务 17:笔记 16 — 内存管理.md **来源章节**:源笔记第 17 章(内存管理 — heap_1~5) **代码项目**:21(内存管理) ### 撰写要点 - FreeRTOS 内存分配发生在:任务创建(堆栈+TCB)、队列创建、信号量创建、定时器创建 - 5 种 heap 算法对比: | 算法 | 分配策略 | 释放 | 碎片 | 适用场景 | |------|---------|------|------|---------| | heap_1 | 简单数组分配 | 不支持释放 | 无 | 不删除任务/队列 | | heap_2 | 最佳匹配链表 | 支持释放 | 有 | 随意分配释放 | | heap_3 | 包装 malloc/free | 标准 C 库 | 取决于 C 库 | 线程安全需要 | | heap_4 | 首序匹配 + 合并 | 合并相邻空闲块 | 优干 heap_2 | 默认推荐 | | heap_5 | 同 heap_4 | 跨非连续 RAM 区域 | 同 heap_4 | 多 RAM 区域 | - `pvPortMalloc()` / `vPortFree()` / `xPortGetFreeHeapSize()` ### 代码提取(项目 21) 提取 `03_代码/21_内存管理/Core/Src/freertos_demo.c`: - task1:KEY1 → `buff = pvPortMalloc(20)` → 打印 `xPortGetFreeHeapSize()` - task1:KEY2 → `vPortFree(buff)` → 打印堆大小 ### 图片引用 ```markdown ![三种 heap 算法结构对比](assets/heap_comparison.png) ``` --- ## 任务 18:更新 Wiki ### 18.1 重写 `wiki/source-freertos.md` - 笔记列表改为 16 篇新笔记映射 - 代码项目映射表更新 ### 18.2 更新 `wiki/index.md` - FreeRTOS 章节保持不变(wikilink 指向 wiki 页不受影响) - 确认原始笔记路径条目已更新到最新目录结构 ### 18.3 追加 `wiki/log.md` ```markdown ## 2026-07-17 - `lint`: 重构 FreeRTOS raw 笔记(16 篇) - 旧 11 篇笔记 → 新 16 篇笔记,按课程章节一对一/合并映射 - 代码来源:22 个正式 Keil 项目 - 图片精选:48 张 → 约 14 张(删除 IDE/Keil 配置截图) - 每篇标准结构:frontmatter + 生活类比 + 概念 + 实验代码 + API 速查表 + 避坑 - 遵循设计规范:`docs/superpowers/specs/2026-07-17-freertos-silicon-valley-ingest-design.md` 新笔记列表: - 01 ~ 16 覆盖:实时操作系统基础/任务调度与状态管理/移植指南/数据类型命名与配置/任务创建删除/挂起恢复/中断管理临界段/时间片调度延时管理/任务状态查询运行时统计/消息队列/信号量机制/队列集/事件标志组/任务通知/软件定时器与Tickless低功耗/内存管理 更新 `wiki/source-freertos.md`、`wiki/index.md`、`wiki/log.md` ``` --- ## 最终验证清单 - [ ] 16 篇笔记全部写入目标目录 - [ ] 每篇笔记 frontmatter 完整 - [ ] 每篇笔记有 `> **用生活理解**:` 类比 - [ ] 代码路径引用指向真实项目文件 - [ ] API 调用行有中文注释 - [ ] 图片路径引用(assets/xxx.png)有效 - [ ] 无冗余 IDE 操作截图保留 - [ ] `wiki/source-freertos.md` 已更新 - [ ] `wiki/index.md` 已更新 - [ ] `wiki/log.md` 已追加