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中即可运行!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/635046.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

提升代码简洁,MVEL 表达式和责任链设计模式应用实践

导读 本文主要讲解了MVEL表达式和责任链设计模式相结合一起的消息处理解决方案设计、解耦消息处理节点以及方便代码维护扩展。通过“订单拆单消息”的接入作为具体实践案例&#xff0c;简要阐述了MVEL表达式和Apache Chain职责链设计模式应用场景。希望通过本文&#xff0c;读…

实战Java虚拟机-高级篇

一、GraalVM 什么是GraalVM GraalVM是Oracle官方推出的一款高性能JDK&#xff0c;使用它享受比OpenJDK或者OracleJDK更好的性能。GraalVM的官方网址&#xff1a;https://www.graalvm.org/官方标语&#xff1a;Build faster, smaller, leaner applications。 更低的CPU、内存…

力扣第206题-反转链表

反转链表的效果示意图 要改变链表结构时&#xff0c;通常加入一个创建的临时头结点会更容易操作 时间复杂度&#xff1a;遍历2遍&#xff0c;2n 空间复杂度&#xff1a;额外创建一个栈&#xff0c;n (空间创建一个数组长度最大为5000&#xff0c;你说这个数组是栈也可以&…

5.17 作业+思维导图+模拟面试

// tcp_ser.c #include <myheader.h>#define SER_PORT 8888 #define SER_IP "192.168.125.109"int newfd, sfd;int main(int argc, const char *argv[]) {//1、为通信创建一个端点sfd socket(AF_INET, SOCK_STREAM, 0);//参数1&#xff1a;说明使用的是ipv4通…

2024中青杯数学建模C题:“X 疾病”在人群中的传播代码论文思路分析

2024中青杯数学建模C题论文和代码已完成&#xff0c;代码为C题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建立和求解、问题2模型的建立和求解、问题3模型的建立和求解&#xff09;、模型的评价…

激光雷达在AGV(自动化导引车)中的应用

激光雷达在AGV&#xff08;自动化导引车&#xff09;中的应用主要体现在智能导航和避障功能上&#xff0c;具体来说有以下几个方面&#xff1a; 精确导航&#xff1a;激光雷达能够实时扫描周围环境&#xff0c;建立详细的三维地图&#xff0c;并与AGV的定位系统相结合&#xf…

如何利用Ubuntu服务器运行深度学习项目?

一、整体思路 先配置好服务器端的软件环境&#xff08;工程源码&#xff0c;miniconda&#xff0c;cuda&#xff0c;显卡驱动等&#xff09;&#xff0c;然后用自己电脑的pycharm远程连接服务器运行代码。一句话总结&#xff1a;借用服务器资源运行代码&#xff0c;本地pycharm…

Linux —— 线程同步

Linux —— 线程同步 死锁线程同步条件变量pthread_cond_waitpthread_cond_signal初始状态为什么之后会“阻塞”如何修改以持续运行 pthread_cond_broadcast 条件变量的接口抢票模拟 我们今天接着来了解线程&#xff1a; 死锁 死锁&#xff08;Deadlock&#xff09;是计算机科…

配置旁挂二层组网直接转发示例(命令行)

业务需求 企业用户通过WLAN接入网络&#xff0c;以满足移动办公的最基本需求。且在覆盖区域内移动发生漫游时&#xff0c;不影响用户的业务使用。 组网需求 AC组网方式&#xff1a;旁挂二层组网。DHCP部署方式&#xff1a; AC作为DHCP服务器为AP分配IP地址。汇聚交换机SwitchB作…

《Effective Objective-C 2.0》读书笔记——熟悉Objective-C

目录 第一章&#xff1a;熟悉Objective-C第1条&#xff1a;了解Objective-C语言的起源第2条&#xff1a;在类的头文件中尽量少引入其他头文件第3条&#xff1a;多用字面量语法&#xff0c;少用与之等价的方法第4条&#xff1a;多用类型常量&#xff0c;少用#define预处理指令第…

记录docker ps查找指定容器的几个命令

