ESP32开发——关于ESP32TimerInterrupt库的例程分析

最近在学习嵌入式开发的内容,正好有一个开发任务涉及到对于定时器中断的使用,今天正好找到了这个相关的库: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_D19
	digitalWrite(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 outputPin
	digitalWrite(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 microsecs
	if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
	{
		Serial.print(F("Starting  ITimer1 OK, millis() = "));
		Serial.println(millis());
	}
	else
		Serial.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_D19
	digitalWrite(PIN_D19, toggle0);
	toggle0 = !toggle0;

	return true;
}

bool IRAM_ATTR TimerHandler1(void * timerNo)
{
	static bool toggle1 = false;

	//timer interrupt toggles outputPin
	digitalWrite(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 microsecs
	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 microsecs
	if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS * 1000, TimerHandler1))
	{
		Serial.print(F("Starting  ITimer1 OK, millis() = "));
		Serial.println(millis());
	}
	else
		Serial.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;
	}
}
上面的完整代码在arduino IDE中安装好定时器中断的库后,即可编译,烧录进ESP32中即可运行!
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

loveCC_orange

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

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

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

打赏作者

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

抵扣说明:

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

余额充值