點亮 LED 只是第一步,接下來更重要的問題是:當現場按鈕與遠端命令都能操作這盞燈時,誰來記住它現在究竟是亮還是滅?接下來要為號誌燈建立統一的狀態管理方式,讓所有操作都使用同一個控制入口,避免各自下指令而造成狀態混亂。
在 LED_PIN 下方加入 bool ledState = false;,bool 是只有 true 與 false 兩種結果的資料型態,適合表示開啟或關閉,這裡將 true 視為 LED 亮起,false 視為 LED 熄滅。
const int LED_PIN = 2;
bool ledState = false;
變數建立後,程式便有一個固定位置記錄目前狀態,不必從分散的 digitalWrite() 指令猜測 LED 應該亮或滅,後續其他操作也能先修改 ledState,再依它的內容更新硬體輸出。
變數名稱使用 ledState,其中 LED 表示控制對象,State 表示狀態,閱讀程式時可以直接理解它保存 LED 的亮滅結果,初始值設為 false,代表 MCU 啟動時先以關閉狀態開始。
注意:布林值本身不會自動控制腳位,它只保存程式對目前狀態的判斷,真正讓 LED 改變的是後面的 digitalWrite(),因此狀態資料與硬體輸出必須一起更新,若只改 ledState 而沒有重新寫入 D2,程式記錄與實體燈號便可能不一致,因此需要特別注意。
接著建立 toggle_led(),函式內先使用 ! 將布林值反轉,再透過三元運算子決定輸出 HIGH 或 LOW。
void toggle_led() {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
}
當 ledState 原本是 false,執行 !ledState 後會變成 true,下一次呼叫時又會由 true 變回 false,因此每執行一次函式,狀態就會切換一次。
ledState ? HIGH : LOW 是三元運算子,問號前方是判斷條件,條件為 true 時採用 HIGH,條件為 false 時採用 LOW,這行程式會讓 D2 的實際輸出與 ledState 保持相同意義。
將反轉狀態與更新輸出放在同一個函式後,其他程式便不需要分別修改變數與腳位,而是只要呼叫 toggle_led(),兩項工作便會依固定順序完成,這樣能減少狀態已改變但硬體尚未更新的情況。
共用函式也讓後續使用更單純,函式外部不必知道 LED 現在是亮或滅,也不必自己決定 HIGH 或 LOW,只需要提出切換要求,剩下的狀態反轉與腳位更新便都由 toggle_led() 一起搞定。
將 sketch/sketch.ino 改成以下內容,其他檔案保持 Day 4 的版本。
const int LED_PIN = 2;
bool ledState = false;
void toggle_led() {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
}
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
toggle_led();
}
void loop() {
}
說明:setup() 先將 D2 設為輸出,再以 LOW 關閉 LED,此時硬體狀態與 ledState = false 一致,接著呼叫 toggle_led(),變數會切換為 true,D2 也會輸出 HIGH,因此程式啟動後 LED 應持續亮起。
先寫入 LOW 再呼叫函式,是為了讓 MCU 啟動時有明確的初始輸出,並用同一個切換流程完成第一次亮燈,loop() 目前仍保持空白,目前只需驗證狀態與函式呼叫。
儲存後按下 App Lab 的 Run,等待建置與部署完成,D2 LED 應在程式啟動後亮起,這表示 ledState 已由 false 變為 true,三元運算子也依狀態將 D2 設為 HIGH。
驗證成功後,也可在 setup() 中再加入一次 toggle_led(); 做短暫驗證,連續呼叫兩次後,狀態會由 false 變成 true,再變回 false,LED 最後應熄滅,確認結果後再恢復本篇只有一次呼叫的版本。
若 LED 結果與預期不同,先檢查 ledState 的初始值、反轉符號 !、三元運算子的 HIGH 與 LOW 順序,以及 toggle_led() 是否真的在 setup() 中被呼叫。
bool ledState 保存 LED 狀態。! 在 true 與 false 之間反轉。toggle_led() 函式。現在號誌燈的狀態已有統一的管理方式,但目前還只能靠程式操作,無法滿足現場需求,接下來要為它加上實體按鈕,讓現場操作人員能直接操作。
下一篇|為 Edge Box 加上實體按鈕