Arduino 中断输入
在Arduino编程中,中断输入是一种强大的功能,允许程序在特定事件发生时立即暂停当前任务,转而执行一个特定的函数(称为中断服务程序,ISR)。这种机制非常适合处理需要快速响应的外部事件,例如按钮按下、传感器触发等。
什么是中断?
中断是一种硬件或软件触发的信号,用于通知处理器某个事件已经发生。当Arduino检测到中断信号时,它会暂停当前正在执行的代码,跳转到预先定义的中断服务程序(ISR),执行完ISR后再返回到原来的任务继续执行。
备注
中断的主要优势在于它能够实时响应外部事件,而不需要程序不断轮询(polling)输入状态,从而节省资源并提高效率。
Arduino 中的中断类型
Arduino支持两种主要类型的中断:
- 外部中断:由外部引脚触发,例如按钮按下或传感器信号变化。
- 定时器中断:由内部定时器触发,用于定时任务。
本文将重点介绍外部中断。
如何使用Arduino中断输入
1. 选择支持中断的引脚
并非所有Arduino引脚都支持中断功能。以下是常见Arduino型号支持中断的引脚:
- Arduino Uno/Nano:引脚2和3。
- Arduino Mega:引脚2、3、18、19、20、21。
- Arduino Leonardo:引脚3、2、0、1、7。
警告
不同型号的Arduino支持的中断引脚可能不同,请务必查阅相关文档。
2. 配置中断
在Arduino中,可以使用 attachInterrupt()
函数来配置中断。该函数的语法如下:
cpp
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);
pin
:支持中断的引脚编号。ISR
:中断服务程序(Interrupt Service Routine),即中断触发时执行的函数。mode
:中断触发模式,可以是以下值之一:LOW
:引脚为低电平时触发。CHANGE
:引脚状态变化时触发。RISING
:引脚从低电平变为高电平时触发。FALLING
:引脚从高电平变为低电平时触发。
3. 编写中断服务程序(ISR)
中断服务程序是一个没有参数和返回值的函数。在ISR中,应尽量保持代码简短,避免使用延迟函数(如 delay()
)或复杂的计算,以确保快速响应。
以下是一个简单的示例,当引脚2的电平从高变低时,触发中断并点亮LED:
cpp
const int ledPin = 13; // 内置LED引脚
const int interruptPin = 2; // 中断引脚
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP); // 使用内部上拉电阻
attachInterrupt(digitalPinToInterrupt(interruptPin), blinkLED, FALLING);
}
void loop() {
// 主程序代码
}
void blinkLED() {
digitalWrite(ledPin, !digitalRead(ledPin)); // 切换LED状态
}
4. 中断的注意事项
- ISR应尽量简短:在ISR中执行过多操作可能导致程序响应变慢或丢失其他中断。
- 避免使用延迟函数:如
delay()
或millis()
,因为它们依赖于中断机制。 - 共享变量需声明为
volatile
:如果ISR和主程序共享变量,需将该变量声明为volatile
,以确保编译器不会优化掉对该变量的访问。
例如:
cpp
volatile int buttonPressed = 0;
void setup() {
attachInterrupt(digitalPinToInterrupt(2), buttonISR, FALLING);
}
void loop() {
if (buttonPressed) {
// 处理按钮按下事件
buttonPressed = 0; // 重置标志
}
}
void buttonISR() {
buttonPressed = 1; // 设置标志
}
实际应用案例
案例1:按钮计数器
以下示例使用中断实现一个按钮计数器,每次按下按钮时计数器加1,并通过串口输出计数值:
cpp
volatile int count = 0;
void setup() {
Serial.begin(9600);
pinMode(2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), incrementCount, FALLING);
}
void loop() {
Serial.println(count);
delay(1000); // 每秒输出一次计数值
}
void incrementCount() {
count++;
}
案例2:旋转编码器
旋转编码器是一种常见的输入设备,用于检测旋转方向和步数。通过中断可以实时捕捉编码器的信号变化:
cpp
volatile int encoderPos = 0;
const int pinA = 2;
const int pinB = 3;
void setup() {
pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinA), updateEncoder, CHANGE);
}
void loop() {
Serial.println(encoderPos);
}
void updateEncoder() {
int stateA = digitalRead(pinA);
int stateB = digitalRead(pinB);
if (stateA == stateB) {
encoderPos++;
} else {
encoderPos--;
}
}
总结
Arduino的中断输入功能为实时响应外部事件提供了强大的工具。通过合理使用中断,可以显著提高程序的效率和响应速度。以下是本文的关键点总结:
- 中断允许程序在特定事件发生时立即执行特定代码。
- 使用
attachInterrupt()
函数配置中断。 - 中断服务程序应尽量简短,避免使用延迟函数。
- 共享变量需声明为
volatile
。
附加资源与练习
- 练习1:修改按钮计数器示例,使其在按下按钮时点亮LED,松开时熄灭。
- 练习2:尝试使用旋转编码器控制LED的亮度(PWM输出)。
- 参考文档:Arduino官方文档中的 attachInterrupt() 函数说明。
希望本文能帮助你掌握Arduino中断输入的基本概念和应用!如果有任何问题,欢迎在评论区留言讨论。