TaskScheduler 是一个为 Arduino、ESP8266/ESP32、STM32 等单片机设计的协作式任务调度库。它让你以任务(Task)为单位安排周期、次数、回调函数和优先级,调度器负责何时调用这些回调,你只需专注功能逻辑。
它解决了哪些痛点
-
• 代码凌乱:不用在 loop() 写一堆 millis 计时判断,逻辑更清晰、可维护。
-
• 频率管理困难:不同模块需不同频率(像 10ms、100ms、1s),TaskScheduler 能以毫秒(甚至微秒)级别管理。
-
• 并发复杂度:协作式调度避免抢占式并发下的 race、死锁等常见问题(对大多数 MCU 小项目足够)。
-
• 节能需求:空闲时可以进入 IDLE sleep,节省功耗(特别是电池供电场景)。
-
• 动态变化:运行时可以修改任务周期、次数、回调,支持启停、暂停、删掉任务。
-
• 诊断与容错:支持任务超时、控制点(Control Points)、本地任务存储、CPU 空闲统计,方便排错。
主要功能速览
-
• 周期执行、动态修改周期(ms/µs)
-
• 指定执行次数或无限循环
-
• 顺序执行、分层优先、调度选项(是否补偿错过的执行等)
-
• 事件驱动调用(Status Request)
-
• 任务 ID、超时/看门狗支持
-
• 可绑定 std::function(ESP/STM32 支持较好)
-
• 在 FreeRTOS 下线程安全、可“无滴答”休眠模式
-
• 调度开销小:普通 Arduino 上每次调度 ~15–18µs
安装和快速上手(最实际的步骤)
-
1. 下载/安装
-
• GitHub 地址(项目地址在文末):直接克隆或在 Arduino IDE 的库管理器里搜索 TaskScheduler 并安装。
-
2. 代码骨架(伪代码 + 说明)
-
• 在 setup() 中创建 TaskScheduler 对象、定义若干 Task,并把 Task 加入调度器。
-
• 在 loop() 里只需调用 tasks.execute(); 就行了。
示例思路(不是完整代码): -
• 定义一个回调 void blinkCb(),每 500ms 切换 LED
-
• Task blinkTask(500, TASK_FOREVER, &blinkCb); scheduler.addTask(blinkTask); blinkTask.enable();
-
• loop() { scheduler.execute(); }
-
3. 常用 API 提示(记住几个方法就够)
-
• addTask(Task) / removeTask(id)
-
• enable()/disable()/pause()/resume()(对单个 task 生效)
-
• setInterval(ms)/setIterations(n) 动态修改
-
• scheduler.execute() 放到 loop() 里运行调度循环
-
4. 在 FreeRTOS 或需要更精确时:可启用微秒分辨率或“tickless”睡眠(参考 extras 文档)
优点
-
• 极其轻量,学习成本低,适合快速原型和小中型项目。
-
• 让代码结构更清晰、职责更分明(每个任务只做一件事)。
-
• 内置省电与诊断功能,适合电池项目和调试场景。
-
• 兼容多平台(从 AVR 到 ESP、STM32 都能跑)。
缺点与局限
-
• 不是抢占式:如果某个任务运行时间过长,会阻塞其它任务(协作式需要你写短小的回调或分段执行)。
-
• 对硬实时要求高(硬实时、多核或复杂并发)场景不适合,FreeRTOS 更合适。
-
• 某些高级特性(比如 std::function)在部分平台上支持有限,需要注意平台兼容。
-
• 极端高频(微秒级)或非常复杂优先级场景会有性能/调度开销限制。
总结
TaskScheduler 是把“多任务”变简单的实用工具:不用学复杂并发,就能把不同频率的工作有序、可控地安排起来。适合绝大多数 Arduino/ESP/STM32 项目,当然如果你需要硬实时或复杂并发管理,还是考虑 RTOS。要不要试一试?把你的 loop() 变得轻松、可读、好调试,很多人从“写爆代码”到“优雅调度”就只差这一步。
项目地址:https://github.com/zephyrproject-rtos/arkhipenko/TaskScheduler