MPU 已經能要求 MCU 切換燈號,今天要讓 MCU 把真正結果回報給 Python。
前一天完成了第一條下行路徑,Python 可以叫 MCU 執行 toggle_led(),D2 LED 也會跟著切換。
但 MPU 目前只知道自己送出了命令,還不知道 MCU 是否真的完成動作,今天要補上 MCU 回報 ledState 的上行路徑。
實體按鈕與 MPU 命令都會進入 toggle_led(),因此狀態回報也應放在這個函式內,無論切換由哪個來源觸發,只要 ledState 與 D2 輸出完成更新,接著就會送出相同的回報。
若只在 on_toggle_led() 中回報,遠端命令雖然有結果,現場按鈕卻不會通知 MPU,兩條操作路徑便再次產生不同規則。
將 Day 14 的 toggle_led() 改成以下內容,其餘按鈕、下降緣與 Bridge 登記維持不變。
void toggle_led() {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
Bridge.call("led_status", ledState); // 本日新增
}
這裡的 "led_status" 是上行事件名稱,第二個參數 ledState 是要傳給 MPU 的布林值,更新順序是先反轉狀態、寫入 D2,最後才回報結果。
toggle_led() 仍是唯一切換入口,MCU 不必分辨命令來自 D9 或 MPU,兩種來源完成後都會回傳同一份真實狀態。
回報放在 digitalWrite() 之後也有明確意義,送出的值代表 MCU 已完成本次狀態更新,而不是尚未執行的命令內容,上層收到結果後才能把它當作硬體真實狀態,這與 Python 自己先把畫面反轉有本質差異。
Python 端先實作最小的 on_led_status(),暫時直接印出布林值,再使用 Bridge.provide() 登記等待 MCU 呼叫。
from arduino.app_utils import App, Bridge
service_name = "Intersection Edge Service"
service_ready = True
def on_led_status(state: bool):
print("MCU 回報狀態:", state) # 本日新增
def on_toggle_led(client_id, data):
Bridge.call("toggle_led")
print("已要求 MCU 切換 LED")
Bridge.provide("led_status", on_led_status) # 本日新增
print("Service ready:", service_name)
on_toggle_led(None, None)
App.run()
Bridge.provide("led_status", on_led_status) 必須使用與 MCU 完全相同的名稱,當 MCU 呼叫 "led_status" 時,Bridge 會執行 Python 的 on_led_status(),並把布林值放入 state。
登記動作要放在啟動測試呼叫之前,否則 MCU 很快完成切換並送回狀態時,Python 端可能還沒有準備好接收入口,本日程式先登記、再測試、最後進入 App.run(),執行順序正好對應這項需求。
按下 Run 後,Python 會先送出一次測試切換,D2 LED 改變狀態,接著 Console 應收到 True 或 False,這表示命令已從 MPU 抵達 MCU,執行完成後又將結果送回 MPU。
輸出的布林值應與實體 LED 相符,亮起時收到 True,熄滅時收到 False,MPU 不需要自行反轉一份狀態,也不應根據上一個畫面結果猜測本次動作是否成功。
可連續重新執行 App 兩次觀察結果,每次啟動測試都只要求切換一次,因此 Console 與 LED 應交替出現兩種狀態,若 LED 有變化但收到的值相反,應檢查 ledState 更新與 digitalWrite() 是否仍使用同一份資料。
服務保持運行時按下 D9,LED 每次切換後,Python Console 也應出現新的布林值,這證明回報不是遠端命令的專用功能,而是 MCU 所有狀態變更的共同出口。
如果 LED 有切換卻沒有輸出,先檢查兩端事件名稱是否一致,再確認 Python 是否已在測試命令前執行 Bridge.provide(),避免回報抵達時接收函式尚未登記。
檢查一次切換只回報一次
每次 toggle_led() 只應產生一筆 led_status,啟動測試一次、D9 短按一次,Console 都各新增一行即可,若同一次操作出現兩筆相同或相反結果,應檢查是否在其他位置重複呼叫 Bridge.call(),回報功能只保留在共同切換入口,才能讓事件數量與實際硬體動作一一對應。
ledState。Bridge.provide() 登記 led_status。現在 MCU 已會把真正狀態回報給 Python,但 True 與 False 對管理畫面不夠直覺,下一篇要把硬體狀態整理成 ON/OFF 這種可讀資料。
下一篇|將硬體狀態轉成可讀資訊