ESP32入门七(中断)

news2025/2/27 23:20:25

中断用于处理在程序正常执行期间通过外部事件或者响应软件指令触发时发生的事件。比如,在一段呼吸灯的代码中,正常运行时的结果为LED从暗到亮,再从亮到暗持续地运行。我们可以通过一个中断来控制呼吸灯的运行和停止。使用中断功能,我们就不需要不停地监控一个引脚的状态,当中断被触发,内部控制器停止执行主程序,并调用中断服务例程 (ISR) 。

中断服务例程 (ISR)

中断服务例程 (ISR)是特殊类型的函数,它有一些特殊的特点和规则:

1、将部分内部 SRAM0 区域分配给IRAM,可以显著减少运行的迟延。

2、必须将中断服务例程 (ISR)放入 IRAM。

3、中断服务例程 (ISR)不能有任何参数,也不返回任何值。

4、因为中断服务例程 (ISR)会中断主程序的运行,运行时间过长会对主程序形成阻塞,所以中断服务例程 (ISR)尽可能短和快。

在IRAM中放置代码,可以使用 IRAM_ATTR 宏在源代码中指定该函数放置到IRAM中,如:

void IRAM_ATTR ISR_function()
{
        // ...
}

我们在使用中断功能时,会使用一个名为attachInterrupt()的函数个设置引脚中断。

函数:attachInterrupt

作用:用于将中断附加到定义的引脚。

格式:attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode);

参数:

        pin                         -定义监控的GPIO 引脚号。

        handler                  -设置中断服务例程 (ISR)

        mode                     -设置中断模式
                LOW                 -低电平触发
                CHANGE          -管脚电平变化,触发
                HIGH                -高电平触发
                RISING            -管脚从低电平变化高电平触发,即上升沿触发
                FALLING         -下降沿触发,电平从高变低

示例代码

我们需要定义一个引脚来用于中断服务,这里选择4号引脚:

int interrupt_pin = 4;          //引脚号

 下面需要要定义一个计数器来记录中断的次数,默认设为0:

int interrupt_counter = 0;      //中断次数计数器

定义一个开关标记来记录中断时的开关状态:

bool press_down;                //中断标记开关

定义一个ISR函数,放置到IRAM:

void  IRAM_ATTR ISR_function(){
  interrupt_counter++;          //中断次数计数器累加
  press_down = true;            //中断标记开关设为开
}

我们需要使用上面所介绍的attachInterrupt函数来把中断服务附加到指定的引脚:

attachInterrupt(interrupt_pin, ISR_function, FALLING);  //中断附加到引脚

以下为硬件的连接和完整的代码:

int interrupt_pin = 4;          //引脚号
int interrupt_counter = 0;      //中断次数计数器
bool press_down;                //中断标记开关

void  IRAM_ATTR ISR_function(){
  interrupt_counter++;          //中断次数计数器累加
  press_down = true;            //中断标记开关设为开
}

void setup() {
  Serial.begin(115200);
  pinMode(interrupt_pin,INPUT_PULLUP);  //引脚初始化为输入上拉模式
  attachInterrupt(interrupt_pin, ISR_function, FALLING);  //中断附加到引脚
}

void loop() {
  if(press_down){                       //如果中断标记开关为开状态
    Serial.print("发生中断事件:");        
    Serial.println(interrupt_counter);  //串口输出计数器的值
    press_down = false;                 //中断标记开关设为关
  }
}

代码说明

在该例程中,我们设置监控4号引脚来触发中断服务。

我们把4号引脚设置为输入上拉模式,当开机时,4号引脚为高电平状态。

4号引脚通过一个开关与GND引脚连接,当开关按下时,4号引脚由高电平变为低电平状态。

这时,触发中断,主程序中断,进入ISR_function函数,函数功能包括给计数器累加中断次数和中断标记开关设置为开。

中断标记为开时满足if(press_down)条件,进入分支,串口此时输出计数器的值,并设置中断标记开关为关闭状态。

测试代码

运行该代码,打开串口监视器,按下开关,可以观察到计数器的变化:

