RTOS-F429-HAL-任务的挂起和恢复(含中断)(2026/7/27) 目录一任务的挂起与恢复1函数原型2中断恢复挂起的任务3申请任务切换的宏二任务挂起与恢复 — 普通版 vs 中断版1、API 对比2、普通版恢复挂起函数vTaskResume3、中断恢复挂起函数xTaskResumeFromISR三中断版提醒恢复挂起的几个变量四任务列表-宿管SysTick五ISR 里不能用 printf1第一层死锁2第二层耗时太长3第三层65 秒超时六局部变量为什么不能加Static1普通单线程程序的“局部变量”2RTOS 任务的“局部变量”3rtos的局部变量加了static会怎么样1不加 static2加了 static3举个栗子4总结一任务的挂起与恢复1函数原型void vTaskSuspend(TaskHandle_t xTaskToSuspend); void vTaskResume(TaskHandle_t xTaskToResume);vTaskSuspendvTaskResume参数要挂起的任务句柄要恢复的任务句柄返回值无无前提宏INCLUDE_vTaskSuspend 1不需要永远编译NULL 代表什么NULL 挂起自己不能传 NULL对任务的影响从就绪/阻塞链表移除 →调度器再也看不到它重新加入就绪链表 →可以继续被调度能重复调吗能。已被挂起的任务再挂一次没效果能。没被挂起的任务恢复一下没效果也不报错ISR 里能调吗❌ 没有 FromISR 版ISR 不干这事❌ 同样没有挂起 ≠ 删除。删除是永久的栈和 TCB 都没了挂起只是暂停——Tcb还在、栈还在恢复接着跑。挂了 10 秒钟vTaskDelay(500)的倒数继续从挂起那一刻计时不是被挂起的 10 秒算进去。2中断恢复挂起的任务BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume); 说明 参数 要恢复的任务句柄不能是 NULL 返回值 pdTRUE 被恢复的任务优先级 ≥ 当前被中断打断的任务 → 需要立刻切 返回值 pdFALSE 表示不需要切任务 前提宏 INCLUDE_vTaskSuspend 1 且 INCLUDE_xTaskResumeFromISR 1 能重复调吗 能。任务没被挂起时返回 pdFALSE不报错 内部干了什么 把任务从挂起列表移到就绪列表 → 比较优先级 → 返回要不要切3申请任务切换的宏portYIELD_FROM_ISR() 这个宏本质上是给 CPU 的 PendSV悬起系统调用 寄存器置位。 置位了中断退出后CPU 就会立刻跳去执行别的任务上下文切换。 没置位中断退出后CPU 就回到原来被打断的地方继续执行。可以填入pdTRUE 和 pdFALSE填入pdTRUE 不管三七二十一直接把 PendSV 置位中断一结束CPU 必然进行一次任务切换。它会去执行当前系统中最高优先级就绪态的任务不一定是 我们恢复挂起的Task1可能是别的任务优先级更高的任务。风险这很浪费如果当前被中断的任务本来就是最高优先级的或者刚唤醒的任务优先级并不高这次切换就是白忙活浪费了 CPU 时间。填入pdFALSE不切换任务中断结束后CPU 老老实实回到原来的任务。风险如果你刚唤醒了一个高优先级的紧急任务结果因为没切换CPU 还在慢吞吞跑着低优先级的任务这就失去了实时操作系统的意义。二任务挂起与恢复 — 普通版 vs 中断版1、API 对比任务版中断版挂起vTaskSuspend(句柄)❌ 不存在恢复vTaskResume(句柄)xTaskResumeFromISR(句柄)前提宏INCLUDE_vTaskSuspend 1同上 INCLUDE_xTaskResumeFromISR 1在哪调任务里ISR 里调完当场切任务可能——被恢复的优先级更高就切绝不当场切——等 ISR 退出后才切返回值无pdTRUE 被恢复的优先级更高→需切pdFALSE 不需要切2、普通版恢复挂起函数vTaskResumetask1(优先级2) 蓝灯翻转task2(优先级3) 打印task3(优先级4) 按键扫描 ​ KEY1 按下 → task3 扫描到 vTaskSuspend(Task1_Handler); → task1 从就绪列表摘掉 → 挂到挂起列表 → task1 消失调度器不再看到它 ​ KEY2 按下 → task3 扫描到轮询版 vTaskResume(Task1_Handler); → task1 从挂起列表摘掉 → 挂回就绪列表 → 优先级 2 当前 task3(4) → 不切task3 继续跑 → 等 task3 Delay、task2 Delay → task1 被调度 → 续跑3、中断恢复挂起函数xTaskResumeFromISR配置KEY2(PC13) → EXTI15_10_IRQn优先级设为 5≥5 可调 FreeRTOS API ​ KEY2 按下 → 硬件触发 EXTI15_10_IRQHandler ① 读标志确认是 PC13 ② for 循环软件消抖 ③ xTaskResumeFromISR(Task1_Handler); → task1 从挂起列表摘掉 → 挂回就绪列表 → 大概率返回 pdFALSEtask12 被打断的任务3 或 4 → 小概率按下刚好是空闲任务返回的就是pdFALSE 因为task1 优先级是1 空闲任务 ④ 清标志退出 ISR ​ ISR 退出后 → 回到上次被打断的任务继续跑 → 下次 SysTick → task1优先级排到它了→ 被调度 → 续跑三中断版提醒恢复挂起的几个变量变量变化第一次按 KEY1→KEY2初始 Task1_SuspendCnt 0 全局变量task3 每挂一次就 1 cnt 0 task1 栈里的局部变量每次打印 1 last_cnt 0 task1 栈里的局部变量记住上次 Task1_SuspendCnt 是几 ​ task1 正常跑着 比较Task1_SuspendCnt(0) last_cnt(0) → 相等不打印 cnt → 打印 task1: 1 vTaskDelay... ​ ══════════ KEY1 按下 ══════════ ​ task3 执行 vTaskSuspend(Task1_Handler); // task1 冻结栈里的 cnt5、last_cnt0 原样保存 Task1_SuspendCnt; // Task1_SuspendCnt 变成 1 ​ ══════════ KEY2 按下 ══════════ ​ ISR 执行 xTaskResumeFromISR(Task1_Handler); // task1 回到就绪列表啥也没丢 ​ task1 被调度继续跑 比较Task1_SuspendCnt(1) ! last_cnt(0) → 不相等 → printf(task1 恢复运行!\r\n) → last_cnt Task1_SuspendCnt; // last_cnt 变成 1追平 → cnt → 打印 task1: 6 // cnt 从 5 续跑 ​ 下一轮循环 比较Task1_SuspendCnt(1) last_cnt(1) → 相等不打印 正常...##四任务列表-宿管SysTickSysTick 每 1ms 来敲门一次翻一下户口本——xTickCount 涨 1有人昨天说第 500 次时叫他吗不是专门盯着某人等 500 次而是每天凌晨 0 点准时敲一遍——第 1ms、第 2ms…第 499ms 都发现还没到第 500ms 一翻户口本——这人到时间了唤醒放就绪队列。SysTick 不单独盯谁每 1ms 扫一遍今天谁到期。五ISR 里不能用printf1第一层死锁正常时Task2 调用 printf → huart1.gState BUSY → 正在往串口发数据突然ISR 中断来了 → 打断 Task2 → ISR 里调 printf → HAL_UART_Transmit 检查 huart1.gState → gState 还是 BUSYTask2 没机会放开锁 → HAL_UART_Transmit 死等while (gState ! READY); → 但 Task2 被 ISR 压着永远不会再次运行去改变 gState → gState 永远 BUSY → while(1) 永远等 → 死锁ISR 在等锁持锁的人在等 ISR 退出——谁也动不了。2第二层耗时太长就算运气好 huart1 刚好闲着gState READYprintf(Hello World!\r\n) ≈ 14 字节 115200 波特率 → 每字节 ≈ 87μs 14 字节 ≈ 1.2msISR 里 CPU 100% 归你发完之前系统里所有任务、所有低优先级中断全部排队等着。1.2ms 在嵌入式里就是永恒——SysTick 心跳都被憋过一次。3第三层65 秒超时HAL_UART_Transmit 内部写法while (串口还没发完) { if (等待时间 0xFFFF ms) // ≈ 65 秒 报错退出; }任务里等 65 秒才报错还能接受。ISR 里卡 65 秒——整个系统看起来像冻死了连调试器都连不上。结论ISR 里绝对不能调任何走到 HAL_UART_Transmit 的函数。以后需要 ISR 通知任务用队列或者任务通知的 FromISR 版本。六局部变量为什么不能加Static1普通单线程程序的“局部变量”void func() { int a 0; a; // 函数结束a所在的这块内存栈帧被系统回收了 } ​ int main() { func(); // a变成1然后a没了 func(); // a重新创建又是0再变成1 }这里的func()跑完一次就销毁一次所以第二次调用a又是新的。2RTOS 任务的“局部变量”void Task1(void *pvParameters) { int a 0; // 局部变量 while(1) { // 重点在这里死循环 a; vTaskDelay(pdMS_TO_TICKS(1000)); } }任务栈的独立性当你用xTaskCreate创建任务时RTOS 会给这个任务分配一块专属的内存叫做任务栈Task Stack。只创建一次当任务第一次运行时int a 0;这句代码只在那一刻执行了一次。变量a被分配在了 Task1 的专属栈里。挂起不等于销毁当vTaskDelay或者taskYIELD发生Task1暂停运行挂起切换到 Task2。这时候CPU 只是把当前的寄存器状态包括栈指针存到了 Task1 的栈里然后跳去 Task2 的栈里玩。恢复运行当 1000ms 到了调度器决定让 Task1 继续跑。CPU 从 Task1 的栈里把之前存的状态恢复回来。那个变量a依然静静地躺在 Task1 的栈里值还是上次算出来的 5假设。3rtos的局部变量加了static会怎么样1不加 staticstatic void task1(void *pvParameters) { uint32_t cnt 0; // ← 存在 task1 的栈上FreeRTOS 堆里挖的那 512 字节 for (;;) { ... } }每个任务的栈是独立的。task1 被挂起 → 整个栈帧冻住 →cnt值原样保存。task2 有自己的栈、自己的局部变量互不踩脚。2加了 staticstatic void task1(void *pvParameters) { static uint32_t cnt 0; // ← 存在 .bss 段芯片 SRAM 的全局区域 for (;;) { ... } }芯片 SRAM 布局 .bss 段全局/静态变量区 ├── Task1_Handler ← 全局句柄 ├── StartTask_Stack[128] ← 静态任务栈 ├── cnt ← static 局部变量跑这来了 └── ... FreeRTOS 堆configTOTAL_HEAP_SIZE 36KB ├── task1 动态栈128 words ├── task2 动态栈 └── ...static让cnt变成了披着局部外衣的全局变量——作用域还在 task1 函数内别的函数访问不到但存储位置不在任务栈在 SRAM 全局区。所有任务共享这块区域。3举个栗子如果你创建了两个 Task1比如 Task1_A 和 Task1_B它们运行的是同一份代码如果用int aTask1_A 里的a和 Task1_B 里的a互不干扰各自计数。如果用static int aTask1_A 和 Task1_B 操作的其实是内存里的同一个a它们会互相覆盖数值这里就需要互斥锁来保护不然会乱套。期望的输出 实际的输出 task1A: 1 task1A: 1 task1B: 1 task1B: 2 ← B 把 A 的 cnt 抢了 task1A: 2 task1A: 3 task1B: 2 task1B: 44总结在 RTOS 任务里不加static变量住在任务自己的小房间栈里只要任务不死它就一直在。而且每个任务都有自己独立的一份互不打扰。加static变量住进了公共地下室全局区大家都能看见容易打架竞争条件除非你加了锁rtos里面有一个叫互斥锁。所以你看到的现象是完全正常的RTOS 就是通过给每个任务分配独立的栈才实现了“看起来像同时运行”的多任务效果。

