最近在学习嵌入式开发的内容,正好有一个开发任务涉及到对于定时器中断的使用,今天正好找到了这个相关的库:ESP32TimerInterrupt
ESP32TimerInterrupt库的下载链接(适用于Arduino IDE)
进入到这个地址后直接下载该库的压缩包,不用解压,直接通过arduino IDE添加即可!
然后关于该库的使用,GitHub中也给出了example来告诉大家如何使用。
下面开始例程的分析
- 使用的开发IDE:arduino IDE
- 使用的板子:ESP32S3
- 例程:TimerInterruptTest.ino
首先要使用这个定时器中断,要引入定时器中断的库,即包含这个库的头文件:
#include "ESP32TimerInterrupt.h"
然后定义中断调用时,输出电平的管脚:
#define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
#define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32
然后编写中断处理函数:
bool IRAM_ATTR TimerHandler0(void * timerNo)
{static bool toggle0 = false; // 定义状态值为false//timer interrupt toggles pin PIN_D19digitalWrite(PIN_D19, toggle0); // 调用该中断时,在ESP的GPIO9输出toggle0的状态值toggle0 = !toggle0; // 将状态反转return true;
}
关于该函数的解释及参数说明
bool IRAM_ATTR TimerHandler0(void * timerNo) 是一个中断服务例程(ISR)的声明,它用于ESP32的硬件定时器中断处理。下面是对该函数声明的详细解释:
- bool:函数的返回类型为布尔值,这意味着函数将返回 true 或 false。在中断服务例程中返回 true 通常表示中断被成功处理,而返回 false 可能表示中断未被处理或处理中出现错误。
- IRAM_ATTR:这是一个宏定义,用于指定该函数需要放置在指令RAM(Instruction RAM,IRAM)中。在ESP32中,将中断服务例程放在IRAM中可以确保它们被快速执行,因为IRAM的访问速度比普通RAM快。这是在处理高速中断时推荐的做法。
- TimerHandler0:这是ISR函数的名称,它遵循了一定的命名约定,表明这是针对特定定时器(在这个例子中是 Timer 0)的中断处理函数。
- (void * timerNo):这是传递给ISR的参数,timerNo 是一个指向 void 类型的指针,通常用于传递与定时器相关的信息或上下文。参数的具体使用取决于中断服务例程的设计和需求。
第二个中断处理函数
bool IRAM_ATTR TimerHandler1(void * timerNo)
{static bool toggle1 = false;//timer interrupt toggles outputPindigitalWrite(PIN_D3, toggle1);toggle1 = !toggle1;return true;
}
注:解释与参数说明同上,唯一的区别是,这里的中断用的Timer 1,上面的中断处理函数用的Timer 0。
接下来定义中断的持续时间(毫秒)和间隔时间(微秒)
#define TIMER0_INTERVAL_MS 1000 // 间隔时间单位是微秒
#define TIMER0_DURATION_MS 5000 // 持续时间单位是毫秒#define TIMER1_INTERVAL_MS 3000
#define TIMER1_DURATION_MS 15000
对两个定时器进行初始化
// Init ESP32 timer 0 and 1
ESP32Timer ITimer0(0);
ESP32Timer ITimer1(1);
编写配置函数
void setup()
{pinMode(PIN_D19, OUTPUT);pinMode(PIN_D3, OUTPUT);// 开启串口Serial.begin(115200);// 如果串口连接建立或者板子运行超过5秒则退出循环while (!Serial && millis() < 5000);// 延迟500毫秒delay(500);// 利用串口打印信息Serial.print(F("\nStarting TimerInterruptTest on "));Serial.println(ARDUINO_BOARD);Serial.println(ESP32_TIMER_INTERRUPT_VERSION);Serial.print(F("CPU Frequency = "));Serial.print(F_CPU / 1000000);Serial.println(F(" MHz"));// Using ESP32 => 80 / 160 / 240MHz CPU clock ,// For 64-bit timer counter// For 16-bit timer prescaler up to 1024// Interval in microsecs// 下面定时器间隔设置为1000000微秒,即1秒if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0)){// 如果定时器中断设置成功,则串口打印定时器设置成功的信息,并打印板子运行时间Serial.print(F("Starting ITimer0 OK, millis() = "));Serial.println(millis());}else// 否则打印定时器无法设置Serial.println(F("Can't set ITimer0. Select another freq. or timer"));// Interval in microsecsif (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1)){Serial.print(F("Starting ITimer1 OK, millis() = "));Serial.println(millis());}elseSerial.println(F("Can't set ITimer1. Select another freq. or timer"));Serial.flush();
}
编写循环函数
void loop()
{static unsigned long lastTimer0 = 0;static unsigned long lastTimer1 = 0;static bool timer0Stopped = false;static bool timer1Stopped = false;if (millis() - lastTimer0 > TIMER0_DURATION_MS){// 如果板子距离上一次中断触发的时间大于定时器持续时间,则更新lastTimer0的值lastTimer0 = millis(); // 检查定时器是否开启,如果开启就关掉,如果关掉就开启if (timer0Stopped){Serial.print(F("Start ITimer0, millis() = "));Serial.println(millis());ITimer0.restartTimer(); // 重启定时器Timer 0}else{Serial.print(F("Stop ITimer0, millis() = "));Serial.println(millis());ITimer0.stopTimer(); // 关闭定时器Timer 0}// 进行状态转换timer0Stopped = !timer0Stopped;}// 如果板子距离上一次中断触发的时间大于定时器持续时间,则更新lastTimer1的值if (millis() - lastTimer1 > TIMER1_DURATION_MS){lastTimer1 = millis();// 检查定时器是否开启,如果开启就关掉,如果关掉就开启if (timer1Stopped){Serial.print(F("Start ITimer1, millis() = "));Serial.println(millis());ITimer1.restartTimer(); // 重启定时器Timer 1}else{Serial.print(F("Stop ITimer1, millis() = "));Serial.println(millis());ITimer1.stopTimer(); // 关闭定时器Timer 1}timer1Stopped = !timer1Stopped;}
}
完整代码
#include "ESP32TimerInterrupt.h"// Don't use PIN_D1 in core v2.0.0 and v2.0.1. Check https://github.com/espressif/arduino-esp32/issues/5868
// Don't use PIN_D2 with ESP32_C3 (crash)
#define PIN_D19 19 // Pin D19 mapped to pin GPIO9 of ESP32
#define PIN_D3 3 // Pin D3 mapped to pin GPIO3/RX0 of ESP32// With core v2.0.0+, you can't use Serial.print/println in ISR or crash.
// and you can't use float calculation inside ISR
// Only OK in core v1.0.6-
bool IRAM_ATTR TimerHandler0(void * timerNo)
{static bool toggle0 = false;//timer interrupt toggles pin PIN_D19digitalWrite(PIN_D19, toggle0);toggle0 = !toggle0;return true;
}bool IRAM_ATTR TimerHandler1(void * timerNo)
{static bool toggle1 = false;//timer interrupt toggles outputPindigitalWrite(PIN_D3, toggle1);toggle1 = !toggle1;return true;
}#define TIMER0_INTERVAL_MS 1000
#define TIMER0_DURATION_MS 5000#define TIMER1_INTERVAL_MS 3000
#define TIMER1_DURATION_MS 15000// Init ESP32 timer 0 and 1
ESP32Timer ITimer0(0);
ESP32Timer ITimer1(1);void setup()
{pinMode(PIN_D19, OUTPUT);pinMode(PIN_D3, OUTPUT);Serial.begin(115200);while (!Serial && millis() < 5000);delay(500);Serial.print(F("\nStarting TimerInterruptTest on "));Serial.println(ARDUINO_BOARD);Serial.println(ESP32_TIMER_INTERRUPT_VERSION);Serial.print(F("CPU Frequency = "));Serial.print(F_CPU / 1000000);Serial.println(F(" MHz"));// Using ESP32 => 80 / 160 / 240MHz CPU clock ,// For 64-bit timer counter// For 16-bit timer prescaler up to 1024// Interval in microsecsif (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0)){Serial.print(F("Starting ITimer0 OK, millis() = "));Serial.println(millis());}elseSerial.println(F("Can't set ITimer0. Select another freq. or timer"));// Interval in microsecsif (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1)){Serial.print(F("Starting ITimer1 OK, millis() = "));Serial.println(millis());}elseSerial.println(F("Can't set ITimer1. Select another freq. or timer"));Serial.flush();
}void loop()
{static unsigned long lastTimer0 = 0;static unsigned long lastTimer1 = 0;static bool timer0Stopped = false;static bool timer1Stopped = false;if (millis() - lastTimer0 > TIMER0_DURATION_MS){lastTimer0 = millis();if (timer0Stopped){Serial.print(F("Start ITimer0, millis() = "));Serial.println(millis());ITimer0.restartTimer();}else{Serial.print(F("Stop ITimer0, millis() = "));Serial.println(millis());ITimer0.stopTimer();}timer0Stopped = !timer0Stopped;}if (millis() - lastTimer1 > TIMER1_DURATION_MS){lastTimer1 = millis();if (timer1Stopped){Serial.print(F("Start ITimer1, millis() = "));Serial.println(millis());ITimer1.restartTimer();}else{Serial.print(F("Stop ITimer1, millis() = "));Serial.println(millis());ITimer1.stopTimer();}timer1Stopped = !timer1Stopped;}
}