Arduino - 告别手搓多任务,使用TaskScheduler协程库

概述

TaskScheduler是协作式多任务(任务调度)的轻量级实现,主要有以下特点:

  1. 任务周期性执行,执行频率以毫秒(默认)或微秒(如果显式启用)为单位;

  2. 支持设定执行次数(有限或无限次)

  3. 按预定义的顺序执行任务

  4. 支持任务执行参数的动态变化(频率、执行次数、回调方法)

  5. 支持在没有任务运行时进入睡眠模式以省电

  6. 支持事件驱动的任务调度

  7. 支持任务优先级

调度开销:每次调度 15 到 18 微秒(Arduino UNO rev 3 @ 16MHz 时钟,没有优先级的单个调度程序)

基本用法

/** 
 *  TaskScheduler 测试
 *  初始化时,task1和task2是激活的
 *	task1 间隔2s,运行10次后停止
 *	task2 间隔3s,一直运行
 *	task1 第一次运行时激活task3
 *	task3 间隔5s,一直运行
 *	task1 最后一次运行时关闭task3,并将task2的运行间隔设置为1/2s
 */
 
 
#include <TaskScheduler.h>

// 声明回调函数,即任务实际执行的代码
void t1Callback();
void t2Callback();
void t3Callback();

// 定义任务
Task t1(2000, 10, &t1Callback);	//任务名称t1,间隔2000ms,总共执行10次,执行的代码为t1Callback()
Task t2(3000, TASK_FOREVER, &t2Callback);//任务名称t2,间隔3000ms,一直执行,执行的代码为t2Callback()
Task t3(5000, TASK_FOREVER, &t3Callback);//任务名称t3,间隔5000ms,一直执行,执行的代码为t3Callback()

//声明调度器
Scheduler runner;


//定义t1Callback()
void t1Callback() {
    Serial.print("t1: ");
    Serial.println(millis());
    
    if (t1.isFirstIteration()) {//如果t1任务是第一次运行,则执行该代码块
      runner.addTask(t3);//将t3任务添加到调度器的任务链中,添加之后要打开(使能)才能够真正运行
      t3.enable();//打开t3任务,执行该语句后,t3任务会立即执行
      Serial.println("t1: 将t3任务加入任务链并开始执行");
    }
    
    if (t1.isLastIteration()) {//如果t1任务是最后一次运行,则执行该代码块
      t3.disable();//关闭t3任务
      runner.deleteTask(t3);//从任务链中删除t3任务
      t2.setInterval(500);//将t2任务的执行间隔设置为500ms
      Serial.println("t1: 关闭t3任务并将其从任务链中删除,并将t2任务的执行间隔设置为500ms");
    }
}

//定义t2Callback()
void t2Callback() {
    Serial.print("t2: ");
    Serial.println(millis());
  
}

//定义t3Callback()
void t3Callback() {
    Serial.print("t3: ");
    Serial.println(millis());
}

void setup () {
  Serial.begin(115200);
  Serial.println("Scheduler TEST");
  
  runner.init();
  Serial.println("初始化 scheduler");
  
  runner.addTask(t1);
  Serial.println("添加t1任务");
  
  runner.addTask(t2);
  Serial.println("添加t2任务");

  delay(5000);
  
  t1.enable();
  Serial.println("打开t1任务");
  t2.enable();
  Serial.println("打开t2任务");
}


void loop () {
  //loop()中只要调用调度器的execute()函数即可
  runner.execute();
}

任务生命周期

看图

在这里插入图片描述

注意

  • 在PlatformIO中使用需要在声明中包含#define _TASK_INLINE

参考资料

Full Document · arkhipenko/TaskScheduler Wiki


版权声明:本文为weixin_39155340原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。