Arduino 按钮抖动问题:外接下拉电阻及消抖电容后中断触发仍异常
Arduino按钮控制秒表异常问题修复方案
核心故障根因
- 硬件接线与引脚配置冲突:外部电路为10k下拉设计,按钮未按下时引脚默认电平为LOW,但代码启用了
INPUT_PULLUP内置上拉,强制引脚默认电平为HIGH,内外电平冲突导致引脚状态无法正确识别。 - 中断触发边沿不匹配:按当前硬件接线,按钮按下时引脚电平从LOW跳变到HIGH(上升沿),松开时才是下降沿,代码配置
FALLING边沿触发中断,只有松开按钮才会触发ISR,和预期的按下触发逻辑不符。 - 无软件消抖逻辑:仅靠硬件电容无法完全消除按键抖动,抖动产生的多次跳变边沿会反复触发ISR,导致
buttonState多次翻转,单次按下的操作结果完全随机。 - 代码逻辑缺陷:
buttonState未初始化,上电后初始状态不确定,启动逻辑混乱。- 存储时间的变量
z、ms定义为有符号long类型,millis()返回无符号unsigned long,运行时间超过24天会发生溢出错误。 - loop中只要
buttonState == LOW就重复重置startTime,不符合秒表启停的逻辑要求。 - 遗漏LCD初始化语句
lcd.begin(),也可能导致显示异常。
修复方案
方案1(推荐,无需改动现有硬件)
- 将
pinMode(button, INPUT_PULLUP)改为pinMode(button, INPUT),匹配外部下拉电路。 - 中断触发边沿改为
RISING,匹配按钮按下时的电平跳变方向。 - 增加ISR消抖逻辑,记录上次中断触发时间,间隔小于20ms的触发直接忽略。
- 初始化
buttonState为LOW,修正时间变量类型,调整loop中的时间赋值逻辑,仅在秒表启动时赋值一次startTime。
方案2(改动硬件,省外部电阻)
把按钮接线改为:一端接GND,另一端直接接数字引脚2,去掉10k下拉电阻,保留INPUT_PULLUP配置,中断触发边沿保留FALLING即可。
修复后完整代码(适配原硬件接线)
#include <LiquidCrystal.h> LiquidCrystal lcd(5, 6, 9, 10, 11, 12); unsigned long volatile startTime = 0; unsigned long volatile sec; volatile boolean buttonState = LOW; // 初始化按钮状态 volatile unsigned long lastIsrTime = 0; // 消抖用的上次中断触发时间 const int button = 2; unsigned long ms; unsigned long z; void setup() { Serial.begin(9600); pinMode(button, INPUT); // 改为INPUT匹配外部下拉电路 lcd.begin(16,2); // 补充LCD初始化配置 lcd.setCursor(0, 0); lcd.print("Stopwatch"); attachInterrupt(digitalPinToInterrupt(button), isr, RISING); // 改为上升沿触发 } void loop() { static bool lastRunState = LOW; // 仅在秒表从停止切换到启动时重置一次开始时间 if (buttonState == HIGH && lastRunState == LOW) { startTime = millis(); lastRunState = HIGH; } if (buttonState == LOW && lastRunState == HIGH) { lastRunState = LOW; } // 秒表运行逻辑 if (buttonState == HIGH) { z = millis() - startTime; sec = z / 1000; ms = z % 1000; lcd.setCursor(0, 1); lcd.print(sec); lcd.print("."); // 毫秒补零对齐,避免数字残留 if(ms < 10) lcd.print("00"); else if(ms < 100) lcd.print("0"); lcd.print(ms); lcd.setCursor(9, 1); lcd.print("Secs"); } } // 中断服务程序增加消抖逻辑 void isr() { unsigned long now = millis(); if (now - lastIsrTime < 20) { // 20ms消抖时长可根据实际按键情况调整 return; } lastIsrTime = now; buttonState = !buttonState; }
内容的提问来源于stack exchange,提问作者user16446371
相关产品推荐
相关产品推荐

