在嵌入式系統開發中,從基礎的輸出入控制進階到整合多個周邊裝置以實現特定應用,是重要的實踐環節。本文接續前章的基礎,深入探討如何以 TinyGo 為核心,建構一個具備完整功能的智慧安全鎖。其理論重點在於狀態管理與事件處理,程式碼展示了如何持續監聽鍵盤事件、暫存使用者輸入,並在特定條件(密碼長度匹配)下啟動驗證程序。此流程不僅整合了鍵盤的輸入邏輯與伺服馬達的致動控制,更透過 LED 提供明確的視覺回饋,完整體現了在微控制器上設計閉環使用者互動系統的典型架構與編程思維。
智慧安全鎖的建構:TinyGo、鍵盤與伺服馬達的整合(續)
玄貓深信,高科技養成不僅止於理論,更在於實踐與創新。在掌握了LED和按鈕的基礎控制後,本章將引導開發者進入更具挑戰性的領域:建構一個智慧安全鎖。這將結合4x4鍵盤的輸入、伺服馬達的精確控制,並深入探討序列埠通信在除錯中的關鍵作用。最終目標是實現一個能透過密碼解鎖的實用裝置。
建構基於鍵盤的安全鎖(續)
編寫安全鎖邏輯(續)
玄貓已經初始化了鍵盤、伺服馬達和LED引腳。現在,玄貓將繼續在main.go中編寫核心的密碼邏輯。
// Chapter03/safety-lock/main.go
package main
import (
"machine"
"time"
"Chapter03/safety-lock/keypad" // 引入鍵盤驅動程式
"Chapter03/safety-lock/servo" // 引入伺服馬達驅動程式 (或 servopwm)
)
func main() {
// 1. 初始化鍵盤驅動程式
var keypadDriver keypad.Driver
keypadDriver.Configure(
machine.D3, machine.D4, machine.D5, machine.D6, // 行引腳
machine.D7, machine.D8, machine.D9, machine.D10, // 列引腳
)
// 2. 初始化伺服馬達驅動程式
// 建議使用硬體 PWM 版本的驅動程式 (servopwm)
// 以下為軟體模擬版本作為範例
var servoDriver servo.Driver
servoDriver.Configure(machine.D11) // 配置伺服馬達連接到 D11 引腳
// 3. 初始化 LED 引腳
greenLED := machine.D12 // 綠色 LED 連接到 D12
redLED := machine.D13 // 紅色 LED 連接到 D13
redLED.Configure(machine.PinConfig{Mode: machine.PinOutput})
greenLED.Configure(machine.PinConfig{Mode: machine.PinOutput})
// 確保 LED 初始狀態為關閉
redLED.Low()
greenLED.Low()
// 4. 定義正確的密碼
const correctPasscode = "133742" // 範例密碼
// 5. 初始化一個變數來儲存使用者輸入的密碼
enteredPasscode := ""
// 6. 無限循環,持續讀取鍵盤輸入並處理密碼邏輯
for {
key := keypadDriver.GetKey() // 獲取按下的按鍵
if key != "" { // 如果有按鍵被按下
println("按鈕: ", key) // 列印按下的按鍵到序列埠
enteredPasscode += key // 將按鍵追加到已輸入密碼字串
// 7. 提供視覺回饋:紅色 LED 閃爍
redLED.High()
time.Sleep(time.Second / 5) // 亮 0.2 秒
redLED.Low()
}
// 8. 檢查已輸入密碼的長度是否與正確密碼相同
if len(enteredPasscode) == len(correctPasscode) {
if enteredPasscode == correctPasscode { // 9. 如果密碼匹配
println("密碼正確!")
enteredPasscode = "" // 重置已輸入密碼
servoDriver.Right() // 觸發伺服馬達(模擬開鎖)
// 10. 綠色 LED 亮起 3 秒,表示成功
greenLED.High()
time.Sleep(time.Second * 3)
greenLED.Low()
} else { // 11. 如果密碼不匹配
println("密碼錯誤!")
println("您輸入的密碼: ", enteredPasscode)
enteredPasscode = "" // 重置已輸入密碼
// 12. 紅色 LED 亮起 3 秒,表示失敗
redLED.High()
time.Sleep(time.Second * 3)
redLED.Low()
}
}
// 13. 短暫延遲,幫助按鍵去抖動並避免過度掃描
time.Sleep(50 * time.Millisecond)
}
}
燒錄與測試: 將程式燒錄到Arduino Uno:
tinygo flash --target=arduino Chapter03/safety-lock/main.go
燒錄完成後,打開PuTTY並監控序列埠輸出。
輸入錯誤密碼:例如輸入"123456"。
每次按鍵,紅色LED會閃爍。
輸入完畢後,PuTTY會顯示"密碼錯誤!“和您輸入的密碼。
紅色LED會亮起3秒。
伺服馬達不會動作。
輸入正確密碼:輸入"133742”。
每次按鍵,紅色LED會閃爍。
輸入完畢後,PuTTY會顯示"密碼正確!"。
綠色LED會亮起3秒。
伺服馬達會轉動(模擬開鎖)。
@startuml !define DISABLE_LINK !define PLANTUML_FORMAT svg !theme none
skinparam dpi auto skinparam shadowing false skinparam linetype ortho skinparam roundcorner 5 skinparam defaultFontName “Microsoft JhengHei UI” skinparam defaultFontSize 16 skinparam minClassWidth 100
actor “使用者” as User
rectangle “安全鎖系統” as SafetyLock { component “main.go (主邏輯)” as MainLogic component “keypad.Driver” as KeypadDriver component “servo.Driver” as ServoDriver component “Red LED” as RedLED component “Green LED” as GreenLED }
User –> KeypadDriver : 按下按鍵 KeypadDriver –> MainLogic : 返回按鍵字元
MainLogic –> RedLED : 閃爍 (按鍵回饋) MainLogic –> MainLogic : 累積輸入密碼
MainLogic –> MainLogic : 檢查密碼長度 alt 密碼長度匹配 MainLogic –> MainLogic : 比較密碼 alt 密碼正確 MainLogic –> ServoDriver : 觸發開鎖動作 (Right()) MainLogic –> GreenLED : 亮起 3 秒 MainLogic –> User : 顯示 “密碼正確!” else 密碼錯誤 MainLogic –> RedLED : 亮起 3 秒 MainLogic –> User : 顯示 “密碼錯誤!” end MainLogic –> MainLogic : 重置輸入密碼 end
ServoDriver –> “SG90 伺服馬達” as ServoMotor : 物理轉動
@enduml
看圖說話:
此圖示展示了智慧安全鎖的軟體邏輯流程。使用者透過鍵盤輸入按鍵,keypad.Driver捕獲這些輸入並傳遞給main.go中的主邏輯。主邏輯接收到每個按鍵後,會讓紅色LED閃爍以提供即時回饋,並將按鍵字元累積到enteredPasscode變數中。當enteredPasscode的長度與預設的correctPasscode長度匹配時,系統會進行密碼比對。如果密碼正確,servo.Driver會被觸發執行開鎖動作,同時綠色LED會亮起3秒,並在序列埠顯示「密碼正確!」。如果密碼錯誤,紅色LED會亮起3秒,並在序列埠顯示「密碼錯誤!」。無論結果如何,enteredPasscode都會被重置,等待下一次輸入。這個流程實現了一個完整的、帶有視覺回饋的安全鎖系統。
智慧安全鎖的建構:TinyGo、鍵盤與伺服馬達的整合(續)
玄貓深信,高科技養成不僅止於理論,更在於實踐與創新。在掌握了LED和按鈕的基礎控制後,本章將引導開發者進入更具挑戰性的領域:建構一個智慧安全鎖。這將結合4x4鍵盤的輸入、伺服馬達的精確控制,並深入探討序列埠通信在除錯中的關鍵作用。最終目標是實現一個能透過密碼解鎖的實用裝置。
問題與思考
- 鍵盤座標: 根據鍵盤的座標系統,如果鍵盤的佈局是:
1 2 3 A
4 5 6 B
7 8 9 C
* 0 # D
並且我們假設行索引從0到3,列索引從0到3。
- 鍵盤的第一行是
1 2 3 A,對應行索引0。 - 鍵盤的第二行是
4 5 6 B,對應行索引1。 - 鍵盤的第三行是
7 8 9 C,對應行索引2。 - 鍵盤的第四行是
* 0 # D,對應行索引3。 - 鍵盤的第一列是
1 4 7 *,對應列索引0。 - 鍵盤的第二列是
2 5 8 0,對應列索引1。 - 鍵盤的第三列是
3 6 9 #,對應列索引2。 - 鍵盤的第四列是
A B C D,對應列索引3。
因此,鍵「3」位於行索引0,列索引2。
- 密碼驗證邏輯修改: 在最終專案中,密碼驗證是在輸入的密碼長度達到預設密碼長度時才進行的。如果玄貓希望在按下特定按鍵後立即檢查密碼(例如,按下「#」鍵後),可以這樣修改程式碼:
// ... (前略)
// 5. 初始化一個變數來儲存使用者輸入的密碼
enteredPasscode := ""
const correctPasscode = "133742" // 範例密碼
// 6. 無限循環,持續讀取鍵盤輸入並處理密碼邏輯
for {
key := keypadDriver.GetKey() // 獲取按下的按鍵
if key != "" { // 如果有按鍵被按下
println("按鈕: ", key) // 列印按下的按鍵到序列埠
// 如果按下的是確認鍵(例如 '#'),則立即檢查密碼
if key == "#" {
if enteredPasscode == correctPasscode {
println("密碼正確!")
servoDriver.Right()
greenLED.High()
time.Sleep(time.Second * 3)
greenLED.Low()
} else {
println("密碼錯誤!")
println("您輸入的密碼: ", enteredPasscode)
redLED.High()
time.Sleep(time.Second * 3)
redLED.Low()
}
enteredPasscode = "" // 無論正確與否,都重置已輸入密碼
} else {
// 如果不是確認鍵,則將按鍵追加到已輸入密碼字串
enteredPasscode += key
// 提供視覺回饋:紅色 LED 閃爍
redLED.High()
time.Sleep(time.Second / 5) // 亮 0.2 秒
redLED.Low()
// 可選:如果輸入長度超過預設密碼長度,則重置,避免過長輸入
if len(enteredPasscode) > len(correctPasscode) {
println("輸入過長,已重置!")
enteredPasscode = ""
}
}
}
// 短暫延遲,幫助按鍵去抖動並避免過度掃描
time.Sleep(50 * time.Millisecond)
}
這個修改將密碼檢查的觸發點從「達到預設長度」變為「按下特定確認鍵(例如’#’)」。同時,也增加了輸入過長時的處理邏輯,以提高使用者體驗。
檢視此智慧安全鎖從概念到實體的建構過程,其核心價值不僅在於功能實現,更在於它體現了將分散的軟硬體知識(如TinyGo編程、週邊驅動、序列埠除錯)整合為單一解決方案的系統性思維。真正的挑戰並非單純的程式碼編寫,而在於管理不同元件間的時序、狀態與互動,這正是從「開發者」邁向「架構師」思維的縮影。
此專案預示著,未來高階技術人才的價值,將更依賴於這種跨越軟體與物理世界的整合能力,以及快速原型化的實踐效率。玄貓認為,這類從無到有的整合性實作,不僅是技術的試煉場,更是培養解決複雜問題的全局視野與實踐韌性的最佳途徑,值得每位追求卓越的技術人深度投入。