我們先用 Arduino 和麵包板接一個電路:它做的事情很簡單,有一個按鈕、一個 LED。當按鈕按下的時候,LED 亮。放開時,LED 滅。
以下是電路接法:
你可以看到我們用一個按鈕做一個 pull down 線路到 Pin2,這是為了避免 Pin2 產生 floating。所以按鈕按下時, Pin2 應該會讀到高電位 (HIGH)
Arduino 上的 code 也很簡單,就只是讀取 Pin2 的值,然後決定要對 Pin13 輸出 HIGH (燈亮) 還是 LOW (燈滅)。
const int buttonPin = 2; // the number of the pushbutton pin const int ledPin = 13; // the number of the LED pin int buttonState = 0; // variable for reading the pushbutton status void setup() { pinMode(ledPin, OUTPUT); pinMode(buttonPin, INPUT); } void loop() { buttonState = digitalRead(buttonPin); if (buttonState == HIGH) { // turn LED on: digitalWrite(ledPin, HIGH); } else { // turn LED off: digitalWrite(ledPin, LOW); } }
但執行結果可能跟我們預期的行為不同。 請看以下的實際操作影片:
你可以發現,當按鈕按下並且保持在按下狀態時,LED 燈還是會熄滅。且若是快速地按下 & 釋放按鈕,LED 燈可能根本完全不亮。
為了讓說明這個現象,現在稍微修改一下程式,讓行為變成 "按一下按鈕,放開後 LED 恆亮。再按一下,放開後 LED 滅"。
const int buttonPin = 2; // the number of the pushbutton pin const int ledPin = 13; // the number of the LED pin int buttonState = 0; // variable for reading the pushbutton status int ledState = LOW; // 增加這個用來記錄 LED 狀態 void setup() { pinMode(ledPin, OUTPUT); pinMode(buttonPin, INPUT); digitalWrite(ledPin, ledState); // 初始化的時候熄滅 LED } void loop() { buttonState = digitalRead(buttonPin); if (buttonState == HIGH) { // 在每次按鈕被按下時, 才改變 LED 的狀態 ledState = !ledState; // 跟上一次相反就對了 digitalWrite(ledPin, ledState); } }
實際的運作我就懶得拍影片了,請直接在上面的 123d Circuits 的視窗中點 "Start Simulation" 觀看。程式碼也可以點 "Code Editor" 觀看。執行結果跟我真實接線的現象非常像。你可以發現當我需要讓 LED 狀態該變時,我需要長按才能夠讓狀態改變的機率大一點 (意思是不是每次都有效!)。
這種現象稱為接觸彈跳 (contact bounce),是機械開關常見的問題。下圖是一個示意圖,假如有一個按鈕,按下時訊號會拉 LOW, 放開時回到 HIGH。理想狀況如同下圖的 "Ideal Button Signal",按鈕按下時,訊號拉 LOW,持續 50ms 後放開按鈕,回到 HIGH 的狀態。
但真實的狀況比較像 "Bouncy Digital Button Signal" 所示,會在機械狀態改變的瞬間發生電流脈衝。
from: Making Embedded Systems, O'Reilly
當開關的接觸點碰撞在一起的時候,它彈性會造成彈跳,其結果是快速的電流脈衝,而不是很理想地從 LOW 到 HIGH (或相反) 的轉換。
使用這些接觸開關時,通常因為彈跳發生得太快了,所以不會影響大部份的設備,但對於反應快速的電路就會產生問題,會導致將這些 on-off 脈衝被誤解為資料串流。
參考資料:
Chapter 4. Outputs, Inputs, and Timers (from Making Embedded Systems)
A Guide to Debouncing (from JG Ganssle)
沒有留言:
張貼留言