Arduino UNO R3自学笔记17 之 Arduino为啥要用中断?

news/2024/10/4 15:08:01/

注意:学习和写作过程中,部分资料搜集于互联网,如有侵权请联系删除。

前言:学习Arduino中断的概念及其功能。

1.什么是中断?

        单片机在执行程序时,发生一些其它紧急的事情,单片机将立即暂停当前程序,赶去处理中断程序,处理完中断程序后再返回刚才暂停处接着执行原来的程序。这个过程称之为中断

        举个通俗易懂的例子:当你在看电视的时候,突然电话响了,你去接电话。接完电话回来继续看电视,这就是一个中断过程。我们以此为例分析一下:

                                          主进程:看电视;

                                          中断触发源:电话响了;

                                          中断服务子程序:接电话;

   通过上述例子我们了解了一些术语,以及中断这个过程。

        思考一个问题,当在上述接电话的时候厨房的燃气报警器突然报警,是不是我们会立即挂掉电话去处理燃气的报警问题,在这个过程中出现了,在中断中又发生了中断,我们称之为中断嵌套,燃气报警器突然报警这个事件的后果很严重,因此我们挂了电话去执行检查开窗通风等操作,在这个过程中,我们认识到这个燃气报警器突然报警这个事件更加需要紧急处理,电话事件次之,看电视事件 紧急程度最低,这种紧急处理的排序就称之为  中断优先级

2.为什么要用中断?

        中断系统的主要目的:

                ●提高系统效率。

                ●维持系统可靠正常工作。

                ●满足实时处理要求。

                ●提供故障现场处理手段。

          为什么要用中断?为此我们继续做一个程序案例进行分析。

3.实验硬件及代码测试

硬件连接图:

代码:

void setup()
{  Serial.begin(115200); //初始化串口,使用波特率115200,其余默认
Serial.println("Hello, I'm in a terminal!");
Serial.println();
pinMode(2, INPUT);
}
void loop()
{static uint32_t lastMillis = 0; //用于存储第一次获取的运行时间static uint32_t time0 = 0;      //用于存储时间差//A
/*lastMillis = micros();          //获取运行时间for(unsigned int m=0;m<10000;m++)  //一个嵌套,消耗CPU时间{for(unsigned int n=0;n<10000;n++){__asm__ __volatile__ ("nop"); //这是一个空指令,但是会花费一个周期去执行}}
//B
*/time0=micros() - lastMillis;  //计算A到B的执行时间差Serial.print("程序A点运行到B点耗时:  ");Serial.print(time0/1000000);Serial.println("秒");
if(digitalRead(2)==0) Serial.println("按钮被按下!");delay(200);
}

  测试视频如下:

        通过视频我们看出按钮硬件及软件上监测是没有问题的(我们屏蔽了A到B 的代码是为了测试其余代码的正确)。

4.案例分析

直接给出如下代码:

void setup()
{  Serial.begin(115200); //初始化串口,使用波特率115200,其余默认
Serial.println("Hello, I'm in a terminal!");
Serial.println();
}
void loop()
{static uint32_t lastMillis = 0; //用于存储第一次获取的运行时间static uint32_t time0 = 0;      //用于存储时间差//AlastMillis = micros();          //获取运行时间for(unsigned int m=0;m<10000;m++)  //一个嵌套,消耗CPU时间{for(unsigned int n=0;n<10000;n++){__asm__ __volatile__ ("nop"); //这是一个空指令,但是会花费一个周期去执行}}
//Btime0=micros() - lastMillis;  //计算A到B的执行时间差delay(200);Serial.print("程序A点运行到B点耗时:  ");Serial.print(time0/1000000);Serial.println("秒");
}

仿真运行效果:上述程序执行后,程序A点运行到B点耗时: 31秒。

        也就是说当有扫描式按钮在主程序等待被监测按下按钮这个动作时,至少会被阻塞31秒,也就是说,在那31秒内按钮按下也不会被监测到!当然一般程序不会有这种情况存在(阻塞31秒),这里将阻塞时间做了放大,实际可能阻塞有几秒钟,但是这种阻塞是非常不利于程序的实时性。

        此时我们再做一个按钮按下监测实验,不屏蔽阻塞代码,看阻塞代码对此按键扫描的影响。

        调整后代码如下:

void setup()
{  Serial.begin(115200); //初始化串口,使用波特率115200,其余默认
Serial.println("Hello, I'm in a terminal!");
Serial.println();
pinMode(2, INPUT);
}
void loop()
{static uint32_t lastMillis = 0; //用于存储第一次获取的运行时间static uint32_t time0 = 0;      //用于存储时间差//AlastMillis = micros();          //获取运行时间for(unsigned int m=0;m<1600;m++)  //一个嵌套,消耗CPU时间{for(unsigned int n=0;n<10000;n++){__asm__ __volatile__ ("nop"); //这是一个空指令,但是会花费一个周期去执行}}
//Btime0=micros() - lastMillis;  //计算A到B的执行时间差Serial.print("程序A点运行到B点耗时:  ");Serial.print(time0/1000000);Serial.println("秒");
if(digitalRead(2)==0) Serial.println("按钮被按下!");delay(200);
}

