07-ESP8266 多任务库函数

Author:teacherXue

一、TaskScheduler多任务库函数

上一章节的计时器伪多线程操作中需要定义大量的变量,封装一下会提高代码的可读性。拿来主义是个不错的选择。Arduino框架提供了TaskScheduler多任务库函数。

  1. 特点

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

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

  • 按预定义的顺序执行任务

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

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

  • 支持事件驱动的任务调度

  • 支持任务优先级

  • 每次调度在Arduino UNO rev 3 @ 16MHz 时钟平台上需消耗 15 到 18 微秒调度开销,ESP8266上只有几微秒)

  1. 导入支持库

第二章节中已经讲过,这里简单陈述步骤。

1)先创建一个新项目Lamp_ task_v2.0。
2)查找支持库并下载安装到执行项目。
3)在main.cpp文件中引入头文件,如果报错,说明扩展库安装失败。
#include <TaskScheduler.h>
  1. 基本使用

创建任务调度对象,虽然C是面向过程的,但并不影响我们使用面向对象的思想去思考。其实看提示你会发现Scheduler是一个class文件。

Scheduler runner;

声明包含时间周期的任务

//声明任务执行函数
void t1Callback();
void t2Callback();
void t3Callback();

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

loop()中只要调用调度器的execute()函数即可

//loop()中只要调用调度器的execute()函数即可
  runner.execute();
  1. 常见函数

该库提供了很多方法供我们使用,下面是一些可能比较常用的方法。

isFirstIteration()

如果任务是第一次运行,则执行该代码块

addTask(Task)

将任务添加到调度器的任务链中,添加之后要打开(使能)才能够真正运行

enable()

打开任务,执行该语句后,任务会立即执行

isLastIteration()

如果任务是最后一次运行,则执行该代码块

disable()

关闭任务

deleteTask(Task)

从任务链中删除任务

setInterval(long)

将任务的执行间隔设置为指定ms

二、TaskScheduler实现多线程灯光控制

根据上一节的讲解,我们发现想要直观的控制两盏灯的开关,就需要将相关操作封装成回调方法,有任务调度器在相应的时间策略里来执行调用。

我们通过全局变量来存储等缘故

需要注意的是单片机运算能力还是有限,某些任务需要较高响应速度,不能一味的往上堆任务。在旋钮控灯的基础上,先让LED1闪烁起来吧(呼吸效果需要较多任务计时,先搞清楚基本原理)。

  1. 新建项目

1)创建项目Lamp_ task_v1.0并确定。

2)修改platformio.ini配置文件增加串口通讯波特率monitor_speed =115200

2、代码实现

1)编辑main.cpp主文件,为旋钮控灯和闪烁控灯分别创建计时器。

unsigned long currentTime=0; //当前时间,每次loop时判断一次,因此一个即可
//闪灯计时器
unsigned long intervalTime1=1000; //等待间隔
unsigned long previousTime1 = millis();//注册开始时间
bool switch_led1=false;//灯光开关状态

//旋钮计时器
unsigned long intervalTime2=30;//等待间隔
unsigned long previousTime2 = millis();//注册开始时间

2)loop中先取当前时间

currentTime = millis();

3)判断当前时间和计时器登记时间差是不是达到等待要求时间,达到则调用任务,同时,再重置计时器登记时间。两个任务都是这样处理。

void loop()
{
  currentTime = millis();//获得当前loop的时间
  //判断当前时间和计时器登记时间是不是超过等待时间间隔
  if(currentTime-previousTime1>=intervalTime1){
    switch_led1=!switch_led1;//改变灯光开关状态
    previousTime1=currentTime;//重新登记计时器1时间
  }
  //根据开关状态控制LED_1开关
  digitalWrite(LED_1, switch_led1?HIGH:LOW);

  //判断当前时间和计时器登记时间是不是超过等待时间间隔
  if(currentTime-previousTime2>=intervalTime2){
    knobValue=analogRead(analogInPin);
    // 读取模拟数值
    analogWrite(LED_2, map(knobValue, 15, 1008, 0, 255));
    // 打印串行监视器中的读数
    Serial.print("sensor = ");
    Serial.println(knobValue);
    previousTime2=currentTime;//重新登记计时器2时间
  }
}

4)完整代码

#include <Arduino.h>
#include <TaskScheduler.h>

#define analogInPin A0 // 模拟输入引脚A0
#define LED_1 D5       // D5白色LED引脚,本例中先不使用
#define LED_2 D6       // D6绿色LED引脚

bool switch_led1=false;//灯光开关状态
int knobValue = 0;//旋钮读数

Scheduler runner; //任务调度器对象

int dutyCycle =0; //亮度值
// 亮灯任务
void task_led1_H() 
{ 
  analogWrite(LED_1,switch_led1?dutyCycle+=3:dutyCycle--);
}

//旋钮任务
void task_knob() 
{ 
   knobValue=analogRead(analogInPin);
    // 读取模拟数值
    analogWrite(LED_2, map(knobValue, 15, 1008, 0, 255));
}

// 定义任务
Task t1(3, TASK_FOREVER, &task_led1_H); //任务名称t1,间隔3ms一直执行.
Task t3(30, TASK_FOREVER, &task_knob);//任务名称t3,间隔50ms,一直执行。

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200); // 设置串口通信波特率
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
  runner.init();//初始化任务调度器
  runner.addTask(t1);//增加任务调度
  runner.addTask(t3);
  t1.enable();//任务开始
  t3.enable();
}

void loop()
{ 
  //达到最亮后后转为逐渐熄灭,熄灭200毫秒后改为逐渐亮起,有400毫秒的全黑时间
  if(dutyCycle>=255){
    switch_led1=false;    
  }
  if(dutyCycle<=-200){   
    switch_led1=true;    
  } 
  runner.execute();//执行任务
}
}

5)烧录代码成功后,控制旋钮观察两盏LED的状态。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盐池虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值