同时,我们也会发现,有时即使只按一次开关,也会出现计数据多次增加。这是同于硬件生产工艺的原因造成的,我们在直观上感觉只按了一次开关,但在十分微小的时间里,开关的接触弹片可能进行了多次的接触。释放按钮时也会发生同样的事情。在生产中,工艺上是无法达到理想的完美状态的。以致产生了这种名为"开关抖动"的现象。我们可以通过硬件或软件的方式来消除这种抖动。

消除开关抖动

我们在上面的例程中加入添加代码,以软件的方式来消除开关抖动。实现每按一次开只允许动行一次ISR程序:

int interrupt_pin = 4;          //引脚号
int interrupt_counter = 0;      //中断次数计数器
bool press_down = false  ;                //中断标记开关

void  IRAM_ATTR ISR_function(){
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  if(interruptTime - lastInterruptTime >200){
      press_down = true;                //中断标记开关设为开
      interrupt_counter++;
  }
  lastInterruptTime = interruptTime;
}

void setup() {
  Serial.begin(115200);
  pinMode(interrupt_pin,INPUT_PULLUP);  //引脚初始化为输入上拉模式
  attachInterrupt(interrupt_pin, ISR_function, FALLING);  //中断附加到引脚
}

void loop() {
  if(press_down){                       //如果中断标记开关为开状态
    Serial.print("发生中断事件:");        
    Serial.println(interrupt_counter);  //串口输出计数器的值
    press_down = false;                 //中断标记开关设为关
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux操作系统( YUM软件仓库技术 )

镜像文件的回环挂载(把iso镜像文件释放成系统安装光盘)foundation0上操作 回环挂载的用法: du -sh 对象名 //估算文件(一切对象皆文件)大小 !$ //上一条命令的最后一个参数 新创建的挂载点目录是空白目录 挂载&#xf…

移动端开发框架mui代码在安卓模拟器上运行(HbuilderX连接到模拟器)

开发工具 HBuilder X 3.8.12.20230817 注意:开发工具尽量用最新的或较新的。太旧的版本在开发调试过程中可能会出现莫名其妙的问题。 1、电脑下载安装安卓模拟器 我这里使用的是 夜神模拟器 ,也可以选择其他安卓模拟器 夜神模拟器官网:夜神安…

Python教程(19)——python异常处理

异常处理 什么是异常异常处理方式try-except语句捕获异常类型 相关的异常类型 什么是异常 在计算机编程中,异常(Exception)是指在程序执行过程中发生的错误或异常情况。当出现异常时,程序无法正常继续执行,因此需要采…

【linux】tail的基本使用

在linux可以用find查找一个文件,可以用grep查找符合要求的文件内容,但是有的时候希望查看文件的前几行或者后几行(其实这种场景经常可以遇到,比如接触到日志分析的时候),那就应该使用head和tail这两个工具了…

亲爱的程序猿们,元旦快乐!

新年祝福 在这个充满欢笑和祝福的日子里,我想对你们说: 新的一年,愿你们像代码一样充满逻辑,像算法一样追求高效,像编程语言一样多样化! 2024年即将到来,预测几个行业趋势: 人工…

SpringBoot+拦截器(Interceptor)

记录一下SpringBoot的拦截器(Interceptor)使用 拦截器(Interceptor)是AOP面向切面编程的思想来实现的,对于只写代码的来说,具体如何实现不需要多关心,只需要关心如何去使用,会用在那些地方。 当http请求进入Springboot应用程序后…

第一部分 随机事件和概率

目录 无放回题目(一次摸多个) 方法: 例1 有放回题目(进行多次,每次情况一致) 方法: 例2 事件的概率 方法: 例3 条件概率 方法: 例4 全概率公式 方法: 例5 贝叶斯公式 方法: 例6 无放回题目(…

方太厨电,在创新科技中看见烟火人间

人类的历史,就是一部创新的历史。科普作者马特里德利在《创新的起源:一部科学技术进步史》写道:能源是所有创新之源。 火的发明和使用,就是一种创新,人类第一次通过控制热量的转换来做功,依靠火来取暖和烹饪…

使用频率分析求周期性

通常很难通过观察时间测量值来表征数据中的振荡行为。频谱分析有助于确定信号是否为周期性信号并测量不同周期。 办公楼内的温度计每半小时测量一次室内温度,持续四个月。加载数据并对其绘图。将温度转换为摄氏度。测量时间以周为单位。因此,采样率为 2 …

高并发处理专题研究 - epoll并发编程[更新中]

文章目录 1 前置知识1.1 Socket编程基础Socket概述Socket通信模型Socket API一个简单的Socket编程实例 1.2 IO多路复用1.3 阻塞原理 2 epoll原理2.1 epoll概述2.2 epoll系统调用epoll_create()epoll_ctl()epoll_wait() 2.3 epoll工作原理 3 示例代码及演示 1 前置知识 1.1 Soc…

Oracle初始化参数修改后,是否需要重启才能生效

可以查看 v$parameter或v$parameter2动态性能视图的ISSYS_MODIFIABLE列。此列指示是否可以使用 ALTER SYSTEM 更改参数以及更改何时生效: IMMEDIATE - 无论用于启动实例的参数文件的类型如何,都可以使用 ALTER SYSTEM 更改参数。 更改立即生效。DEFERRE…

spring核心与思想

spring核心与思想 Spring 是什么?什么是容器?什么是 IoC?传统程序开发传统程序开发的缺陷解决传统开发中的缺陷控制反转式程序开发对⽐总结规律 理解 Spring IoCDI 概念说明 Spring 是什么? Spring 指的是 Spring Framework&…

青龙面板的安装

一、安装docker 首先,需要在服务器上安装docker。 没有服务器的可以使用虚拟机,或申请一台三丰云的免费云服务器体验一下,独立IP地址,送免备案服务,可以满足基本的使用,三丰云上还有免费虚拟主机等其他免费…

【Vue2+3入门到实战】(18)VUE之Vuex状态管理器概述、VueX的安装、核心概念 State状态代码实现 详细讲解

目录 一、[Vuex](https://vuex.vuejs.org/zh/) 概述1.是什么2.使用场景3.优势4.注意: 二、需求: 多组件共享数据1.创建项目2.创建三个组件, 目录如下3.源代码如下 三、vuex 的使用 - 创建仓库1.安装 vuex2.新建 store/index.js 专门存放 vuex3.创建仓库 store/index…

下载大模型,保存阿里云盘

一、解决场景 下载模型或数据集,到国内云GPU平台、阿里云盘(便于持久化储存,或者分享朋友)。 及时收藏,下次还能找到! 二、优势 此方法可以避免大文件下载到本地——占用内存,受到小带宽网络…

SpringBoot定时监听RocketMQ的NameServer

问题分析 自己在测试环境部署了RocketMQ,发现namesrv很容易挂掉,于是就想着监控,挂了就发邮件通知。查看了rocketmq-dashboard项目,发现只能监控Broker,遂放弃这一路径。于是就从报错的日志入手,发现最终可…

vue整理面试题

1. v-if/v-show的区别? v-if"表达式" 当表达式值true,v-if所作用的元素显示 否则隐藏 v-show"表达式" 当表达式值true,v-if所作用的元素显示 否则隐藏 理解: v-if控制元素显示与隐藏,通过js创建dom元素或删除…

用通俗易懂的方式讲解大模型:ChatGLM3-6B 部署指南

最近智谱 AI 对底层大模型又进行了一次升级,ChatGLM3-6B 正式发布,不仅在性能测试和各种测评的数据上有显著提升,还新增了一些新功能,包括工具调用、代码解释器等,最重要的一点是还是保持 6B 的这种低参数量&#xff0…

阿里员工:本月收入489325元,开心过年

阿里员工:本月收入489325元,开心过年 近日,一名阿里员工在社交媒体上爆料自己的本月收入,竟然高达48.9万,真是让人目瞪口呆。 震惊之余,大家都很好奇这么高收入是怎么来的,再仔细看工资单&…

C++初阶——基础知识(内联函数)

目录 1.内联函数 内联函数的示例代码 1.内联函数 是一种 C 中的函数定义方式,它告诉编译器在每个调用点上插入函数体的副本,而不是像普通函数那样在调用时跳转到函数体所在的地址执行。这样可以减少函数调用的开销,提高程序的执行效率。 …