相关新闻

最新新闻

TI DRV5032超低功耗霍尔传感器评估与能量收集系统实战解析

TI DRV5032超低功耗霍尔传感器评估与能量收集系统实战解析

1. 项目概述:从官方文档到实战应用的深度解析最近在做一个需要磁感应开关的便携式设备项目,对功耗和体积都卡得特别死,市面上常见的霍尔传感器要么功耗太高,要么灵敏度不够。翻遍了TI、Allegro、Infineon的选型手册,最…

2026/7/28 0:05:34
如何让经典DirectX游戏在现代Windows上流畅运行:DDrawCompat完全指南

如何让经典DirectX游戏在现代Windows上流畅运行:DDrawCompat完全指南

如何让经典DirectX游戏在现代Windows上流畅运行:DDrawCompat完全指南 【免费下载链接】DDrawCompat DirectDraw and Direct3D 1-7 compatibility, performance and visual enhancements for Windows Vista, 7, 8, 10 and 11 项目地址: https://gitcode.com/gh_mir…

2026/7/28 0:05:34
基于TPS68000EVM-202的CCFL背光驱动方案:从相移全桥原理到双灯独立调光实战

基于TPS68000EVM-202的CCFL背光驱动方案:从相移全桥原理到双灯独立调光实战

1. 项目概述与核心价值如果你正在设计一款需要冷阴极荧光灯(CCFL)作为背光光源的设备,比如医疗显示器、工业控制面板或者一些专业级的液晶显示设备,那么驱动电路的设计绝对是一个绕不开的挑战。CCFL灯管需要的是高频、高压的交流电…

