iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0

我們已讓按鈕操作變得穩定,但當現場按鈕與遠端系統都能控制同一盞燈時,新的問題也隨之出現:燈號狀態到底該聽誰的?今天要讓 MCU 來統一管理燈號狀態。

交給 MCU 的 ledState

目前程式已經有 bool ledState = false;,也有負責反轉狀態與更新輸出的 toggle_led(),但 Day 8 的 setup() 仍直接使用 digitalWrite(LED_PIN, LOW); 初始化硬體。

這兩行目前剛好都代表關閉,所以執行結果沒有衝突,但它們仍是兩個獨立設定,若日後將 ledState 初始值改成 true,卻忘記同步修改 digitalWrite(),程式會認為 LED 應該亮起,實體輸出卻仍維持 LOW。

單一狀態來源的意思,是程式只保留一個可判定真實狀態的位置,其他輸出與顯示都依它更新,本專案將這項責任交給 MCU 的 ledState

開機也要依照 ledState

Day 9 將 setup() 中寫死的 LOW 改為三元運算子,讓開機輸出直接依照 ledState 初始化。

digitalWrite(LED_PIN, ledState ? HIGH : LOW);

ledStatefalse,D2 輸出 LOW,LED 維持關閉,若未來初始值改成 true,同一行程式便會輸出 HIGH,不需要再到 setup() 修改另一個固定值。

這項改動雖然只有一行,卻讓初始化與後續切換遵守相同規則,D2 的輸出不再由不同位置各自決定。

所有操作共用 toggle_led

按鈕只負責產生「切換一次」的事件,下降緣成立後呼叫 toggle_led(),它不另外保存自己的 LED 狀態,也不直接決定 HIGH 或 LOW。

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

toggle_led() 先反轉 ledState,再依新狀態更新 D2,未來即使增加其他操作來源,也應呼叫相同函式,不要繞過 ledState 直接控制腳位。

這樣設計後,按鈕、未來的 Python 命令與網頁操作都只提出事件,真正的狀態變更與硬體輸出仍由 MCU 統一處理。

檢查現有程式時可以採用一條固定規則,除了 setup()ledState 初始化輸出,任何需要改變 LED 的位置都不直接呼叫 digitalWrite(),而是統一呼叫 toggle_led(),新增功能時便不會繞過狀態管理。

這項規則也讓除錯有明確順序,先確認 ledState 的內容,再查看 D2 的實際輸出,若兩者不一致,問題會集中在初始化或 toggle_led(),不必逐一搜尋每個按鈕與命令來源。

完整 MCU 程式

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, ledState ? HIGH : LOW);
}

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

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

  lastBtn = btn;
}

相較 Day 8,程式只修改 setup() 的初始化輸出,按鈕讀取、下降緣、去彈跳與切換函式都維持原有版本。

執行與驗證結果

按下 App Lab 的 Run,因為 ledState 初始值是 false,LED 開機後應保持關閉,每按一次 D9,toggle_led() 會反轉狀態,LED 依序在亮與滅之間切換。

可暫時將初始值改成 true 後重新部署,LED 應在開機後直接亮起,這能確認初始化輸出確實讀取 ledState,測試完成後再恢復 false

連續操作按鈕時,程式中的 ledState 與實體 LED 應始終一致,按鈕只觸發事件,不會建立另一份亮滅記錄。

測試可依序確認開機關燈、第一次按下亮燈、第二次按下關燈,再重新啟動 App,LED 應回到 ledState 設定的初始狀態,四個結果都正確才表示狀態責任已整理完成。

本篇完成內容

  • ledState 統一決定開機輸出。
  • 保留 toggle_led() 作為唯一切換入口。
  • 讓按鈕只產生事件,不自行保存狀態。
  • 建立 MCU 管理號誌真實狀態的規則。

下一篇會整合並測試目前的 LED、按鈕、狀態與去彈跳,完成可離線運作的現場控制器 1.0。

下一篇|階段驗收 Edge Box 1.0


上一篇
Day 8|處理實體按鈕的彈跳問題
下一篇
Day 10|階段驗收 Edge Box 1.0
系列文
一塊板子,兩個腦袋:Arduino UNO Q 30 天實戰11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言