1.docker ps | grep registry 查询包含registry的容器 2.docker ps | grep -E "reigistry\s" 开启正则匹配模式&#xff0c;匹配registry后面为空格的容器&#xff0c;若是匹配一整行可以这样写docker ps | grep -E "^([0-9a-f]{12})\sregistry\s.*" 这…

Nacos 2.x 系列【2】单机部署

文章目录 1. 准备工作2. Windows2.1 下载2.2 目录 & 文件2.3 启动2.4 控制台 3. Linux&#xff08;CentOS&#xff09; 1. 准备工作 Nacos服务端支持三种部署模式&#xff1a; 单机模式&#xff1a;用于测试和单机试用。集群模式&#xff1a;用于生产环境&#xff0c;确保…

Elasticsearch集群和Logstash、Kibana部署

1、 Elasticsearch集群部署 服务器 安装软件主机名IP地址系统版本配置ElasticsearchElk10.3.145.14centos7.5.18042核4GElasticsearchEs110.3.145.56centos7.5.18042核3GElasticsearchEs210.3.145.57centos7.5.18042核3G 软件版本&#xff1a;elasticsearch-7.13.2.tar.gz 示…

Little Snitch for Mac(小飞贼防火墙软件)v5.7.6注册激活版

Little Snitch for Mac&#xff0c;也被称为“小飞贼”防火墙软件&#xff0c;是一款专为Mac用户设计的网络安全工具。以下是关于Little Snitch for Mac的一些主要特点&#xff1a; Little Snitch for Mac(小飞贼防火墙软件)v5.7.6注册激活版下载 强大的监控能力&#xff1a;Li…

Spring框架中获取方法参数名称:DefaultParameterNameDiscoverer

DefaultParameterNameDiscoverer 是Spring框架中用于获取方法参数名称的一个类。在Java中&#xff0c;方法的参数名称通常在编译时会丢失&#xff0c;因为Java字节码并不强制要求保留这些信息。Spring提供了一种机制来恢复这些参数名称&#xff0c;这就是通过DefaultParameterN…

【C++】 单例设计模式的讲解

前言 在我们的学习中不免会遇到一些要设计一些特殊的类&#xff0c;要求这些类只能在内存中特定的位置创建对象&#xff0c;这就需要我们对类进行一些特殊的处理&#xff0c;那我们该如何解决呢&#xff1f; 目录 1. 特殊类的设计1.1 设计一个类&#xff0c;不能被拷贝&#xf…

阿木实验室联合openEuler开源社区-Embedded SlG组(海思项目)参加第五届「开源之夏」,参赛学生火热招募中...

开源之夏是中国科学院软件研究所发起的“开源软件供应链点亮计划”系列暑期活动&#xff0c;旨在鼓励高校学生积极参与开源软件的开发维护&#xff0c;促进优秀开源软件社区的蓬勃发展。活动联合各大开源社区&#xff0c;针对重要开源软件的开发与维护提供项目开发任务&#xf…

bugku 网络安全事件应急响应

开启靶场&#xff1a; 开始实验&#xff1a; 使用Xshell登录服务器&#xff0c;账号及密码如上图。 1、提交攻击者的IP地址 WP: 找到服务器日志路径&#xff0c;通常是在/var/log/&#xff0c;使用cd /var/log/&#xff0c;ls查看此路径下的文件. 找到nginx文件夹。 进入ng…

LabVIEW超高温高压流变仪测试系统

LabVIEW超高温高压流变仪测试系统 超高温高压流变仪广泛应用于石油、天然气、化工等行业&#xff0c;用于测量材料在极端条件下的流变特性。随着计算机技术、测试技术和电子仪器技术的快速发展&#xff0c;传统的流变仪测试方式已无法满足现代工业的需求。因此&#xff0c;开发…

Java——通过方法交换实参值

想写一个方法来交换main函数中的两个变量值&#xff0c;代码如下&#xff1a; public class Test {public static void swap(int x,int y) {int tmp x;x y;y tmp;}public static void main(String[] args) {int a 10;int b 20;System.out.println("交换前&#xff1…