Arduino 中断
介绍
在Arduino编程中,中断是一种强大的机制,允许微控制器在执行主程序的同时,对外部事件做出快速响应。中断可以暂停当前正在执行的代码,转而执行一个特殊的函数(称为中断服务程序,ISR),然后再返回到原来的代码继续执行。
中断通常用于处理时间敏感的任务,例如读取传感器数据、检测按钮按下或处理外部信号。通过使用中断,Arduino可以更高效地处理这些事件,而不需要不断地轮询输入状态。
中断的基本概念
什么是中断?
中断是一种硬件或软件触发的信号,用于通知微控制器某个事件已经发生。当中断发生时,微控制器会暂停当前的任务,保存当前状态,并跳转到预先定义的中断服务程序(ISR)中执行。执行完ISR后,微控制器会恢复之前的状态,并继续执行主程序。
中断的类型
Arduino支持两种类型的中断:
- 硬件中断:由外部硬件信号触发,例如按钮按下或传感器信号变化。
- 软件中断:由程序内部触发,例如定时器溢出或特定条件满足。
中断的优点
- 实时响应:中断可以立即响应外部事件,而不需要等待主程序轮询。
- 高效性:通过中断处理事件,可以减少CPU的轮询开销。
- 简化代码:中断可以将事件处理逻辑与主程序分离,使代码更清晰。
Arduino 中断的使用
中断引脚
Arduino的不同型号支持不同数量的中断引脚。例如,Arduino Uno有两个外部中断引脚:D2
和D3
。这些引脚可以配置为在信号上升沿、下降沿或电平变化时触发中断。
配置中断
在Arduino中,使用attachInterrupt()
函数来配置中断。该函数的语法如下:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);
pin
:中断引脚号。ISR
:中断服务程序的函数名。mode
:中断触发模式,可以是以下值之一:LOW
:低电平时触发。CHANGE
:电平变化时触发。RISING
:上升沿触发。FALLING
:下降沿触发。
示例:按钮中断
以下是一个简单的示例,展示如何使用中断检测按钮按下:
const int buttonPin = 2; // 按钮连接到D2引脚
volatile bool buttonPressed = false; // 用于存储按钮状态的变量
void setup() {
pinMode(buttonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(buttonPin), buttonISR, FALLING);
Serial.begin(9600);
}
void loop() {
if (buttonPressed) {
Serial.println("Button pressed!");
buttonPressed = false; // 重置按钮状态
}
}
void buttonISR() {
buttonPressed = true; // 在中断中设置按钮状态
}
在这个示例中,当按钮按下时,buttonISR()
函数会被调用,并将buttonPressed
变量设置为true
。主程序在loop()
中检测到这个变化,并打印一条消息。
注意:在中断服务程序(ISR)中,应尽量避免使用delay()
或执行耗时操作,因为这会影响主程序的执行。
实际应用场景
案例1:旋转编码器
旋转编码器是一种常见的输入设备,用于检测旋转方向和速度。通过使用中断,可以实时检测编码器的信号变化,并计算旋转方向和步数。
const int pinA = 2; // 编码器A相连接到D2
const int pinB = 3; // 编码器B相连接到D3
volatile int encoderPos = 0; // 编码器位置
void setup() {
pinMode(pinA, INPUT);
pinMode(pinB, INPUT);
attachInterrupt(digitalPinToInterrupt(pinA), encoderISR, CHANGE);
Serial.begin(9600);
}
void loop() {
Serial.println(encoderPos); // 打印编码器位置
}
void encoderISR() {
int stateA = digitalRead(pinA);
int stateB = digitalRead(pinB);
if (stateA == stateB) {
encoderPos++; // 顺时针旋转
} else {
encoderPos--; // 逆时针旋转
}
}
案例2:超声波传感器
超声波传感器通常用于测量距离。通过使用中断,可以在接收到回波信号时立即计算距离,而不需要等待主程序轮询。
const int trigPin = 9; // 超声波传感器触发引脚
const int echoPin = 2; // 超声波传感器回波引脚
volatile long duration = 0; // 存储回波时间
volatile bool echoReceived = false; // 回波接收标志
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
attachInterrupt(digitalPinToInterrupt(echoPin), echoISR, CHANGE);
Serial.begin(9600);
}
void loop() {
if (echoReceived) {
long distance = duration * 0.034 / 2; // 计算距离
Serial.print("Distance: ");
Serial.println(distance);
echoReceived = false; // 重置标志
}
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
}
void echoISR() {
static unsigned long startTime = 0;
if (digitalRead(echoPin) == HIGH) {
startTime = micros(); // 记录回波开始时间
} else {
duration = micros() - startTime; // 计算回波持续时间
echoReceived = true; // 设置回波接收标志
}
}
总结
中断是Arduino编程中一个强大的工具,可以帮助你实时响应外部事件,提高程序的效率和响应速度。通过合理使用中断,你可以简化代码结构,并处理时间敏感的任务。
提示:在使用中断时,务必注意中断服务程序的执行时间,避免影响主程序的正常运行。
附加资源与练习
- 练习1:修改按钮中断示例,使其在按钮按下时点亮LED灯。
- 练习2:使用中断实现一个简单的计数器,每按一次按钮,计数器加1,并在串口监视器中显示计数值。
- 参考资源:
通过以上内容,你应该对Arduino中断有了初步的了解。继续实践和探索,你将能够更好地掌握这一强大的功能!