iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0

上一篇我們已經讓號誌只在按鈕被按下瞬間切換一次,但實體按鈕並不總是乖乖配合,偶爾按一次,訊號卻可能跳動好幾次,今天要加入簡易去彈跳處理,讓每一次按下都能得到更穩定的結果。

按鈕接點並非瞬間完成切換

實體按鈕內部由金屬接點接通與斷開,按下時接點可能在很短時間內反覆碰觸,MCU 讀到的結果便可能依序出現 LOW、HIGH、LOW,而不是一次乾淨地從 HIGH 變成 LOW。

https://ithelp.ithome.com.tw/upload/images/20260808/20058745bsFTH4ECH7.png

Day 7 的下降緣判斷會把每次 HIGH 轉 LOW 都視為新的按下動作,因此同一次實體按壓若產生數次電位跳動,toggle_led() 也可能被呼叫數次,最後看到的 LED 狀態便不一定符合預期。

這種機械接點在短時間內反覆變化的現象稱為接點彈跳,程式需要忽略按下後的一小段不穩定時間,避免將同一次操作誤認為多次事件。

加入延遲

本篇採用最簡單的作法,在確認下降緣並完成 LED 切換後,加入 delay(50);,讓 MCU 暫停 50 毫秒,再繼續執行後面的程式。

if (lastBtn == HIGH && btn == LOW) {
  toggle_led();
  delay(50);
}

delay(50) 要放在條件區塊內, toggle_led() 之後,只有偵測到按下事件並且程式先完成這次有效操作後才暫停,以暫時忽略接點後續跳動,按鈕放開或維持原狀時不需要等待。

完整 MCU 程式

sketch/sketch.ino 更新如下,Day 7 的程式只增加一行 delay(50);

const int LED_PIN = 2;
const int BTN_PIN = 9;

bool ledState = false;
bool lastBtn = HIGH;

void toggle_led() {
  ledState = !ledState;
  digitalWrite(LED_PIN, ledState ? HIGH : LOW);
}

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(BTN_PIN, INPUT_PULLUP);
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  bool btn = digitalRead(BTN_PIN);

  if (lastBtn == HIGH && btn == LOW) {
    toggle_led();
    delay(50);
  }

  lastBtn = btn;
}

程式先讀取 D9,再比較 lastBtnbtn,只有 HIGH 轉 LOW 時切換 LED,完成後暫停 50 ms,最後將目前讀值保存到 lastBtn,下一圈繼續判斷新的狀態變化。

執行與驗證

按下 App Lab 的 Run,部署完成後連續操作按鈕,每次都要完整按下再放開,LED 應依序在亮與滅之間切換,按住不放仍只會觸發一次,快速短按時的多次觸發也應比 Day 7 明顯減少。

可將 delay(50); 暫時註解後測試十次,再恢復程式測試十次,比較兩個版本是否出現按一下卻切換兩次的情況,完成比較後保留有 50 ms 延遲的 Day 8 版本。

測試時每次按壓速度不必完全一致,可混合快速輕按、正常按壓與稍長按住,若三種操作都能穩定維持一次切換,代表這個簡易去彈跳已符合目前原型需求。

若 LED 完全沒有變化,先確認 delay(50) 是否放在下降緣條件內,而不是誤刪 toggle_led(),若按鈕反應仍偶爾不穩定,則重新檢查 D9、GND、按鈕方向與接點是否鬆動。

簡易延遲的優缺點

delay(50) 容易理解,也足以完成目前單一按鈕的原型,但暫停期間 MCU 不會執行 loop() 中的其他工作,未來若同時處理多個輸入、通訊或需要快速反應的任務,delay() 這種阻塞式方法便可能影響其他功能,之後若篇幅容許,筆者會再介紹非阻塞式方法。

本篇完成內容

  • 認識機械按鈕的接點彈跳。
  • 在下降緣事件後加入 delay(50)
  • 降低一次按下造成多次切換的機會。
  • 保持既有狀態與控制流程不變。

現在按鈕操作已經穩定,但現實世界是現場與遠端都會控制同一號誌燈,為了避免狀態不同步,接下來我們需要統一管理燈號狀態。

下一篇|狀態不能有兩個答案


上一篇
Day 7|按一下再切換,別讓燈一直跳
下一篇
Day 9|狀態不能有兩個答案
系列文
一塊板子,兩個腦袋:Arduino UNO Q 30 天實戰11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言