注意:学习和写作过程中,部分资料搜集于互联网,如有侵权请联系删除。
前言:学习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; //用于存储时间差
//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的执行时间差
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; //用于存储时间差
//A
lastMillis = micros(); //获取运行时间
for(unsigned int m=0;m<1600;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);
}
注意:上述代码,我把阻塞时间调整了一下,由原来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; //用于存储时间差
//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("秒");
delay(200);
}
void btn_press()
{
Serial.println("按钮被按下!");
}
测试视频如下:
按钮中断实时性测试
可以看到实时性非常强,基本和按下是同步检测到的!,这就是中断的优势。这也就是为什么用中断的缘故,Arduino的中断相关知识下一篇细讲。
上一篇:Arduino UNO R3自学笔记16 之 Arduino的定时器介绍及应用
下一篇:Arduino UNO R3自学笔记18 之 Arduino的外部中断、定时中断介绍及应用