注意:上述代码,我把阻塞时间调整了一下,由原来31秒调整到了5秒,好录测试视频。

测试视频如下:

        通过上述仿真视频看到,阻塞非常严重,你在设备端不断按按钮,但是系统却没检测到!这样的系统实时性就非常的差,操作体验感不佳!

        我们修改代码,用中断的方式监测按钮按下,硬件不变,代码如下:

void btn_press();
void setup()
{  Serial.begin(115200); //初始化串口,使用波特率115200,其余默认
Serial.println("Hello, I'm in a terminal!");
Serial.println();
attachInterrupt(0, btn_press, LOW);//引脚20外部中断
}
void loop()
{static uint32_t lastMillis = 0; //用于存储第一次获取的运行时间static uint32_t time0 = 0;      //用于存储时间差//AlastMillis = micros();          //获取运行时间for(unsigned int m=0;m<10000;m++)  //一个嵌套,消耗CPU时间{for(unsigned int n=0;n<10000;n++){__asm__ __volatile__ ("nop"); //这是一个空指令,但是会花费一个周期去执行}}
//Btime0=micros() - lastMillis;  //计算A到B的执行时间差Serial.print("程序A点运行到B点耗时:  ");Serial.print(time0/1000000);Serial.println("秒"); delay(200);
}
void btn_press()
{Serial.println("按钮被按下!");  
}

测试视频如下:

按钮中断实时性测试

可以看到实时性非常强,基本和按下是同步检测到的!,这就是中断的优势。这也就是为什么用中断的缘故,Arduino的中断相关知识下一篇细讲。

上一篇:Arduino UNO R3自学笔记16 之 Arduino的定时器介绍及应用

下一篇:Arduino UNO R3自学笔记18 之 Arduino的外部中断、定时中断介绍及应用


http://www.ppmy.cn/news/1534475.html

相关文章

Python编码系列—Python访问者模式:为对象结构添加新功能的艺术

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

工作笔记20240927——vscode + jlink调试

launch.json的配置&#xff0c;可以用的 {"name": "Debug","type": "cppdbg","request": "launch","miDebuggerPath": "./arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-g…

看480p、720p、1080p、2k、4k、视频一般需要多大带宽呢?

看视频都喜欢看高清&#xff0c;那么一般来说看电影不卡顿需要多大带宽呢&#xff1f; 以4K为例&#xff0c;这里引用一位网友的回答&#xff1a;“视频分辨率4092*2160&#xff0c;每个像素用红蓝绿三个256色(8bit)的数据表示&#xff0c;视频帧数为60fps&#xff0c;那么一秒…

Spring:强制登陆与拦截器

1.只使用session验证 &#xff08;1&#xff09;第一步&#xff1a;用户登陆时存储session ApiOperation("用户登陆") PostMapping("/login") public AppResult login(HttpServletRequest request,RequestParam("username") ApiParam("用…

C++——函数功能是:将两个两位数的正整数a、b合并成一个整数c,合并规则是将a的十位和个位分别放在c的千位和个位,将b的十位和个位分别放在c的十位和百位。

没注释的源代码 #include <iostream> using namespace std; int he(int x,int y); int main() { int a,b; cout<<"请输入两个两位数的正整数:"; cin>>a>>b; cout<<"合并结果为:"<<he(a,b); return 0; } int he(i…

【rCore OS 开源操作系统】Rust 字符串(可变字符串String与字符串切片str)

【rCore OS 开源操作系统】Rust 语法详解: Strings 前言 这次涉及到的题目相对来说比较有深度&#xff0c;涉及到 Rust 新手们容易困惑的点。 这一次在直接开始做题之前&#xff0c;先来学习下字符串相关的知识。 Rust 的字符串 Rust中“字符串”这个概念涉及多种类型&…

使用RestTemplate调用EMQX API查询MQTT客户端列表信息

项目中集成mqtt客户端查询功能&#xff0c;使用到了EMQX api-v5&#xff0c;具体步骤&#xff1a; 一、准备工作 首先在EMQX dashboard中添加API 密钥 填写密钥名称&#xff0c;点击确定&#xff0c;会生成API Key和Secret Key&#xff0c;保存起来备用。 二、配置文件 在…

Stable Diffusion绘画 | 插件-Deforum:动态视频生成(终篇)

Deforum 中其他模块主要是服务于上传视频的&#xff0c;而视频转绘有其他效果更好的插件。 初始化 除了 图像初始化 模块&#xff0c;其他模块都用不上&#xff1a; 上一篇文章生成的视频&#xff0c;都用了图像初始化功能。 像我这样&#xff0c;拖入一张图片&#xff0c;D…