2026/7/28 0:05:34
5分钟免费掌握Windows风扇控制:FanControl中文版终极指南

5分钟免费掌握Windows风扇控制:FanControl中文版终极指南

5分钟免费掌握Windows风扇控制:FanControl中文版终极指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending…

2026/7/28 0:05:34
多无人机协同路径规划:基于多段Dubins路径的Matlab实现

多无人机协同路径规划:基于多段Dubins路径的Matlab实现

1. 项目背景与核心挑战在复杂威胁环境下实现多无人机协同路径规划是当前无人机自主控制领域的前沿课题。传统单机路径规划算法难以应对动态威胁、协同避障和任务分配等多重挑战。本项目基于多段杜宾斯(Dubins)路径构建了一种新型协同规划框架,通过Matlab实现了复杂场…

2026/7/28 0:05:34
视频扒音乐怎么操作?2026年最新完整方法(电脑手机免费工具大盘点)

视频扒音乐怎么操作?2026年最新完整方法(电脑手机免费工具大盘点)

今年七月,我帮朋友从一段采访视频里提取背景音乐,前后试了五六种方法,才发现不同需求的解决方案差别挺大。有些人只想快速把整段视频的音频导出来当铃声,有些人却要分离人声和伴奏做混音,还有人纠结于“在线工具会不会…

2026/7/28 0:00:34

月新闻