亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

Arduino UNO 单中断高效控制 10 个按钮

元器件与材料

软件与在线服务

项目简介

引言

中断非常实用。除了简化代码,还可用于精确计时或从睡眠模式唤醒 Arduino。

假设你有一个由电池供电的用户界面(如遥控器),可能希望将 Arduino(或独立 ATmega)置于掉电模式以省电。进入掉电模式后,Arduino 只能通过外部中断唤醒。Arduino Uno 使用的 ATmega328P 芯片仅有两个外部引脚中断(引脚 2 和 3 上的 INT0 和 INT1)。既然用户界面通常不止两个按钮,这就成了问题。

标准解法是将所有按钮常规连接,并通过二极管连到中断引脚,但这会显著增加电路复杂度。

Arduino UNO 单中断高效控制 10 个按钮

除了标准外部中断,ATmega328P 还支持引脚变更中断,有现成库可用,也是解决此问题的好办法。

然而在一次编程比赛中,我发现了一种无需额外电气元件、仅用标准外部中断即可实现的方法。

电路设计

Arduino UNO 单中断高效控制 10 个按钮
Arduino UNO 单中断高效控制 10 个按钮
Arduino UNO 单中断高效控制 10 个按钮

示例使用了 10 个按钮,完美适配面包板。每个按钮一侧接任意引脚(示例用 4~13),另一侧共同连接到单个支持中断的引脚(示例用引脚 2)。Uno 可支持最多 20 个按钮,Mega 甚至可达 70 个(若真需 70 按键,建议用多路复用,无需整块 Mega)。

Arduino UNO 单中断高效控制 10 个按钮

代码实现

完整代码见文末。上传后打开串口监视器,按下任意按钮即显示其编号。注意 loop() 函数完全未使用。

Arduino UNO 单中断高效控制 10 个按钮

工作原理

核心是一个配置为 FALLING 模式的中断(示例用引脚 2)。为避免使用二极管,Arduino 即时重构电路,在两种模式间切换:公共模式和独立模式。

公共模式

大部分时间处于公共模式:中断引脚配置为 INPUT_PULLUP,其余按钮引脚设为 OUTPUT 并输出 LOW。

void configureCommon() {
  pinMode(commonPin, INPUT_PULLUP);
  for (int i = 0; i < sizeof(buttonPins)/sizeof(int); i++) {
    pinMode(buttonPins[i], OUTPUT);
    digitalWrite(buttonPins[i], LOW);
  }
}

此模式下按下任意按钮都会拉低中断引脚并触发中断。中断服务程序随即切换到独立模式。

独立模式

中断触发后迅速切换到独立模式:中断引脚变为 OUTPUT 并输出 LOW,其余按钮引脚设为 INPUT_PULLUP。

void configureDistinct() {
  pinMode(commonPin, OUTPUT);
  digitalWrite(commonPin, LOW);
  for (int i = 0; i < sizeof(buttonPins)/sizeof(int); i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
}

独立模式下,只有实际被按下的按钮对应引脚会被拉低。遍历所有引脚即可识别触发中断的按钮。识别完成后可切回公共模式等待下一次中断,或视应用需求保持独立模式处理输入,睡眠前再切回公共模式。

进阶示例:舵机控制与睡眠模式

Arduino UNO 单中断高效控制 10 个按钮
Arduino UNO 单中断高效控制 10 个按钮
Arduino UNO 单中断高效控制 10 个按钮

该示例将每个按钮映射到不同舵机角度(1=0°,2=20°……10=120°),并用电池供电。无操作 5 秒后进入掉电模式省电,舵机通过晶体管供电,不用时切断。完整代码见文末。

代码

串口记录器版本

const int commonPin = 2;
const int buttonPins[] = {4,5,6,7,8,9,10,11,12,13};
unsigned long lastFire = 0;

void setup() {
  configureCommon();
  attachInterrupt(digitalPinToInterrupt(commonPin), pressInterrupt, FALLING);
  Serial.begin(9600);
}

void loop() { /* 空 */ }

void pressInterrupt() {
  if (millis() - lastFire < 200) return; // 去抖
  lastFire = millis();
  configureDistinct();
  for (int i = 0; i < sizeof(buttonPins)/sizeof(int); i++) {
    if (!digitalRead(buttonPins[i])) press(i);
  }
  configureCommon();
}

void configureCommon() {
  pinMode(commonPin, INPUT_PULLUP);
  for (int i = 0; i < sizeof(buttonPins)/sizeof(int); i++) {
    pinMode(buttonPins[i], OUTPUT);
    digitalWrite(buttonPins[i], LOW);
  }
}

void configureDistinct() {
  pinMode(commonPin, OUTPUT);
  digitalWrite(commonPin, LOW);
  for (int i = 0; i < sizeof(buttonPins)/sizeof(int); i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
}

void press(int button) {
  Serial.println(button + 1);
}

舵机+睡眠模式版本

#include 
#include 
#include 

const int commonPin = 2;
const int buttonPins[] = {4,5,6,7,8,9,10,11,12,13};
const int servoEnablePin = A1;
const int servoPin = A0;
Servo servo;
unsigned long lastFire = 0;
int status = 0;

void setup() {
  pinMode(commonPin, INPUT_PULLUP);
  configureCommon();
  attachInterrupt(digitalPinToInterrupt(commonPin), pressInterrupt, FALLING);
  servo.attach(servoPin);
  pinMode(servoEnablePin, OUTPUT);
}

void loop() {
  if (millis()-lastFire > 5000) {
    digitalWrite(servoEnablePin, LOW);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sleep_mode();
  }
  delay(10);
}

void pressInterrupt() {
  sleep_disable();
  power_all_enable();
  if (millis()-lastFire < 200) return;
  lastFire = millis();
  configureDistinct();
  for (int i=0; i

原理图

提供 Fritzing 源文件:multiinterrupt_hoF76Oc4T5.fzz、servo_with_sleep_u9ZqxF0jhY.fzz

制造工艺

  1. 仅用 Arduino 构建 DTMF 解码器 – 无需额外 IC
  2. 用 Arduino 打造绚丽显示器 Ambilight 系统
  3. 用 Arduino 制作超声波悬浮装置:分步指南
  4. Arduino 与智能手机打造智能电压表——简单易做的 DIY 项目
  5. 基于 Arduino 与 MAX30100 的实时物联网心率监测系统
  6. Arduino Uno WiFi 网页服务器:通过浏览器控制 LED 开关
  7. 智能停车计数系统:Arduino + Processing + PHP 实时车位追踪上云
  8. Arduino 自动化 Chrome 恐龙游戏 - LDR 光敏电阻 + Python 实现全自动跳跃
  9. 使用 Arduino Nano 和 RDA8057M 制作紧凑型 FM 收音机
  10. 无线Arduino编程盾:HC-05蓝牙模块实现免USB线烧录
  11. 基于有限状态机的 Arduino 电子表 – YAKINDU Statechart Tools 实战
  12. Arduino 电容式触控开关:一枚硬币点亮 LED 的极简 DIY