【FreeRTOS】核心原理与实战速查手册

### 文章目录

  • [@toc](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [一、基础知识](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [1.1 堆 & 栈](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [1.2 句柄](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [1.3 钩子函数 HOOK](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [二、任务](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.1 创建一个任务-模板`first_rtos_app`](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.2 创建新任务](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.2.1 动态分配内存](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.2.2 源码](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.2.3 静态分配内存](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.3 删除任务](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.4 优先级](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.5 任务状态](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.6 任务的管理与调度(重要)](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.6.1 优先级链表数组](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.6.2 同优先级的调度机制](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.6.3 多优先级调度机制](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.7 空闲任务](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.7.1 任务如何退出?](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.7.2 要让空闲函数有机会执行](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [2.8 两个 Delay 函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [三、同步互斥与通信](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [四、队列](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.1 队列的本质](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.2 队列函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.2.1 创建](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.2.1.1 动态分配内存](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.2.1.2 静态分配内存](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.2.2 复位](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.2.3 删除](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.2.4 写队列 & 读队列](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.2.5 查询](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.3 队列集](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.3.1 创建队列集](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.3.2 把队列加入队列集](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [4.3.3 读取队列集](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [五、信号量 & 互斥量-mutex](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.1 信号量的本质](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.2 信号量跟队列的对比](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.3 信号量函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.3.1 创建](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.3.2 删除](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.3.3 give / take](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.4 优先级反转](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.5 互斥量_mutex--可解决优先级反转](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.6 互斥量函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.6.1 创建](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.6.2 其他函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.7 优先级继承](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.8 递归锁](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.8.1 死锁](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.8.2 自我死锁](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [5.8.3 递归锁 函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [六、事件组](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.1 事件组的概念 与 操作](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.1.1 事件组的概念](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.1.2 事件组的操作](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.2 事件组函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.2.1 创建](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.2.2 删除](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.2.3 设置事件](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.2.4 等待事件](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [6.2.5 同步点](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [七、任务通知 (Task Notification)](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [7.1 任务通知的特性](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [7.2 通知状态和通知值](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [7.2.1 通知状态](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [7.2.2 通知值](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [7.3 任务通知函数 的使用](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [7.3.1 简化版函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [八、软件定时器](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [8.1 工作原理](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [8.2 软件定时器的函数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [8.2.1 创建_动态/静态 分配内存](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [8.2.2 删除](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [8.2.3 启动/停止](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [8.2.4 复位](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [8.2.5 修改周期](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [8.2.6 定时器ID](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [九、中断管理](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [9.1 两套API函数_更高效](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [9.2 参数](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [9.3 中断的延迟处理](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [十、资源管理](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [10.1 屏蔽中断_任务/ISR](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [10.2 停止调度器](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [十一、调试与优化](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [11.1 调试](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [11.1.1 打印 & 断言](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [11.1.2 内存申请失败 / 栈溢出 Hook](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [11.2 优化](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [11.2.1 精细调整栈大小](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)
  • [11.2.2 打印所有任务的栈信息](#文章目录 @[toc] 一、基础知识 1.1 堆 & 栈 1.2 句柄 1.3 钩子函数 HOOK 二、任务 2.1 创建一个任务-模板first_rtos_app 2.2 创建新任务 2.2.1 动态分配内存 2.2.2 源码 2.2.3 静态分配内存 2.3 删除任务 2.4 优先级 2.5 任务状态 2.6 任务的管理与调度(重要) 2.6.1 优先级链表数组 2.6.2 同优先级的调度机制 2.6.3 多优先级调度机制 2.7 空闲任务 2.7.1 任务如何退出? 2.7.2 要让空闲函数有机会执行 2.8 两个 Delay 函数 三、同步互斥与通信 四、队列 4.1 队列的本质 4.2 队列函数 4.2.1 创建 4.2.1.1 动态分配内存 4.2.1.2 静态分配内存 4.2.2 复位 4.2.3 删除 4.2.4 写队列 & 读队列 4.2.5 查询 4.3 队列集 4.3.1 创建队列集 4.3.2 把队列加入队列集 4.3.3 读取队列集 五、信号量 & 互斥量-mutex 5.1 信号量的本质 5.2 信号量跟队列的对比 5.3 信号量函数 5.3.1 创建 5.3.2 删除 5.3.3 give / take 5.4 优先级反转 5.5 互斥量_mutex--可解决优先级反转 5.6 互斥量函数 5.6.1 创建 5.6.2 其他函数 5.7 优先级继承 5.8 递归锁 5.8.1 死锁 5.8.2 自我死锁 5.8.3 递归锁 函数 六、事件组 6.1 事件组的概念 与 操作 6.1.1 事件组的概念 6.1.2 事件组的操作 6.2 事件组函数 6.2.1 创建 6.2.2 删除 6.2.3 设置事件 6.2.4 等待事件 6.2.5 同步点 七、任务通知 (Task Notification) 7.1 任务通知的特性 7.2 通知状态和通知值 7.2.1 通知状态 7.2.2 通知值 7.3 任务通知函数 的使用 7.3.1 简化版函数 八、软件定时器 8.1 工作原理 8.2 软件定时器的函数 8.2.1 创建_动态/静态 分配内存 8.2.2 删除 8.2.3 启动/停止 8.2.4 复位 8.2.5 修改周期 8.2.6 定时器ID 九、中断管理 9.1 两套API函数_更高效 9.2 参数 9.3 中断的延迟处理 十、资源管理 10.1 屏蔽中断_任务/ISR 10.2 停止调度器 十一、调试与优化 11.1 调试 11.1.1 打印 & 断言 11.1.2 内存申请失败 / 栈溢出 Hook 11.2 优化 11.2.1 精细调整栈大小 11.2.2 打印所有任务的栈信息)

一、基础知识

API封装

1.1 堆 & 栈

1.Malloc和free函数源码其实都是链表,把空闲内存用链表串起来,包括头部空间8位链表 和开辟的空间大小。

2.一块内存空间,可以从中分配出小buffer,用完在把它放回去

1.也是一块内存空间,CPU和SP寄存器指向它,它可以用于函数调用返回地址(LR )、其他寄存器Reg 、局部变量、多任务系统里保存现场

2.每个任务都有自己的栈,在A任务切换到B任务时,A会保存自己的寄存器内容到自己的栈。

3.在从B任务恢复到A任务时,会从A的栈中读取寄存器到 cpu 中。特别是SP寄存器;

1.2 句柄

c 复制代码
// 调用示例
typedef void * TaskHandle_t;
TaskHandle_t xSoundTaskHandle = NULL;  //定义句柄 句柄本质上是一个数字编号(或指针) 可以把它通俗地理解为操作系统发给你的"会震动取餐器"
xTaskCreate(PlayMusic, "SoundTask", 128, NULL, osPriorityNormal+1, &xSoundTaskHandle);  // 点餐 取餐器的屏幕亮了 获得订单号 
/* ... */
if( xSoundTaskHandle != NULL )
{
    vTaskSuspend( xSoundTaskHandle ); // 正确暂停声音任务 暂停该订单号餐品的制作 
}

句柄就是操作系统发给你的一张"加密索引卡"。你拿着它,不用知道资源藏在内存的哪个犄角旮旯,也不用担心资源搬家,只需把它递给操作系统,操作系统就能凭这个卡号在内部表格里一秒查出资源在哪,并帮你执行操作。

1.3 钩子函数 HOOK

钩子函数就是系统提前留好的"插入口"。你按照规定写好函数,当特定事件发生时,系统会自动调用它,从而执行你自己的代码。

c 复制代码
// FreeRTOS 来说,可以先重点理解这几个
vApplicationIdleHook()
vApplicationTickHook()
vApplicationMallocFailedHook()
vApplicationStackOverflowHook()  
// 钩子函数不是主动调用的,而是系统在特定时机自动回调的。

二、任务

2.1 创建一个任务-模板first_rtos_app

txt 复制代码
01_freertos_template  //基准

配置STM32CubeMX 初始化代码 + 拷贝硬件模块驱动

01_freertos_template.7z 参考源码中,已集成模块驱动程序

powershell 复制代码
\DEV_MCU\DShanMCU_F103\5_程序源码\02_FreeRTOS程序\01_文档配套的源码\01_freertos_template.7z

默认创建任务

c 复制代码
\01_freertos_template\Core\Src\freertos.c 
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

默认任务入口

c 复制代码
/* 01_freertos_template\Core\Src\freertos.c*/
    
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  LCD_Init();
  LCD_Clear();
  
  for(;;)
  {
    //Led_Test();
    //LCD_Test();
	...
  }
  /* USER CODE END StartDefaultTask */
}

2.2 创建新任务

txt 复制代码
02_first_rtos_app  //创建新任务
2.2.1 动态分配内存

\02_first_rtos_app\Core\Src\freertos.c

c 复制代码
// API介绍
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
                        const char * const pcName, // 任务的名字
                        const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
                        void * const pvParameters, // 调用任务函数时传入的参数
                        UBaseType_t uxPriority, // 优先级
                        TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务
);

调用实例

c 复制代码
// 在freertos.c 中添加一下函数实现和函数调用
void MyTask(void *argument)
{
    while(1)
    {
        Led_Test();
    }
}

xTaskCreate(MyTask,"myfirsttask", 128, NULL, osPriorityNormal, NULL); //创建了一个新任务
2.2.2 源码
c 复制代码
// freertos.c
/* USER CODE BEGIN Header */
#include "driver_led.h"
#include "driver_lcd.h"
#include "driver_mpu6050.h"
#include "driver_timer.h"
#include "driver_ds18b20.h"
#include "driver_dht11.h"
#include "driver_active_buzzer.h"
#include "driver_passive_buzzer.h"
#include "driver_color_led.h"
#include "driver_ir_receiver.h"
#include "driver_ir_sender.h"
#include "driver_light_sensor.h"
#include "driver_ir_obstacle.h"
#include "driver_ultrasonic_sr04.h"
#include "driver_spiflash_w25q64.h"
#include "driver_rotary_encoder.h"
#include "driver_motor.h"
#include "driver_key.h"
#include "driver_uart.h"

#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

void MyTask(void *argument)
{
    while(1)
    {
        Led_Test();
    }
}

void StartDefaultTask(void *argument);

void MX_FREERTOS_Init(void); 

void MX_FREERTOS_Init(void) {
  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
  xTaskCreate(MyTask,"myfirsttask", 128, NULL, osPriorityNormal, NULL);
}

void StartDefaultTask(void *argument)
{
  LCD_Init();
  LCD_Clear();
  
  for(;;)
  {
    //Led_Test();
    LCD_Test();
	//MPU6050_Test(); 
	//DS18B20_Test();
	//DHT11_Test();
	//ActiveBuzzer_Test();
	//PassiveBuzzer_Test();
	//ColorLED_Test();
	//IRReceiver_Test();
	//IRSender_Test();
	//LightSensor_Test();
	//IRObstacle_Test();
	//SR04_Test();
	//W25Q64_Test();
	//RotaryEncoder_Test();
	//Motor_Test();
	//Key_Test();
	//UART_Test();
  }
  /* USER CODE END StartDefaultTask */
}
2.2.3 静态分配内存
c 复制代码
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
                                const char * const pcName, // 任务的名字
                                const uint32_t ulStackDepth, // 栈大小,单位为word,10表示40字节
                                void * const pvParameters, // 调用任务函数时传入的参数
                                UBaseType_t uxPriority, // 优先级
                                StackType_t * const puxStackBuffer, // 静态分配的栈,就是一个buffer
                                StaticTask_t * const pxTaskBuffer // 静态分配的任务结构体的指针, 用它来操作这个任务  //TCB结构体
);
/*	对于每个任务都会有一个TCB(Task Control Block)任务控制块 结构体

	任务 三要数
	* 函数:做何事;
	* 栈:每个任务都得有其独享的栈
	* 优先级*/

2.3 删除任务

txt 复制代码
07_delete_task  //删除任务_用遥控器控制音乐
c 复制代码
void vTaskDelete( TaskHandle_t xTaskToDelete );
参数 描述
xTaskToDelete 任务句柄,使用 xTaskCreate 创建任务时可以得到一个句柄。也可传入 NULL,这表示删除自己。

怎么删除任务?举个不好的例子

  • 自杀: vTaskDelete(NULL)
  • 被杀:别的任务执行 vTaskDelete(pvTaskCode) pvTaskCode 是自己的句柄
  • 杀人:执行 vTaskDelete(pvTaskCode)pvTaskCode 是别的任务的句柄

2.4 优先级

txt 复制代码
08_task_priority  //优先级_提高音乐播放优先级-vTaskDelay延时(不参与调度)(Blocking)
c 复制代码
// API介绍
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
                        const char * const pcName, // 任务的名字
                        const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
                        void * const pvParameters, // 调用任务函数时传入的参数
                        UBaseType_t uxPriority, // 优先级
                        TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务
);
xTaskCreate(PlayMusic, "SoundTask", 128, NULL, osPriorityNormal+1, &xSoundTaskHandle);

2.5 任务状态

txt 复制代码
09_task_suspend  //添加音乐暂停 / 恢复功能
四种状态 完整的任务状态转换图
Ready Running Blocked(等待某些 event) suspended(暂停)

Running ========== Blocking API function called :vTaskDelay() ==========> Blocked

函数 说明
vTaskSuspend ( 句柄 ) 暂停 suspend
vTaskResume ( 句柄 ) 恢复 resume

2.6 任务的管理与调度(重要)

2.6.1 优先级链表数组

优先级:链表管理:链表数组,数组序号就是优先级

c 复制代码
Readlist[N]  //表示 优先级为N的处于 Ready / Running 的任务;同一个优先级的任务以链表的形式连着; 
优先级链表数组
Blocked 后,任务被安排去 阻塞链表 DelayedTaskList suspend 后,任务被安排去 暂停链表 xSuspendedTask
2.6.2 同优先级的调度机制
同优先级的调度机制
  • 相同优先级的任务轮流运行
  • 最高优先级的任务先运行
    1. 高优先级的任务未执行完,低优先级的任务无法运行
    2. 高优先级任务 一旦就绪,马上运行 (立马抢占,即使还没到一个tick周期)
    3. 最高优先级的任务有多个,它们轮流运行
  • tick中断会做三件事情
    1. 累加计数 cnt++
    2. 判断DelayedTaskList 里 任务是否可恢复 ==> ReadyList
    3. 发起调度 ==> 遍历ReadyLists ==> 由高优先级往低优先级遍历 ==> 找到非空链表
2.6.3 多优先级调度机制
多优先级调度机制

暂停 suspend 任务 也是一样的道理,需要得到恢复 resume 指令才行

2.7 空闲任务

txt 复制代码
10_idle_task  //空闲任务

启动调度器vTaskStartScheduler(),会产生一个空闲任务,优先级为0Readylist[0] ;要么处于就绪 要么处于运行状态,永不阻塞;

txt 复制代码
空闲任务我一般用于指示小灯闪烁,来表示MCU正常运行
2.7.1 任务如何退出?
任务函数直接返回_ERROR
  1. 自杀:vTaskDelete(NULL)
  2. 他杀:vTaskDelete(handle) handle:需退出任务的 句柄
  3. A杀B 由A给B收尸;B自杀 由空闲任务收尸;
  4. 收尸:释放TCB结构体,释放栈;
2.7.2 要让空闲函数有机会执行

良好的编程习惯

  1. 使用事件来驱动任务,无事件就阻塞;
  2. 延时函数,不要使用死循环,尽可能使用阻塞函数 vTaskDelay()
  3. 高优先级的任务做完任务后,可以添加一个阻塞函数 vTaskDelay(),使当前任务不参与调度,让其他任务有更多的运行机会

2.8 两个 Delay 函数

txt 复制代码
11_task_delay  //两个不同的Delay函数-vTaskDelay_xTaskDelayUntil
函数 说明
vTaskDelay 至少等待指定个数的 Tick Interrupt 才能变为就绪状态
vTaskDelayUntil 等待到指定的绝对时刻,才能变为就绪态

函数定义

c 复制代码
void vTaskDelay( const TickType_t xTicksToDelay ); /* xTicksToDelay: 等待多少给Tick */

/* 
* 单位都是Tick Count
*/

BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
						  const TickType_t xTimeIncrement );
/*
* pxPreviousWakeTime: 上一次被唤醒的时间
* xTimeIncrement: 要阻塞到(pxPreviousWakeTime + xTimeIncrement)
*/

使用 vTaskDelay(n)时,进入、退出vTaskDelay的时间间隔至少是 n 个 Tick中;

可以使用 xTaskDelayUntil(&Pre, n) 来让任务周期性地运行;

图解

三、同步互斥与通信

C 复制代码
12_task_sync_exclusion  //同步&互斥通信

同步:两个任务之间有先后顺序,别死等,可以vTaskDelay 阻塞的方式,尽可能不占用太多 cpu 资源

互斥:某些资源一次只能一个任务使用,比如串口、I2C_OLED等;


四、队列

C 复制代码
14.1queue_game_multi_input_better  // 用旋转编码器和遥控器控制 游戏_队列-阻塞,少占CPU资源;  不够纯粹,红外遥控程序与按键耦合,后续用队列集优化

4.1 队列的本质

数据个数 互斥措施 阻塞-唤醒
全局变量 1
环形缓冲区 多个
队列 多个
c 复制代码
int r;   // 读数据
int w;   // 写数据
int num; // 数据个数 计数值

使用队列,最主要还是有阻塞效果,尽可能少的占用CPU资源;

队列中,数据的读写本质就是环形缓冲区,在这个基础上增加了互斥措施、阻塞-唤醒机制。

  • 如果这个队列不传输数据,只调整"数据个数",它就是 信号量(semaphore)

  • 如果信号量中,限定"数据个数"最大值为1,它就是 互斥量(mutex)

4.2 队列函数

4.2.1 创建
4.2.1.1 动态分配内存
c 复制代码
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, 
                            UBaseType_t uxItemSize ); 
参数 说明
uxQueueLength 队列长度,最多能存放多少个数据(item)
uxItemSize 每个数据(item)的大小:以字节为单位
返回值非 0: 成功,返回句柄,以后使用句柄来操作队列
NULL 失败,因为内存不足
4.2.1.2 静态分配内存
c 复制代码
QueueHandle_t xQueueCreateStatic( UBaseType_t uxQueueLength, 
                           		  UBaseType_t uxItemSize, 
                           		  uint8_t *pucQueueStorageBuffer, 
                           		  StaticQueue_t *pxQueueBuffer ); 
参数 说明
uxQueueLength 队列长度,最多能存放多少个数据(item)
uxItemSize 每个数据(item)的大小:以字节为单位
pucQueueStorageBuffer 如果 uxItemSize 非 0,pucQueueStorageBuffer 必须指向一个 uint8_t 数组, 此数组大小至少为 "uxQueueLength * uxItemSize"
pxQueueBuffer 必须执行一个 StaticQueue_t 结构体,用来保存队列的数据结构
返回值非 0: 成功,返回句柄,以后使用句柄来操作队列
NULL 失败,因为内存不足

示例代码

c 复制代码
// 示例代码 
 #define QUEUE_LENGTH 10 
 #define ITEM_SIZE sizeof( uint32_t ) 
  
 // xQueueBuffer 用来保存队列结构体 
 StaticQueue_t xQueueBuffer; 
  
 // ucQueueStorage 用来保存队列的数据 
 // 大小为:队列长度 * 数据大小 
 uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ]; 
  
 void vATask( void *pvParameters ) 
 { 
     QueueHandle_t xQueue1;
   	// 创建队列: 可以容纳 QUEUE_LENGTH 个数据,每个数据大小是 ITEM_SIZE 
  	xQueue1 = xQueueCreateStatic( QUEUE_LENGTH, 
 								  ITEM_SIZE, 
   								  ucQueueStorage, 
    						      &xQueueBuffer );  
 } 
4.2.2 复位

队列刚被创建时,里面没有数据;使用过程中可以调用 xQueueReset() 把队列恢复为初始状态,此函数原型为:

c 复制代码
/* pxQueue : 复位哪个队列; 
 * 返回值: pdPASS(必定成功) 
 */ 
BaseType_t xQueueReset( QueueHandle_t pxQueue);
4.2.3 删除

删除队列的函数为 vQueueDelete(),只能删除使用动态方法创建的队列,它会释放内存。原型如下:

c 复制代码
void vQueueDelete( QueueHandle_t xQueue ); 
4.2.4 写队列 & 读队列

可以把数据写到队列头部,也可以写到尾部,这些函数有两个版本:在任务中使用、在ISR 中使用。函数原型如下:

c 复制代码
/* 等同于xQueueSendToBack 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait */ 
BaseType_t xQueueSend( 
                                QueueHandle_t    xQueue, 
                                const void       *pvItemToQueue, 
                                TickType_t       xTicksToWait 
                            ); 
 
/* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait */ 
BaseType_t xQueueSendToBack( 
                                QueueHandle_t    xQueue, 
                                const void       *pvItemToQueue, 
                                TickType_t       xTicksToWait 
                            ); 
 
 
/* 往队列尾部写入数据,此函数可以在中断函数中使用,不可阻塞 */ 
BaseType_t xQueueSendToBackFromISR( 
                                      QueueHandle_t xQueue, 
                                      const void *pvItemToQueue, 
                                      BaseType_t *pxHigherPriorityTaskWoken    // 见第九章 中断管理
                                   ); 
 
/* 往队列头部写入数据,如果没有空间,阻塞时间为xTicksToWait */ 
BaseType_t xQueueSendToFront( 
                                QueueHandle_t    xQueue, 
                                const void       *pvItemToQueue, 
                                TickType_t       xTicksToWait 
                            ); 
 
/* 往队列头部写入数据,此函数可以在中断函数中使用,不可阻塞 */ 
BaseType_t xQueueSendToFrontFromISR( 
                                      QueueHandle_t xQueue, 
                                      const void *pvItemToQueue, 
                                      BaseType_t *pxHigherPriorityTaskWoken 
                                   ); 

这些函数用到的参数是类似的,统一说明如下:

参数 说明
xQueue 队列句柄,要写哪个队列
pvItemToQueue 数据指针,这个数据的值会被复制进队列,复制多大的数据?在创建队列时已经指定了数据大小
xTicksToWait 若队列满则无法写入新数据,可让任务进入阻塞状态,xTicksToWait表示阻塞的最大时间(Tick Count) 如果被设为 0,无法写入数据时函数会立刻返回;如果被设为 portMAX_DELAY,则会一直阻塞直到有空间可写
返回值 pdPASS:数据成功写入了队列 errQUEUE_FULL:写入失败,因为队列满了。

读队列

使用 xQueueReceive()函数读队列,读到一个数据后,队列中该数据会被移除。这个函数有两个版本:在任务中使用、在 ISR 中使用。函数原型如下:

c 复制代码
BaseType_t xQueueReceive( QueueHandle_t xQueue, 
                          void * const pvBuffer, 
                          TickType_t xTicksToWait ); 
 
BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, 
                                 void *pvBuffer, 
                                 BaseType_t *pxTaskWoken ); 
参数 说明
xQueue 队列句柄,要写哪个队列
pvBuffer bufer 指针,队列的数据会被复制到这个 buffer,复制多大的数据?在创建队列时已经指定了数据大小
xTicksToWait 若队列满则无法写入新数据,可让任务进入阻塞状态,xTicksToWait表示阻塞的最大时间(Tick Count) 如果被设为 0,无法读出数据时函数会立刻返回;如果被设为 portMAX_DELAY,则会一直阻塞直到有数据可写
返回值 pdPASS:从队列读出数据入 errQUEUE_EMPTY:读取失败,因为队列空了。
4.2.5 查询

可以查询队列中有多少个数据、有多少空余空间。函数原型如下:

c 复制代码
/* 返回队列中可用数据的个数 */ 
UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue ); 
 
/* 返回队列中可用空间的个数 */ 
UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue );

4.3 队列集

c 复制代码
15_queueset_game  // 使用**队列集**改善程序框架 解耦

假设有2个输入设备:红外遥控器、旋转编码器,它们的驱动程序应该专注于"产生硬件数据",不应该跟"业务有任何联系"。比如:红外遥控器驱动程序里,它只应该把键值记录下来、写入某个队列,它不应该把键值转换为游戏的控制键。在红外遥控器的驱动程序里,不应该有游戏相关的代码,这样,切换使用场景时,这个驱动程序还可以继续使用。

把红外遥控器的按键转换为游戏的控制键,应该在游戏的任务里实现。要支持多个输入设备时,我们需要实现一个"InputTask",它读取各个设备的队列,得到数据后再分别转换为游戏的控制键。

InputTask如何及时读取到多个队列的数据?要使用队列集。队列集的本质也是队列,只不过里面存放的是"队列句柄"。使用过程如下:

  • 创建队列A,它的长度是n1; 创建队列B,它的长度是n2
  • 创建队列集S,它的长度是"n1+n2"
  • 把队列A、B加入队列集S
  • 这样,写队列A的时候,会顺便把队列A的句柄写入队列集S; 写队列B的时候,会顺便把队列B的句柄写入队列集S
  • InputTask 先读取队列集S,它的返回值是一个队列句柄,这样就可以知道哪个队列有有数据了;然后InputTask再读取这个队列句柄得到数据。
4.3.1 创建队列集
c 复制代码
QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength )
参数 说明
uxQueueLength 队列集长度,最多能存放多少个数据(队列句柄)
返回值 非0:成功,返回句柄,以后使用句柄来操作队列NULL:失败,因为内存不足
4.3.2 把队列加入队列集
c 复制代码
BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,
                		  QueueSetHandle_t xQueueSet );
参数 说明
xQueueOrSemaphore 队列句柄,这个队列要加入队列集
xQueueSet 队列集句柄
返回值 pdTRUE:成功pdFALSE:失败
4.3.3 读取队列集
c 复制代码
QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,
                        				  TickType_t const xTicksToWait );
参数 说明
xQueueSet 队列集句柄
xTicksToWait 如果队列集空则无法读出数据,可以让任务进入阻塞状态,xTicksToWait表示阻塞的最大时间(Tick Count)。如果被设为0,无法读出数据时函数会立刻返回;如果被设为portMAX_DELAY,则会一直阻塞直到有数据可写
返回值 NULL:失败,队列句柄:成功

五、信号量 & 互斥量-mutex

V 复制代码
17_queue_car_dispatch   //赛车游戏_用遥控器123 控制
* 18_semaphore_not_use //不使用信号量,3俩车都可以进城
* 19_semaphore_count   //使用计数型信号量,同时允许多辆车进城
* 20_semaphore_binary  //使用二进制信号量,同时只允许一辆车进城

5.1 信号量的本质

信号量主要用于任务同步、事件通知或资源计数。信号量是特殊的队列,信号量是不涉及数据传输的队列,信号量仅传输状态

  • 示例
    • 进城 票数: cnt;
    • 领导放票:Give:cnt++、唤醒一个任务等待者;
    • 客户买票:task:cnt--、没票就阻塞 或者 回家;
信号量示例

5.2 信号量跟队列的对比

信号量跟队列的对比

5.3 信号量函数

使用信号量时,先创建、然后去添加资源、获得资源。使用句柄来表示一个信号量。

5.3.1 创建

使用信号量之前,要先创建,得到一个句柄;使用信号量时,要使用句柄来表明使用哪个信号量。 对于二进制信号量、计数型信号量,它们的创建函数不一样:

二进制信号量 计数型信号量
动态创建 xSemaphoreCreateBinary 计数值初始值为0 xSemaphoreCreateCounting
静态创建 xSemaphoreCreateBinaryStatic xSemaphoreCreateCountingStatic

创建二进制信号量的函数原型如下:

c 复制代码
/* 创建一个二进制信号量,返回它的句柄。
 * 此函数内部会分配信号量结构体 
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateBinary( void );

/* 创建一个二进制信号量,返回它的句柄。
 * 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );

创建计数型信号量的函数原型如下:

c 复制代码
/* 创建一个计数型信号量,返回它的句柄。
 * 此函数内部会分配信号量结构体 
 * uxMaxCount: 最大计数值
 * uxInitialCount: 初始计数值
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);

/* 创建一个计数型信号量,返回它的句柄。
 * 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针
 * uxMaxCount: 最大计数值
 * uxInitialCount: 初始计数值
 * pxSemaphoreBuffer: StaticSemaphore_t结构体指针
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, 
                                                 UBaseType_t uxInitialCount, 
                                                 StaticSemaphore_t *pxSemaphoreBuffer );
5.3.2 删除

对于动态创建的信号量,不再需要它们时,可以删除它们以回收内存。vSemaphoreDelete可以用来删除二进制信号量、计数型信号量,函数原型如下:

c 复制代码
/*
 * xSemaphore: 信号量句柄,你要删除哪个信号量
 */
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
5.3.3 give / take

二进制信号量、计数型信号量的give、take操作函数是一样的。这些函数也分为2个版本:给任务使用,给ISR使用。列表如下:

在任务中使用 在ISR中使用
give xSemaphoreGive xSemaphoreGiveFromISR
take xSemaphoreTake xSemaphoreTakeFromISR

xSemaphoreGive的函数原型如下:

c 复制代码
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
参数 说明
xSemaphore 信号量句柄,释放哪个信号量
返回值 pdTRUE表示成功, 如果二进制信号量的计数值已经是1,再次调用此函数则返回失败; 如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败

xSemaphoreGiveFromISR 的函数原型如下:

c 复制代码
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
                        		 BaseType_t *pxHigherPriorityTaskWoken );
参数 说明
xSemaphore 信号量句柄,释放哪个信号量
pxHigherPriorityTaskWoken 如果释放信号量导致更高优先级的任务变为了就绪态, 则*pxHigherPriorityTaskWoken = pdTRUE
返回值 pdTRUE表示成功, 如果二进制信号量的计数值已经是1,再次调用此函数则返回失败; 如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败

xSemaphoreTake 的函数原型如下:

c 复制代码
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
                   		  TickType_t xTicksToWait );
参数 说明
xSemaphore 信号量句柄,获取哪个信号量
xTicksToWait 如果无法马上获得信号量,阻塞一会: 0:不阻塞,马上返回 portMAX_DELAY: 一直阻塞直到成功 其他值: 阻塞的Tick个数,可以使用*pdMS_TO_TICKS()*来指定阻塞时间为若干ms
返回值 pdTRUE表示成功

xSemaphoreTakeFromISR的函数原型如下:

c 复制代码
BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,
                        		 BaseType_t *pxHigherPriorityTaskWoken );
参数 说明
xSemaphore 信号量句柄,获取哪个信号量
pxHigherPriorityTaskWoken 如果获取信号量导致更高优先级的任务变为了就绪态, 则 *pxHigherPriorityTaskWoken = pdTRUE
返回值 pdTRUE表示成功

5.4 优先级反转

c 复制代码
21_semaphore_priority_inversion   // 信号量反转

不反转的话,高优先级的任务先运行,低优先级的任务后运行; 反转之后,低优先级的先运行,高优先级的反而不能运行;

优先级反转 理论示例

5.5 互斥量_mutex--可解决优先级反转

互斥量主要用于保护共享资源,防止多个任务同时访问

c 复制代码
22_mutex_priority_inversion   //互斥量_解决优先级反转  //优先级继承
互斥量_解决优先级反转---优先级继承

5.6 互斥量函数

使用互斥量时,先创建、然后去获得、释放它。使用句柄来表示一个互斥量。

  • 要注意的是,互斥量不能在ISR中使用。

  • 要想使用互斥量,需要在配置文件FreeRTOSConfig.h中定义:

c 复制代码
#define configUSE_MUTEXES 1
5.6.1 创建

创建互斥量的函数有2种:动态分配内存,静态分配内存,函数原型如下:

c 复制代码
/* 创建一个互斥量,返回它的句柄。
 * 此函数内部会分配互斥量结构体 
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateMutex( void );

/* 创建一个互斥量,返回它的句柄。
 * 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer );
5.6.2 其他函数

各类操作函数,比如删除、give/take,跟一般是信号量是一样的。

c 复制代码
/* xSemaphore: 信号量句柄,你要删除哪个信号量, 互斥量也是一种信号量*/
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

/* 释放 */
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

/* 获得 */
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,  TickType_t xTicksToWait );

5.7 优先级继承

  • 假设持有互斥锁的是任务A,如果更高优先级的任务B也尝试获得这个锁
  • 任务B说:你既然持有宝剑,又不给我,那就继承我的愿望吧
  • 于是任务A就继承了任务B的优先级
  • 这就叫:优先级继承
  • 等任务A释放互斥锁时,它就恢复为原来的优先级
  • 互斥锁内部就实现了优先级的提升、恢复
c 复制代码
259 void car_game(void)
260 {
261	int x;
262	int i, j;
263	g_framebuffer = LCD_GetFrameBuffer(&g_xres, &g_yres, &g_bpp);
264	draw_init();
265	draw_end();
267	
268	//g_xSemTicks = xSemaphoreCreateCounting(1, 1);   // 信号量
269	g_xSemTicks = xSemaphoreCreateMutex();			 // 互斥量,解决 优先级反转的问题    // 后续任务A 需要 xSemaphoreTake 和 xSemaphoreGive

5.8 递归锁

5.8.1 死锁

假设有2个互斥量M1、M2,2个任务A、B:

  • A获得了互斥量M1、 B获得了互斥量M2
  • A还要获得互斥量M2才能运行,结果A阻塞、 B还要获得互斥量M1才能运行,结果B阻塞
  • A、B都阻塞,再无法释放它们持有的互斥量
  • 死锁发生!
5.8.2 自我死锁
  • 任务A获得了互斥锁M
  • 它调用一个库函数
  • 库函数要去获取同一个互斥锁M,于是它阻塞:任务A休眠,等待任务A来释放互斥锁!
  • 死锁发生!
5.8.3 递归锁 函数

怎么解决这类问题?可以使用递归锁(Recursive Mutexes),它的特性如下:

  • 任务A获得递归锁M后,它还可以多次去获得这个锁
  • "take"了N次,要"give"N次,这个锁才会被释放

递归锁的函数根一般互斥量的函数名不一样,参数类型一样,列表如下:

递归锁 一般互斥量
创建 xSemaphoreCreateRecursiveMutex xSemaphoreCreateMutex
获得 xSemaphoreTakeRecursive xSemaphoreTake
释放 xSemaphoreGiveRecursive xSemaphoreGive
c 复制代码
/* 创建一个递归锁,返回它的句柄。*
 * 此函数内部会分配互斥量结构体* 
 * 返回值: 返回句柄,非NULL表示成功*  */
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void );

*/ 释放 */
BaseType_t xSemaphoreGiveRecursive( SemaphoreHandle_t xSemaphore );

*/ 获得 */
BaseType_t xSemaphoreTakeRecursive( SemaphoreHandle_t xSemaphore,  TickType_t xTicksToWait );

六、事件组

c 复制代码
23_eventgroup_broadcast: car1到站后,广播通知car2,car3启动
24_eventgroup_or: car1或car2到站后,car3启动
25_eventgroup_and: car1和car2都到站后,car3启动

事件组(Event Group)是一种用多个二进制位(Bit)表示多个事件状态,实现任务等待、同步和事件通知的机制。

6.1 事件组的概念 与 操作

6.1.1 事件组的概念
事件组的概念
  • 先创建事件组
  • 任务C、D等待事件:
    • 等待什么事件?可以等待某一位、某些位中的任意一个,也可以等待多位。简单地说就是**"或"、"与"**的关系。
    • 得到事件时,要不要清除?可选择清除、不清除。
  • 任务A、B产生事件:设置事件组里的某一位 或 某些位
6.1.2 事件组的操作

事件组和队列、信号量等不太一样,主要集中在2个地方:

队列、信号量 事件组
唤醒谁? 事件发生时,只会唤醒一个任务 事件发生时,会唤醒所有符号条件的任务,简单地说它有"广播"的作用
是否清除事件? 是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了 被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件

6.2 事件组函数

6.2.1 创建

使用事件组之前,要先创建,得到一个句柄;使用事件组时,要使用句柄来表明使用哪个事件组。

c 复制代码
/* 创建一个事件组,返回它的句柄。
 * 此函数内部会分配事件组结构体 
 * 返回值: 返回句柄,非NULL表示成功 */
EventGroupHandle_t xEventGroupCreate( void );

/* 创建一个事件组,返回它的句柄。
 * 此函数无需动态分配内存,所以需要先有一个StaticEventGroup_t结构体,并传入它的指针
 * 返回值: 返回句柄,非NULL表示成功 */
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer );
6.2.2 删除
c 复制代码
/* xEventGroup: 事件组句柄,你要删除哪个事件组 */
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
6.2.3 设置事件

可以设置事件组的某个位、某些位,使用的函数有2个:

  • 在任务中使用**xEventGroupSetBits()**
  • 在ISR中使用**xEventGroupSetBitsFromISR()**

有一个或多个任务在等待事件,如果这些事件符合这些任务的期望,那么任务还会被唤醒。

c 复制代码
/* 设置事件组中的位
 * xEventGroup: 哪个事件组
 * uxBitsToSet: 设置哪些位? 
 *              如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1
 *              可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0
 * 返回值: 返回原来的事件值(没什么意义, 因为很可能已经被其他任务修改了) */
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
                                const EventBits_t uxBitsToSet );

/* 设置事件组中的位
 * xEventGroup: 哪个事件组
 * uxBitsToSet: 设置哪些位? 
 *              如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1
 *              可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0
 * pxHigherPriorityTaskWoken: 有没有导致更高优先级的任务进入就绪态? pdTRUE-有, pdFALSE-没有
 * 返回值: pdPASS-成功, pdFALSE-失败 */
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
								   const EventBits_t uxBitsToSet,
								   BaseType_t * pxHigherPriorityTaskWoken );
6.2.4 等待事件

使用**xEventGroupWaitBits**来等待事件,可以等待某一位、某些位中的任意一个,也可以等待多位;等到期望的事件后,还可以清除某些位。

c 复制代码
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
                                 const EventBits_t uxBitsToWaitFor,
                                 const BaseType_t xClearOnExit,
                                 const BaseType_t xWaitForAllBits,
                                 TickType_t xTicksToWait );

先引入一个概念:unblock condition。一个任务在等待事件发生时,它处于阻塞状态;当期望的时间发生时,这个状态就叫"unblock condition",非阻塞条件,或称为"非阻塞条件成立";当"非阻塞条件成立"后,该任务就可以变为就绪态。

参数 说明
xEventGroup 等待哪个事件组?
uxBitsToWaitFor 等待哪些位?哪些位要被测试?
xWaitForAllBits 怎么测试?是"AND"还是"OR"? pdTRUE: 等待的位,全部为1; pdFALSE: 等待的位,某一个为1即可
xClearOnExit 函数提出前是否要清除事件? pdTRUE: 清除uxBitsToWaitFor指定的位 pdFALSE: 不清除
xTicksToWait 如果期待的事件未发生,阻塞多久。 可以设置为0:判断后即刻返回; 可设置为portMAX_DELAY:一定等到成功才返回; 可以设置为期望的Tick Count,一般用*pdMS_TO_TICKS()*把ms转换为Tick Count
返回值 返回的是事件值, 如果期待的事件发生了,返回的是"非阻塞条件成立"时的事件值; 如果是超时退出,返回的是超时时刻的事件值。

举例如下:

事件组的值 uxBitsToWaitFor xWaitForAllBits 说明
0100 0101 pdTRUE 任务期望bit0,bit2都为1, 当前值只有bit2满足,任务进入阻塞态; 当事件组中bit0,bit2都为1时退出阻塞态
0100 0110 pdFALSE 任务期望bit0,bit2某一个为1, 当前值满足,所以任务成功退出
0100 0110 pdTRUE 任务期望bit1,bit2都为1, 当前值不满足,任务进入阻塞态; 当事件组中bit1,bit2都为1时退出阻塞态
6.2.5 同步点

使用 xEventGroupSync() 函数可以同步多个任务:

  • 可以设置某位、某些位,表示自己做了什么事
  • 可以等待某位、某些位,表示要等等其他任务
  • 期望的事件发生后, xEventGroupSync() 才会成功返回。
  • xEventGroupSync成功返回后,会清除事件

xEventGroupSync 函数原型如下:

c 复制代码
EventBits_t xEventGroupSync(    EventGroupHandle_t xEventGroup,
                                const EventBits_t uxBitsToSet,
                                const EventBits_t uxBitsToWaitFor,
                                TickType_t xTicksToWait );
参数 说明
xEventGroup 哪个事件组?
uxBitsToSet 要设置哪些事件?我完成了哪些事件? 比如0x05(二进制为0101)会导致事件组的bit0,bit2被设置为1
uxBitsToWaitFor 等待那个位、哪些位? 比如0x15(二级制10101),表示要等待bit0,bit2,bit4都为1
xTicksToWait 如果期待的事件未发生,阻塞多久。 可以设置为0:判断后即刻返回; 可设置为portMAX_DELAY:一定等到成功才返回; 可以设置为期望的Tick Count,一般用*pdMS_TO_TICKS()*把ms转换为Tick Count
返回值 返回的是事件值, 如果期待的事件发生了,返回的是"非阻塞条件成立"时的事件值; 如果是超时退出,返回的是超时时刻的事件值。

七、任务通知 (Task Notification)

c 复制代码
27_tasknotification_car_game   //任务通知实验_通知车辆运行

任务通知是一种轻量、高效、低内存的单任务通信机制,适用于"一个发送者 → 一个接收任务"的场景,但不支持数据缓存、广播和发送阻塞等待。

我们使用队列、信号量、事件组等等方法时,并不知道对方是谁。使用任务通知时,可以明确指定:通知哪个任务。

队列、信号量、事件组等等方法 任务通知

7.1 任务通知的特性

内容
优势 效率高 :比队列、信号量、事件组执行效率更高。 内存占用小:无需创建队列、信号量或事件组对象,直接使用任务自身的通知值。
限制 不能通知 ISR :只能通知任务,ISR 没有任务控制块;但 ISR 可以通知任务任务独享 :通知值存储在目标任务中,其他任务无法访问或共享。 无数据缓冲 :仅有一个通知值,不能像队列一样缓存多个数据。 不能广播 :一次通知只能发送给一个任务,不能像事件组一样同时通知多个任务。 发送方不能阻塞等待:通知失败立即返回,不能像队列发送那样阻塞等待目标接收。

任务通知是一种轻量、高效、低内存的单任务通信机制,适用于"一个发送者 → 一个接收任务"的场景,但不支持数据缓存、广播和发送阻塞等待。

7.2 通知状态和通知值

每个任务都有一个结构体:TCB(Task Control Block),里面有2个成员:通知状态通知值

c 复制代码
typedef struct tskTaskControlBlock
{
    ......
    /* configTASK_NOTIFICATION_ARRAY_ENTRIES = 1 */
    volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];   // 用来表示通知值
    volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];      // 用来表示通知状态
    ......
} tskTCB;
7.2.1 通知状态

通知状态有3种取值

c 复制代码
##define taskNOT_WAITING_NOTIFICATION              ( ( uint8_t ) 0 )  /* 也是初始状态 */ // 任务没有在等待通知
##define taskWAITING_NOTIFICATION                  ( ( uint8_t ) 1 )				  // 任务在等待通知
##define taskNOTIFICATION_RECEIVED                 ( ( uint8_t ) 2 )				  // 任务接收到了通知,也被称为pending(有数据了,待处理)
7.2.2 通知值

计数值、位(类似事件组)、任意数值

7.3 任务通知函数 的使用

使用任务通知,可以实现轻量级的队列(长度为1)、邮箱(覆盖的队列)、计数型信号量、二进制信号量、事件组。

类型 发送 接收 用途
简化版(常用) xTaskNotifyGive() vTaskNotifyGiveFromISR() ulTaskNotifyTake() 用于任务同步,可替代二值/计数信号量
专业版(了解) xTaskNotify() xTaskNotifyFromISR() xTaskNotifyWait() 功能更丰富,可实现事件组、长度为 1 的队列、邮箱等功能。

常用场景

场景 推荐 API
任务同步 xTaskNotifyGive() + ulTaskNotifyTake() ⭐⭐⭐⭐⭐
中断唤醒任务 vTaskNotifyGiveFromISR() ⭐⭐⭐⭐⭐
事件标志 xTaskNotify() + eSetBits
发送一个数据 xTaskNotify() + eSetValueWithoutOverwrite
保存最新数据 xTaskNotify() + eSetValueWithOverwrite
7.3.1 简化版函数

xTaskNotifyGive() 负责发通知,ulTaskNotifyTake() 负责等待通知,两者组合即可实现轻量级信号量。

c 复制代码
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
/*作用:
* 通知值 +1
* 将目标任务设为 Pending(有通知)*/
参数 说明
xTaskToNotify 任务句柄(创建任务时得到),给哪个任务发通知
返回值 必定返回 pdPASS
c 复制代码
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
参数 说明
xTaskHandle 任务句柄(创建任务时得到),给哪个任务发通知
pxHigherPriorityTaskWoken 被通知的任务,可能正处于阻塞状态。 此函数发出通知后,会把它从阻塞状态切换为就绪态。 如果被唤醒的任务的优先级,高于当前任务的优先级, 则 pxHigherPriorityTaskWoken 被设置为 pdTRUE, 这表示在中断返回之前要进行任务切换。
c 复制代码
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
参数 说明
xClearCountOnExit 函数返回前是否清零: pdTRUE:把通知值清零 pdFALSE:如果通知值大于0,则把通知值减一
xTicksToWait 任务进入阻塞态的超时时间,它在等待通知值大于0。 0:不等待,即刻返回; portMAX_DELAY:一直等待,直到通知值大于0; 其他值:Tick Count,可以用*pdMS_TO_TICKS()*把ms转换为Tick Count
返回值 函数返回之前,在清零或减一之前的通知值。 如果xTicksToWait非0,则返回值有2种情况: 1. 大于0:在超时前,通知值被增加了 2. 等于0:一直没有其他任务增加通知值,最后超时返回0

八、软件定时器

c 复制代码
28_timer_game_sound  //* 启动PWM发出声音,启动定时器   定时器的时间到后,停止PWM以静音

软件定时器就像"闹钟":设置一个时间,时间到后自动执行指定的回调函数,可用于延时执行或周期性执行任务;它基于系统 Tick,不占用额外的硬件定时器。

两种类型_一次性&自动加载

8.1 工作原理

任务调用定时器 API 时,通常只是把启动、停止等命令发送到 定时器命令队列 ,再由 FreeRTOS 的守护任务 Daemon Task处理命令和执行回调函数,而不是在 Tick 中断中直接执行。

定时器执行 过程

8.2 软件定时器的函数

定时器的状态转换图

冬眠(Dormant):冬眠态的定时器还可以通过句柄来访问它,但是它不再运行,它的回调函数不会被调用;

运行(Running、Active):运行态的定时器,当指定时间到达之后,它的回调函数会被调用

8.2.1 创建_动态/静态 分配内存
c 复制代码
/* 使用动态分配内存的方法创建定时器
 * pcTimerName:定时器名字, 用处不大, 尽在调试时用到
 * xTimerPeriodInTicks: 周期, 以Tick为单位
 * uxAutoReload: 类型, pdTRUE表示自动加载, pdFALSE表示一次性
 * pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器
 * pxCallbackFunction: 回调函数
 * 返回值: 成功则返回TimerHandle_t, 否则返回NULL
 */
TimerHandle_t xTimerCreate( const char * const pcTimerName, 
							const TickType_t xTimerPeriodInTicks,
							const UBaseType_t uxAutoReload,
							void * const pvTimerID,
							TimerCallbackFunction_t pxCallbackFunction );

/* 使用静态分配内存的方法创建定时器
 * pcTimerName:定时器名字, 用处不大, 尽在调试时用到
 * xTimerPeriodInTicks: 周期, 以Tick为单位
 * uxAutoReload: 类型, pdTRUE 表示自动加载, pdFALSE 表示一次性
 * pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器
 * pxCallbackFunction: 回调函数
 * pxTimerBuffer: 传入一个StaticTimer_t结构体, 将在上面构造定时器
 * 返回值: 成功则返回TimerHandle_t, 否则返回NULL
 */
TimerHandle_t xTimerCreateStatic(const char * const pcTimerName,
                                 TickType_t xTimerPeriodInTicks,
                                 UBaseType_t uxAutoReload,
                                 void * pvTimerID,
                                 TimerCallbackFunction_t pxCallbackFunction,
                                 StaticTimer_t *pxTimerBuffer );

/* 回调函数的类型是: */
void ATimerCallback( TimerHandle_t xTimer );
typedef void (* TimerCallbackFunction_t)( TimerHandle_t xTimer );
8.2.2 删除
c 复制代码
/* 删除定时器
 * xTimer: 要删除哪个定时器
 * xTicksToWait: 超时时间
 * 返回值: pdFAIL表示"删除命令"在xTicksToWait个Tick内无法写入队列
 *        pdPASS表示成功
*/
BaseType_t xTimerDelete( TimerHandle_t xTimer, TickType_t xTicksToWait );
8.2.3 启动/停止

启动定时器就是设置它的状态为运行态(Running、Active) 。 停止定时器就是设置它的状态为冬眠(Dormant),让它不能运行。

c 复制代码
/* 启动定时器
 * xTimer: 哪个定时器
 * xTicksToWait: 超时时间
 * 返回值: pdFAIL表示"启动命令"在xTicksToWait个Tick内无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );

/* 启动定时器(ISR版本)
 * xTimer: 哪个定时器
 * pxHigherPriorityTaskWoken: 向队列发出命令使得守护任务被唤醒,
 *                            如果守护任务的优先级比当前任务的高,
 *                            则"*pxHigherPriorityTaskWoken = pdTRUE",
 *                            表示需要进行任务调度
 * 返回值: pdFAIL表示"启动命令"无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerStartFromISR( TimerHandle_t xTimer,
                               BaseType_t *pxHigherPriorityTaskWoken );

/* 停止定时器
 * xTimer: 哪个定时器
 * xTicksToWait: 超时时间
 * 返回值: pdFAIL表示"停止命令"在xTicksToWait个Tick内无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );

/* 停止定时器(ISR版本)
 * xTimer: 哪个定时器
 * pxHigherPriorityTaskWoken: 向队列发出命令使得守护任务被唤醒,
 *                            如果守护任务的优先级比当前任务的高,
 *                            则"*pxHigherPriorityTaskWoken = pdTRUE",
 *                            表示需要进行任务调度
 * 返回值: pdFAIL表示"停止命令"无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerStopFromISR( TimerHandle_t xTimer,
                              BaseType_t *pxHigherPriorityTaskWoken );
8.2.4 复位

如果定时器已经处于运行态,使用 xTimerReset() 函数就相当于重新确定超时时间

c 复制代码
/* 复位定时器
 * xTimer: 哪个定时器
 * xTicksToWait: 超时时间
 * 返回值: pdFAIL表示"复位命令"在xTicksToWait个Tick内无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );

/* 复位定时器(ISR版本)
 * xTimer: 哪个定时器
 * pxHigherPriorityTaskWoken: 向队列发出命令使得守护任务被唤醒,
 *                            如果守护任务的优先级比当前任务的高,
 *                            则"*pxHigherPriorityTaskWoken = pdTRUE",
 *                            表示需要进行任务调度
 * 返回值: pdFAIL表示"停止命令"无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerResetFromISR(   TimerHandle_t xTimer,
                                 BaseType_t *pxHigherPriorityTaskWoken );
8.2.5 修改周期

使用 xTimerChangePeriod() 函数,处理能修改它的周期外,还可以让定时器的状态从冬眠态转换为运行态。会使用新的周期重新计算它的超时时间

c 复制代码
/* 修改定时器的周期
 * xTimer: 哪个定时器
 * xNewPeriod: 新周期
 * xTicksToWait: 超时时间, 命令写入队列的超时时间 
 * 返回值: pdFAIL表示"修改周期命令"在xTicksToWait个Tick内无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerChangePeriod(   TimerHandle_t xTimer,
                                 TickType_t xNewPeriod,
                                 TickType_t xTicksToWait );

/* 修改定时器的周期
 * xTimer: 哪个定时器
 * xNewPeriod: 新周期
 * pxHigherPriorityTaskWoken: 向队列发出命令使得守护任务被唤醒,
 *                            如果守护任务的优先级比当前任务的高,
 *                            则"*pxHigherPriorityTaskWoken = pdTRUE",
 *                            表示需要进行任务调度
 * 返回值: pdFAIL表示"修改周期命令"在xTicksToWait个Tick内无法写入队列
 *        pdPASS表示成功
 */
BaseType_t xTimerChangePeriodFromISR( TimerHandle_t xTimer,
                                      TickType_t xNewPeriod,
                                      BaseType_t *pxHigherPriorityTaskWoken );
8.2.6 定时器ID
定时器的结构体

怎么使用定时器ID,完全由程序来决定:

  • 可以用来标记定时器,表示自己是什么定时器
  • 可以用来保存参数,给回调函数使用

它的初始值在创建定时器时由 xTimerCreate() 这类函数传入,后续可以使用这些函数来操作:

  • 更新ID:使用 vTimerSetTimerID() 函数
  • 查询ID:查询 pvTimerGetTimerID() 函数

这两个函数不涉及命令队列,它们是直接操作定时器结构体。

c 复制代码
/* 获得定时器的ID
 * xTimer: 哪个定时器
 * 返回值: 定时器的ID*/
void *pvTimerGetTimerID( TimerHandle_t xTimer );

/* 设置定时器的ID
 * xTimer: 哪个定时器
 * pvNewID: 新ID
 * 返回值: 无*/
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID );

九、中断管理

c 复制代码
29_fromisr_game   // 主要看DshanMCU-F103\driver_ir_receiver.c 

中断函数 要尽快执行,不能进入阻塞状态。

ISR的优先级高于任务:即使是优先级最低的中断,它的优先级也高于任务。任务只有在没有中断的情况下,才能执行。

9.1 两套API函数_更高效

类型 在任务中 在ISR中
队列(queue) xQueueSendToBack xQueueSendToBackFromISR
xQueueSendToFront xQueueSendToFrontFromISR
xQueueReceive xQueueReceiveFromISR
xQueueOverwrite xQueueOverwriteFromISR
xQueuePeek xQueuePeekFromISR
信号量(semaphore) xSemaphoreGive xSemaphoreGiveFromISR
xSemaphoreTake xSemaphoreTakeFromISR
事件组(event group) xEventGroupSetBits xEventGroupSetBitsFromISR
xEventGroupGetBits xEventGroupGetBitsFromISR
任务通知(task notification) xTaskNotifyGive vTaskNotifyGiveFromISR
xTaskNotify xTaskNotifyFromISR
软件定时器(software timer) xTimerStart xTimerStartFromISR
xTimerStop xTimerStopFromISR
xTimerReset xTimerResetFromISR
xTimerChangePeriod xTimerChangePeriodFromISR

9.2 参数

c 复制代码
/* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait */ 
BaseType_t xQueueSendToBack( QueueHandle_t xQueue, 
                             const void *pvItemToQueue, 
                             TickType_t xTicksToWait ); 

/* 
* 往队列尾部写入数据,此函数可以在中断函数中使用,不可阻塞 
* xQueue:队列句柄,要写哪个队列
* pvItemToQueue:数据指针,这个数据的值会被复制进队列,复制多大的数据?在创建队列时已经指定了数据大小
 * pxHigherPriorityTaskWoken:
 	* pdTRUE:唤醒了更高优先级任务,ISR退出前需要请求任务切换
 	* pdFALSE:未唤醒更高优先级任务,无需请求任务切换
BaseType_t xQueueSendToBackFromISR( QueueHandle_t xQueue,
                                    const void *pvItemToQueue,
                                    BaseType_t *pxHigherPriorityTaskWoken );

/* 用法示例 *//* 使得如果被唤醒的任务优先级更高,不会即刻调度,只是记录下来表示*/  //见9.3
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendToBackFromISR(xQueue, pvItemToQueue, &xHigherPriorityTaskWoken);

if (xHigherPriorityTaskWoken == pdTRUE)
{
    /* 任务切换 */    
}
xQueueSendToBack xQueueSendToBackFromISR
参数不同 xTicksToWait: 队列满的话阻塞多久 没有xTicksToWait
唤醒等待的任务 写队列后,会唤醒等待数据的任务 写队列后,会唤醒等待数据的任务
调度 如果被唤醒的任务优先级更高,即刻调度 如果被唤醒的任务优先级更高,不会调度 只是记录下来表示:
阻塞 如果队列满,可以阻塞 +如果队列满,不能阻塞

9.3 中断的延迟处理

任务 A 运行时,中断通过 xQueueSendFromISR() 唤醒了更高优先级任务 B,但由于没有通过 pxHigherPriorityTaskWokenportYIELD_FROM_ISR() 请求任务切换,B 要等到下一次系统节拍中断才开始运行。

中断唤醒高优先级任务后未及时切换导致调度延迟

使用 pxHigherPriorityTaskWokenportYIELD_FROM_ISR() 后,被唤醒的高优先级 Task2 会在中断退出后马上运行,而不是等到下一个系统节拍

中断的延迟处理机制
c 复制代码
任务A运行 → 中断发生 → ISR唤醒B → ISR退出时切换到B → B处理完并阻塞 → A继续运行

十、资源管理

在前面讲解互斥量时,引入过临界资源的概念。在前面课程里,已经实现了临界资源的互斥访问。

要独占式地访问临界资源,有3种方法:

  • 公平竞争:比如使用互斥量,谁先获得互斥量谁就访问临界资源,这部分内容前面讲过。
  • 谁要跟我抢,我就灭掉谁:
    • 中断要跟我抢?我屏蔽中断
    • 其他任务要跟我抢?我禁止调度器,不运行任务切换

10.1 屏蔽中断_任务/ISR

任务中使用 ISR中使用
taskENTER_CRITICA( ) / taskEXIT_CRITICAL( ) taskENTER_CRITICAL_FROM_ISR( ) / taskEXIT_CRITICAL_FROM_ISR( )
  • 低优先级的中断被屏蔽了:优先级 <= configMAX_SYSCALL_INTERRUPT_PRIORITY

  • 高优先级的中断可以产生:优先级 > configMAX_SYSCALL_INTERRUPT_PRIORITY

  • 任务调度依赖于中断、依赖于API函数,所以:这两段代码之间,不会有任务调度产生

在任务中屏蔽中断

c 复制代码
/* 在任务中,当前时刻中断是使能的
 * 执行这句代码后,屏蔽中断
 */
taskENTER_CRITICAL();

/* 访问临界资源 */

/* 重新使能中断 */
taskEXIT_CRITICAL();

在ISR中屏蔽中断

c 复制代码
void vAnInterruptServiceRoutine( void )
{
    /* 用来记录当前中断是否使能 */
    UBaseType_t uxSavedInterruptStatus;
    
    /* 在ISR中,当前时刻中断可能是使能的,也可能是禁止的
     * 所以要记录当前状态, 后面要恢复为原先的状态
     * 执行这句代码后,屏蔽中断
     */
    uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
    
    /* 访问临界资源 */

    /* 恢复中断状态 */
    taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
    /* 现在,当前ISR可以被更高优先级的中断打断了 */
}

10.2 停止调度器

如果有别的任务来跟你竞争临界资源,你可以把中断关掉:这当然可以禁止别的任务运行,但是这代价太大了。它会影响到中断的处理。

如果只是禁止别的任务来跟你竞争,不需要关中断,暂停调度器就可以了:在这期间,中断还是可以发生、处理。

c 复制代码
/* 暂停调度器 */
void vTaskSuspendAll( void );

/* 恢复调度器
 * 返回值: pdTRUE表示在暂定期间有更高优先级的任务就绪了
 *        可以不理会这个返回值
 */
BaseType_t xTaskResumeAll( void );

这套 vTaskSuspendAll() / xTaskResumeAll() 函数,是可以递归使用的,它的内部会记录嵌套的深度uxSchedulerSuspended。只有嵌套深度变为 0 时,调用 xTaskResumeAll() 才会真正恢复调度器。在此期间,中断始终处于使能状态,可以正常响应和处理。


十一、调试与优化

c 复制代码
31_stack_state         // 精细调整栈大小_单个任务                               
32_all_stack_state     // 打印所有任务的栈信息_钩子函数`vApplicationIdleHook()`中 
33_cpu_usage           // 找到大量消耗CPU资源的任务                               

11.1 调试

调试方法 说明
printf 查看程序运行信息
configASSERT (断言) 发现非法参数和严重错误
Trace 跟踪任务、队列和内核运行过程
Malloc Hook 检测堆内存申请失败
`Stack Overflow Hook (栈溢出Hook函数) 检测任务栈溢出
11.1.1 打印 & 断言

打印

在工程中实现下面的函数后,即可使用 printf:主要用于输出变量、程序状态和错误信息。

复制代码
int fputc(int ch, FILE *f);

断言 _configASSERT

断言用于检查某个条件是否成立:

c 复制代码
#define configASSERT(x)  \
	if (!x) \
	{
		printf("%s %s %d\r\n", __FILE__, __FUNCTION__, __LINE__); \
        while(1); \
 	}

x 为假时,说明程序发生严重错误,打印出错位置并停止运行。常用于检查:句柄是否为空、参数是否合法、中断优先级是否符合要求

Trace宏

FreeRTOS在任务切换、队列操作、任务阻塞等关键位置预留了很多 trace 宏。默认情况下这些宏为空,不占用程序空间和运行时间;调试时可以重新定义,用来:打印运行信息、记录事件次数、分析任务切换、统计队列收发情况;

常见Trace宏:

Trace宏 触发时机
traceTASK_SWITCHED_IN() 任务切入运行
traceTASK_SWITCHED_OUT() 任务被切出
traceTASK_DELAY() 任务调用 vTaskDelay() 进入阻塞
traceQUEUE_SEND() 队列发送成功
traceQUEUE_SEND_FAILED() 队列发送失败
traceQUEUE_RECEIVE() 队列接收成功
traceQUEUE_RECEIVE_FAILED() 队列接收失败
traceBLOCKING_ON_QUEUE_SEND() 队列已满,发送任务阻塞
traceBLOCKING_ON_QUEUE_RECEIVE() 队列为空,接收任务阻塞
11.1.2 内存申请失败 / 栈溢出 Hook

内存申请失败 Hook

pvPortMalloc() 申请内存失败时,可以调用:void vApplicationMallocFailedHook(void);需要在 FreeRTOSConfig.h 中开启:

c 复制代码
#define configUSE_MALLOC_FAILED_HOOK 1

该函数用于定位堆内存不足的问题。

栈溢出 Hook

检测到任务栈溢出时,会调用:

c 复制代码
void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );

栈溢出有两种检测方法:

方法1:检查栈指针 方法2:检查栈填充值
任务切换时,检查栈指针是否越界。 速度快、但可能漏掉任务运行过程中出现的临时栈峰值 创建任务时,用固定值 0xA5 填充任务栈,之后检查栈末尾的值是否被修改。 检测更加可靠、能发现绝大多数栈溢出、运行开销略高

11.2 优化

在Windows中,当系统卡顿时我们可以查看任务管理器找到最消耗CPU资源的程序。在FreeRTOS中,我们也可以查看任务使用CPU的情况、使用栈的情况,然后针对性地进行优化。这就是查看"任务的统计"信息。

11.2.1 精细调整栈大小

c 复制代码
/* 31_stack_state             // 精细调整栈大小_单个任务   
*参数/返回值    	   说明
*xTask	           哪个任务
*返回值	        任务运行时、任务被切换时,都会用到栈。栈里原来值(0xa5)就会被覆盖。 逐个函数从栈的尾部判断栈的值连续为0xa5的个数, 它就是任务运行过程                    中空闲内存容量的最小值。 注意:假设从栈尾开始连续为0xa5的栈空间是N字节,返回值是 N/4。*/
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );



/* 使用示例 */
xTaskHandle = xTaskGetCurrentTaskHandle();
freeNum = uxTaskGetStackHighWaterMark(xTaskHandle);
printf("FreeStack of Task %s : %d\n\r", pcTaskGetName(xTaskHandle), freeNum);	
11.2.2 打印所有任务的栈信息

在钩子函数vApplicationIdleHook()里面 添加这方面程序,以免影响其他任务

c 复制代码
void vTaskList( signed char *pcWriteBuffer );
void vTaskGetRunTimeStats( signed char *pcWriteBuffer );


/* 配置cubeMX,添加vTaskList()函数
* 32_all_stack_state     // 打印所有任务的栈信息_钩子函数`vApplicationIdleHook()`中 
* 33_cpu_usage           // 找到大量消耗CPU资源的任务 */
void vApplicationIdleHook( void )
{
   /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set to 1 in FreeRTOSConfig.h. It will be called on each   	    iteration of the idle task. It is essential that code added to this hook function never attempts to block in any way (for example,        call xQueueReceive() with a block time specified, or call vTaskDelay()). If the application makes use of the vTaskDelete() API            function (as this demo application does) then it is also important that vApplicationIdleHook() is permitted to return to its calling      function, because it is the responsibility of the idle task to clean up memory allocated by the kernel to any task that has since been    deleted. */
	vTaskList(pcWriteBuffer);				// 栈信息
    //vTaskGetRunTimeStats(pcWriteBuffer);  // 找到大量消耗CPU资源的任务 33
	for (int i = 0; i < 16; i++)
	{
		printf("-");
	}
	printf("\n\r");
	printf("%s\n\r", pcWriteBuffer);
}

任务的统计信息

栈信息 统计CPU占比

本文仅供个人学习与交流,如有疏漏或错误,敬请批评指正

相关推荐
白帽小阳1 小时前
Typora插件开发指南:打造专属IDE式写作环境
c语言·网络·python·网络安全·github·pygame·护网行动
ysu_031411 小时前
06 | 200个单元测试C项目也能TDD
c语言·单元测试·tdd
花花无缺17 小时前
Windows 定时执行 Python 脚本方案
python·操作系统·命令行
小宇子2B18 小时前
LRU 不只是最近最少使用:active/inactive、anon/file、folio 和分代 LRU
操作系统
烟锁池塘柳020 小时前
【C/C++】解决C++控制台输出中文乱码问题
c语言·开发语言·c++
捷瑞电子工坊1 天前
C语言联合体(Union)——让同一块内存“变脸”
c语言·union·联合体·内存共享
凉、介1 天前
Linux 设备驱动匹配机制
linux·笔记·单片机·学习·操作系统·嵌入式
aaPIXa6221 天前
C++ 用 Claude Code 的 defending-code-reference-harness:C/C++ 内存漏洞自动发现与修复 Pipeline
java·c语言·c++
xingke2 天前
C 语言多文件编程:(一)头文件、extern、编译链接
c语言·开发语言·多文件