文章目录
-
- 前言
- CPU中断
- Arduino中断
- 触发原理
- 在setup函数中配置中断
- 附录
前言
无论是在现代PC中,还是在嵌入式系统中(如Arduino,51单片机,还是stm32),中断都是重要的概念,此文我将介绍中断的原理与其在Arduino中的应用
CPU中断
中断是指计算机在执行当前程序的过程中,当出现某些紧急或需要立即处理的事件时,暂时停止正在执行的程序,转而去处理这些事件,待处理完成后再返回原来的程序继续执行的过程。
中断中断可以分为内中断和外中断
内中断:中断信号来源于CPU内部
例1:当CPU处在用户态时执行特权指令
例2:执行除法时发现除数为0
例3:应用程序想要请求操作系统内核的服务,会执行陷入指令
以上三个例子会引发中断信号,CPU会立即处理该中断
外中断:中断信号来源于CPU外部
例1:时钟中断-------由CPU时钟部件引发的
例2:I/O中断------由输入输出设备引发的中断信号
Arduino中断
触发原理
Arduino中断有两种种方式,时钟中断和外部中断,此文我只介绍外部中断,因为时钟中断并不常见。
常见的Arduino板是UNO板,它有外部中断引脚,2和3,分别产生的中断信号是0和1
只有使用正确的引脚才能触发中断
常见的中断触发模式如下:
在setup函数中配置中断:
void setup()
{
attachTnterrupt(中断编号,中断函数,中断触发模式)
}
例如:attachInterrupt(0,onChange,Change)
中断编号0对应的是2号引脚,Change是电平改变时触发,当触发中断时会调用onCHange函数
如果觉得要查引脚号对应的中断号麻烦的话,可以用digitalPinToInterrupt(引脚号)函数 ,例如:
attachInterrupt(digitalPinToInterrupt(2),onChange,Change)
项目实例
下面用所学知识做一个项目,用按钮控制LED的亮灭,代码如下:
const int ledPin = 8;//定义led引脚,const使ledPin的值无法修改,防止程序被意外修改
const int buttonPin = 2;//定义按钮引脚为2
volatile bool ledState = LOW;
/*volatile用于修饰可能被意外修改的值,保证主程序和中断服务函数能正确访问和修改变量*/
void led_change(){
ledState=!ledState; //对ledState的状态取反
digitalWrite(ledPin,ledState);
}
void setup() {
pinMode(ledPin,OUTPUT);
pinMode(buttonPin,INPUT);
attachInterrupt(digitalPinToInterrupt(buttonPin),led_change,FALLING);//设置中断函数
}
void loop() {
//此处可以正常运行其他程序,只有当中断触发时,Arduino才会执行中断程序
}
但这个代码是不完善的,因为普通按钮会发生抖动, 因而需要加入消抖逻辑:
millis()是arduino中的一个非常实用的函数,用于返回Arduino板通电以来经过的时间(unsigned int类型),单位是毫秒,例如:
unsigned long startTime = millis(); //用于记录arduino板当前时间
unsigned long elapseTime = millis() - startTime; //用于计算从记录的时间到现在所经过的时间
改进后的代码如下:
const int ledPin = 8;
const int buttonPin = 2;
volatile bool ledState = LOW;
unsigned long lastDebounceTime = 0; //记录上次按下的时间
unsigned long debounceDelay = 50; //在触发中断的50毫秒内不再触发中断
void led_change() {
if (millis() - lastDebounceTime > debounceDelay) {
ledState =!ledState;
digitalWrite(ledPin, ledState);
lastDebounceTime = millis();
}
}
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(buttonPin), led_change, CHANGE);
}
void loop() {
}
附录 :
(1)detachInterrupt()
取消中断函数。
函数原型:
void detachInterrupt(uint8_t interruptNum)
例子:
detachInterrupt(digitalPinToInterrupt(2));//取消2号引脚的中断
(2)interrupts()
重新启用中断。中断允许一些重要任务在后台运行,默认状态是启用的。禁用中断后一些函数可能无法工作,并且传入信息可能会被忽略。
函数原型:
#define interrupts() sei()
参数:无
(3)noInterrupts()
禁止中断。
函数原型:
#define noInterrupts() cli()
参数:无