跳到主要内容

Arduino 中断输入

在Arduino编程中,中断输入是一种强大的功能,允许程序在特定事件发生时立即暂停当前任务,转而执行一个特定的函数(称为中断服务程序,ISR)。这种机制非常适合处理需要快速响应的外部事件,例如按钮按下、传感器触发等。

什么是中断?

中断是一种硬件或软件触发的信号,用于通知处理器某个事件已经发生。当Arduino检测到中断信号时,它会暂停当前正在执行的代码,跳转到预先定义的中断服务程序(ISR),执行完ISR后再返回到原来的任务继续执行。

备注

中断的主要优势在于它能够实时响应外部事件,而不需要程序不断轮询(polling)输入状态,从而节省资源并提高效率。

Arduino 中的中断类型

Arduino支持两种主要类型的中断:

  1. 外部中断:由外部引脚触发,例如按钮按下或传感器信号变化。
  2. 定时器中断:由内部定时器触发,用于定时任务。

本文将重点介绍外部中断

如何使用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的中断输入功能为实时响应外部事件提供了强大的工具。通过合理使用中断,可以显著提高程序的效率和响应速度。以下是本文的关键点总结:

  1. 中断允许程序在特定事件发生时立即执行特定代码。
  2. 使用 attachInterrupt() 函数配置中断。
  3. 中断服务程序应尽量简短,避免使用延迟函数。
  4. 共享变量需声明为 volatile

附加资源与练习

  • 练习1:修改按钮计数器示例,使其在按下按钮时点亮LED,松开时熄灭。
  • 练习2:尝试使用旋转编码器控制LED的亮度(PWM输出)。
  • 参考文档:Arduino官方文档中的 attachInterrupt() 函数说明。

希望本文能帮助你掌握Arduino中断输入的基本概念和应用!如果有任何问题,欢迎在评论区留言讨论。