在Arduino开发中,定时器是一个关键的工具,它允许我们在特定时间间隔执行预定的任务。本篇文章将介绍如何使用Ticker库创建和管理多个定时器,以实现多任务定时操作。
在ESP32使用Ticker库之前,我先介绍一下不同IDE下Ticker库的位置以及由于系统自带的Ticker与我们安装的Ticker冲突的解决办法:
Arduino IDE的Ticker文件夹位置
- Arduino IDE安装ESP32开发包后, ESP32目录下自带的Ticker:
C:\Users\UserName\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.14\libraries\Ticker
- 你通过下图方式安装Ticker后的位置,根据你项目目录的不同,位置也不同,可以通过“文件”-“首选项…”-“项目文件夹地址”来查看。
如果此时编译,系统默认用的是文件夹1所在的位置。编译文中代码时,会出错。
Ticker名称解决方法有两种:
- 删除ESP32文件夹下的Ticker目录,编译时IDE会使用你自己安装的Ticker4.4.0库
- 用TickTwo库,TickTwo库是专门针对这个ESP32自带的Ticker库名称冲突而开发的,其使用方法与Ticker4.4.0一样,除了导入时要导入TickTwo库,创建对象时要创建TickTwo对象。
PlatformIO IDE的Ticker文件夹位置
- 在VSCode里安装PlatformIO后, ESP32目录下自带的Ticker:
C:\Users\UserName\.platformio\packages\framework-arduinoespressif32\libraries\Ticker
2.众所周知,PlatformIO安装的库都在下面的位置:
项目所在目录\.pio\libdeps\esp32dev\Ticker
Ticker名称解决方法有两种:
- 如果你在你的项目里已经安装了Ticker, PlatformIDE会优先使用项目文件夹内的Ticker库,编译不会出错,你可以放心大胆地的Ticker,不存在因为名称冲突造成编译出错的问题
- 如果你既用PlatformIO也用Arduino IDE,那你就直接用TickTwo,代码在两个IDE复制的时候,不会改来改去。
示例代码:
#include <Arduino.h>
#include "TickTwo.h"
#define LED_BUILTIN 2
void printMessage();
void printCounter();
void printCountdown();
void blink();
void printCountUS();
bool ledState;
int counterUS;
/** 创建一个Ticker对象
*
* @param callback 要调用的函数名称
* @param timer 间隔长度,以毫秒或微秒为单位
* @param repeat 默认为0,表示无限循环,repeat > 0 表示重复次数
* @param resolution 默认为MICROS,适用于70分钟以下的ticker,对于超过70分钟的ticker,请使用MILLIS
*
*/
// 创建五个定时器对象,分别用于不同的功能
TickTwo timer1(printMessage, 0, 1); // 执行一次,立即执行
TickTwo timer2(printCounter, 1000, 0, MILLIS); // 每1000毫秒触发一次printCounter函数,使用毫秒单位
TickTwo timer3(printCountdown, 1000, 5); // 执行5次,每次间隔1秒,即1000毫钞
TickTwo timer4(blink, 500); // 创建一个定时器,每500毫钞触发一次blink函数
TickTwo timer5(printCountUS, 100, 0, MICROS_MICROS); // 每100*10000微秒(即100*10毫秒)触发一次printCountUS函数,使用10毫秒为单位
/** Ticker 内部时基设定
*
* @param MICROS 默认值,时基单位为微秒,最大可设置周期为70分钟,实际最小分辨率为16MHz CPU时钟下的4微秒。
* @param MILLIS 将时基设置为毫秒,适用于超过70分钟的更长周期。
* Firmin123456备注:不管是MICROS还是MILLIS,都是以毫秒为单位计数。。MICROS_MICROS是以10毫秒为单位计数。
*/
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
delay(2000);
timer1.start();
timer2.start();
timer3.start();
timer4.start();
timer5.start();
}
void loop()
{
timer1.update();
timer2.update();
timer3.update();
timer4.update();
timer5.update();
if (timer4.counter() == 20)
timer4.interval(200); // 当计数器等于20时,将定时器的间隔时间调整为200毫秒
if (timer4.counter() == 80)
timer4.interval(1000); // 当计数器等于80时,将定时器的间隔时间调整为1000毫秒
}
void printCounter()
{
Serial.print("Counter ");
Serial.println(timer2.counter());
}
void printCountdown()
{
Serial.print("Countdowm ");
Serial.println(5 - timer3.counter());
}
void printMessage()
{
Serial.println("Hello!");
}
void blink()
{
digitalWrite(LED_BUILTIN, ledState);
ledState = !ledState;
}
void printCountUS()
{
counterUS++;
if (counterUS == 10000)
{
Serial.println("10000 * 100us");
counterUS = 0;
}
}
这个示例比较简单,所有重点都在注释里说明了,但请注意loop()里条件判断重设interval()的部分,当计数器等于20时,将定时器的间隔时间调整为200毫秒,当计数器等于80时,将定时器的间隔时间调整为1000毫秒。
你可以通过观察板载LED D2的闪烁看到周期变化。
安装TickTwo库的话,修改一下相应内容,其功能也是一样的,修改后的代码
#include <Arduino.h>
#include "Ticker.h"
#define LED_BUILTIN 2
void printMessage();
void printCounter();
void printCountdown();
void blink();
void printCountUS();
bool ledState;
int counterUS;
/** 创建一个Ticker对象
*
* @param callback 要调用的函数名称
* @param timer 间隔长度,以毫秒或微秒为单位
* @param repeat 默认为0,表示无限循环,repeat > 0 表示重复次数
* @param resolution 默认为MICROS,适用于70分钟以下的ticker,对于超过70分钟的ticker,请使用MILLIS
*
*/
// 创建五个定时器对象,分别用于不同的功能
Ticker timer1(printMessage, 0, 1); // 执行一次,立即执行
Ticker timer2(printCounter, 1000, 0, MILLIS); // 每1000毫秒触发一次printCounter函数,使用毫秒单位
Ticker timer3(printCountdown, 1000, 5); // 执行5次,每次间隔1秒,即1000毫钞
Ticker timer4(blink, 500); // 创建一个定时器,每500毫钞触发一次blink函数
Ticker timer5(printCountUS, 100, 0, MICROS_MICROS); // 每100*10000微秒(即100*10毫秒)触发一次printCountUS函数,使用10000微秒为单位
/** Ticker 内部时基设定
*
* @param MICROS 默认值,时基单位为微秒,最大可设置周期为70分钟,实际最小分辨率为16MHz CPU时钟下的4微秒。
* @param MILLIS 将时基设置为毫秒,适用于超过70分钟的更长周期。
* Firmin123456备注:不管是MICROS还是MILLIS,都是以毫秒为单位计数。。MICROS_MICROS是以10毫秒为单位计数。
*/
/** Ticker 内部时基设定
*/
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
delay(2000);
timer1.start();
timer2.start();
timer3.start();
timer4.start();
timer5.start();
}
void loop()
{
timer1.update();
timer2.update();
timer3.update();
timer4.update();
timer5.update();
if (timer4.counter() == 20)
timer4.interval(200);
if (timer4.counter() == 80)
timer4.interval(1000);
}
void printCounter()
{
Serial.print("Counter ");
Serial.println(timer2.counter());
}
void printCountdown()
{
Serial.print("Countdowm ");
Serial.println(5 - timer3.counter());
}
void printMessage()
{
Serial.println("Hello!");
}
void blink()
{
digitalWrite(LED_BUILTIN, ledState);
ledState = !ledState;
}
void printCountUS()
{
counterUS++;
if (counterUS == 10000)
{
Serial.println("10000 * 100us");
counterUS = 0;
}
}