第 6 章 輸入控制(開關)
6-1 功能簡介
• 本實習希望進行按鈕開關的實驗,當壓放開關一次時 LED 亮,
再壓放開關一次時 LED 滅,並周而復始運作。
• 系統方塊圖如圖 6-1 所示。
• 本實驗主要提到開關資料的讀取,以及開關彈跳問題的發生原因 及解決方法。
6-2 電路說明
邏輯電路的輸入訊號除了由其他電路所送來的訊號外,最常見的 輸入訊號就是開關,開關種類主要分為自動復歸型與非自動復歸 型兩類。
1) 自動復歸型開關(如圖 6-2 )是指當開關按下後,隨即改變開 關狀態,當開關放開後隨即又回復原狀,例如按鈕開關( Push Button )即屬於此類型,電路符號為 。
2) 非自動回復型開關(如圖 6-3 )是指當撥動開關後,其狀態會 維持在某一狀態(例如導通 ON 狀態),若要改變至關閉
( OFF )狀態,則需要再一次撥動開關才行,例如搖頭開關、
滑動開關,電路符號為 ;另外像二段式開關 、 指撥開關 \
( DIP Switch )、水銀開關等,皆屬於此類型。
6-2 電路說明
6-2 電路說明
• 以開關做為輸入元件,通常會接一個提升電阻到正電源或是接地 端,不能讓開關空接,也就是當按鈕開關未按下(亦即 OFF ) 時,會先有一個固定電壓給輸入端當作初始狀態。
6-2 電路說明
• 由於機械開關的特性,由某一接點投擲至另一接點的瞬間,會產 生多次的彈跳現象,無論是接點由 ON 至 OFF 或由 OFF 至 ON ,接點會經過閉合→打開→閉合→打開→…最後到穩定狀態的 過程,此一現象稱為接點的彈跳現象,如圖 6-4 所示。
• 開關的彈跳時間通常不大於 20ms ( 10ms ~ 20ms )。
6-2 電路說明
• 一般而言, CPU 是以極快(與彈跳時間比較)的速度執行指令
,這些彈跳的狀態會被偵測到,以致被 CPU 誤以為按了好幾次
(甚至數百次)。
• 為了避免這種誤判的現象,可以使用二種方式解決 : 1. 硬體(正反器、 RC 電路或單擊電路)。
2. 軟體(程式)。
• 就 CPU 控制而言,以軟體解決彈跳現象是較為經濟的方法,而 處理彈跳現象的過程稱為「去彈跳」( debounce )。
• 解決彈跳的方法是當檢知開關被按下後,先延遲一段時間(約 20ms ~ 50ms )用以避開彈跳現象後再確認,就可避免按一 次鍵被讀到好幾次的問題。
6-2 電路說明
圖 6-5 為本實驗 的硬體電路圖,其 中按鈕開關 S1 接 至 D2 ,接一個提升 電阻至正電源,形 成未按時 D2 被提 升至 +5V 為邏輯 1
,按下時 D2 接地 為邏輯 0 的狀態;
另外 LED 接至 D10 ,採低態動作
。
6-2 電路說明
6-2 電路說明
1. Arduino Leonardo + 麵包板的接線圖
如圖 6-6 所示,本電路使用 USB 提供的 5V ,不需外加電源。
6-2 電路說明
2. 圖 6-7 所示為使用 Arduino Leonardo + 麵包板擴展板 的接線圖,其中按鈕開關有 4 支接腳,未按時 1 、 4 腳短路
, 2 、 3 腳短路,按下時 4 支腳全短路。
6-2 電路說明
3. 圖 6-8 為 Leonardo 板(或 OZONE ) +Arminno 多功能 實驗板接線情況,為簡化顯示,圖 6-8 只畫出多功能實驗板 的區塊 8 及區塊 15 。由於實驗板區塊 15 為 4x4 鍵盤矩陣 電路,不同於單一顆按鈕開關的接法,故 JP24 上的 pin3 應 接地。
6-3 程式設計
Arduino IDE 內建了一些按鍵程式範例, 請選擇 Examples 中的
02.Digital → Button 。此程式是一個比較簡單的範例,按鍵 按下時 LED 亮,放開時 LED 滅,程式結構中包含一開始的 I/O 宣告, setup() 的 I/O 電氣特性指定,主迴圈程式 loop() 的內容。以下為 Button 的部分程式碼。
6-3 程式設計
其中 digitalRead(pin) 為讀取指定數位腳的指令
, 傳回值為 HIGH 或 LOW 。
6-3 程式設計
接著,以官方的 Button 程式為基礎,開始修改內容以符合實驗 要求;首先請看流程圖。
6-3 程式設計
6-3 程式設計
6-3 程式設計
6-3 程式設計
6-3 程式設計
1. const :常數宣告
此命令宣告變數在執行期間,數值是不會變動的,例如
lenPin 在電路上就是 D10 ,不會在執行過程中換成其它 I/O ,故適合宣告成常數,不會占用 CPU 的暫存器資源。而 任何非 const 開頭的變數宣告,皆會占用 CPU 資源。
2. boolean :布林資料型態
宣告正確的資料型態,有助於減少 CPU 資源的占用,由於按 鍵的狀態 buttonState 、 led 值的狀態 ledState 都是非 0 即 1 的二位元狀態,故宣告成 boolean 型態即可。
3. if( 條件式 ){statement1 }else{statement2} :條件 判斷指令
此命令是基本的條件式命令,如果 if 命令中的條件式為
「真」,則 statement1 的敘述會被執行;如果條件式為
「假」,則 else 後的程式段 statement2 就會被執行。
6-3 程式設計
4. while ( 條件式 ) { statement } :迴圈控制指令
此命令為前測迴圈指令, 如果命令中的條件式為「真」, 則 statement 的敘述會被執行,直到條件式不成立才離開迴圈。
若條件式為 1 ,代表條件式永遠成立,形成一個永久迴圈的結 構 while (1) { } 。
5. break :強迫跳出迴圈指令
執行迴圈指令時,若有需要跳出迴圈,可使用 break 強迫跳 出。
6-4 實驗成果
• 一切準備就緒後,即可開始進行編譯程式,以及下載、燒錄、測 試的工作;
• 首先請使用 USB 傳輸線連接好個人電腦與 Arduino
Leonardo 板,並依第 5-3 節中的實驗流程再練習一次,確 認選擇微控制器板為 Arduino Leonardo ,選擇正確的串列 傳輸埠及晶片燒錄方式,接著可點選圖示進行程式語法檢查、編 譯及燒錄。
• 燒錄成功後,可按一下電路(圖 6-7 或圖 6-8 )所標示的 按鍵 S1 ,試試下列三種狀況:
1. 壓放一次 LED 會亮,再壓放一次 LED 會滅,並持續變化
。
2. 當壓下時 LED 會立即轉態,即亮→滅,滅→亮,放開時則 無任何變化,可明顯看出有無開關彈跳問題。
3. 快速壓放按鍵,觀察 LED 的轉態是否正常、是否順暢。
6-5 延伸應用與練習
有了讀取按鍵狀態的輸入能力後,還有哪些是可以延伸應用並練習 的呢?以下帶領大家來思考一下!
6-5.1 使用 millis() 函式解決彈跳問題
為了瞭解開關彈跳問題的影響,請試著將 chap6-1.ino 程式中 的行號 33 、 38 刪除(或在行號前加入註解符號 // ),然後重 新下載燒錄,測試表 6-2 按鍵的壓放與 LED 的顯示是否有異常
,並記錄結果於表 6-2 中。
6-5 延伸應用與練習
• 實驗可發現,未加上防彈跳時間的延遲會造成開關資料讀取的錯 誤,爾後遇到開關類元件的實作一定要特別注意。
• Arduino IDE 中也有提供官方版的消除開關彈跳範例,請打 開 File → Examples → 02.Digital→Debounce 。
6-5 延伸應用與練習
官方提供的 Debounce 程式也是利用延遲時間消除開關彈跳,但 不是利用 delay() 函式,而是利用 millis() 函式來處理,以 下說明這兩個函式的差異。
6-5 延伸應用與練習
以下為使用 millis() 完成的延遲副程式範例,其中行號 1 開 頭的 void 代表無傳回值, myDelay 為副程式名稱, duration 為傳入參數,資料型態為無符號長整數;若對副程式語法有點陌生
,可先參看第 3-2.7 節的說明。
6-5 延伸應用與練習
下列程式為使用 millis() 函式完成的消除開關彈跳程式,紅字 代表需修改的地方;礙於篇幅,刪除了部分官方 Debounce 範例 程式的註解。
6-5 延伸應用與練習
6-5 延伸應用與練習
6-5 延伸應用與練習
• 接著,請下載程式至 Arduino Leonardo 控制板,測試結果 是否正常,並觀察按鍵是壓下時改變 LED 狀態,或是放開時改 變 LED 狀態?
• 若想得到壓下時改變 LED 狀態,上列程式 chap6-5-1.ino 應如何修改?
6-5 延伸應用與練習
6-5.2 按鈕開關與 LED 亮度控制
延伸第 6-5.1 節的 millis() 函式的功能,思考該如何修改 chap6-5-1.ino 的程式,完成按鈕開關控制 LED 亮度的實驗
,功能敘述如下:
1. 單步亮度調整:按鈕開關 S1 每壓放一次, LED 亮度值加 5
,重複此動作,直到最亮( 255 )時,再反轉變成 S1 每壓放 一次, LED 亮度值減 5 ,直到最暗時,再反轉回遞增。
2. 自動亮度調整:久按 S1 超過 1 秒時, LED 變成自動亮度調 整模式,會按原有變亮或變暗的方向持續變化,直到 S1 放開 為止。
3. 可透過 Serial Monitor 視窗,顯示 LED 亮度值的變化,
並持續循環。
6-5 延伸應用與練習
• 可綜合參考第 5-5.2 節呼吸燈及第 6-5.1 節使用 millis() 解決彈跳的程式,完成本小節的功能要求。
• 單步與自動亮度調整功能的地方,就在現在與上次時間點的差值 有無超過消除彈跳延遲時間(例如 50ms )程式區塊的處理,程 式碼如下。
6-5 延伸應用與練習
• 虛框線內代表已消除開關彈跳後的處理,可將單步與自動亮度調 整的功能撰寫於虛框線內指示的地方;常數 longPress 為按鍵 久按值的設定, longPress=1000 ( 1 秒)。
6-5 延伸應用與練習
無論單步或自動亮度調整,都需要類似呼吸燈的亮度調整程式,因 此可寫一個名稱為 ChangeBrightness() 的副程式, 方便共 同呼叫使用, ChangeBrightness() 程式碼請看程式檔
chap6_5_2.ino 行號 51-64 ,是由第 5-5.2 節呼吸燈的程式 修改而成,每呼叫一次可依 fadeAmount 遞增或遞減 LED 亮度 值一次。因此上方藍色字的程式碼可寫為:
if (buttonState==LOW) ChangeBrightness();
代表 S1 按鍵狀態為 LOW (壓下)時呼叫亮度調整程式,達到本 實驗
的要求。
6-5 延伸應用與練習
6-5 延伸應用與練習
6-5 延伸應用與練習
6-5 延伸應用與練習
6-5 延伸應用與練習
一切準備就緒後,接著開始進行編譯程式,以及下載、燒錄、測 試的工作;請依以下步驟進行測試:
1. 點選 Tools →
Serial Monitor ,開啟
電腦端的 Serial Monitor 。 2. 壓放開關 S1 一次,觀察
Serial Monitor 上的數 值變化,每壓放一次數值 是否遞增加 5 , LED 亮度 是否有變化。
6-5 延伸應用與練習
3. 當壓下 S1 時 Serial Monitor 會立即有數值變化,還 是放開 S1 時變化呢?
4. 快速壓放按鍵,觀察 Serial Monitor 上的數值與 LED 亮度變化,是否符合預期,其中因為 LED 為低態動作的電 路結構,故數值愈少, LED 愈亮。
5. 久按開關 S1 超過 1 秒後,觀察 Serial Monitor 上 的數值與 LED 亮度,有否快速自動變化,放開時會立即停 住。