按著按鈕不放,LED 竟然開始閃爍?真讓人頭痛! 獨門「旗標」技巧大公開,人人都能設計超完美電子開關!
在上一堂課程,我們推出了按鈕特輯的第一集!有動手完成小專案的各位應該會發現,雖然每次按下按鈕,LED 的狀態就會改變,但如果按著按鈕不放,LED 就會開始閃爍。這麼不人性化的設計,我們就要在今天推出的「按鈕特輯第二集」,好好的改良一下啦!
回想一下!我們在 Class 8 的程式碼當中,採用了 delay() 來防止開關彈跳。坦白來說,我們等於讓 Arduino 負責兩個很單純的工作:第一,就是每間隔 200 毫秒,就看一下開關的狀態;第二,只要發現開關是被按下去的,就切換一次 LED 的狀態。
在這樣的情況下,當你按著按鈕不放,Arduino 就會在每 200 毫秒的時候,讀取到按鈕被按下去的訊息,然後將 LED 的狀態相反。這樣的程式,缺少了一個很重要的機制,就是在切換 LED 狀態之前,先檢查使用者有沒有把按鈕放開再按下。這也就是為什麼,我們會遇到 LED 閃爍的問題了。
邏輯運算符號
今天,我們要透過一個叫做「旗標 (Flag)」的技巧,來對付這個詭異的閃爍現象。不過,在使用旗標之前,我們必須先了解一個非常重要的概念,叫做「邏輯運算」。我們把上一集 Class 8 的程式碼,借過來當例子:
今天你的朋友又來了,他說:你在接腳 7 外接了一個按鈕來當作 LED 的開關,恩,這樣很不錯耶。那如果我在接腳 8 也裝一個按鈕,然後,只有當兩個按鈕「都」被按下去的時候,LED 才切換一次狀態,那你該怎麼做呢?
這下你又崩潰了,因為這感覺是一個很麻煩的工作。難道要在 if 裡面再放一個 if,來判斷第二顆按鈕的狀態嗎?其實不用。你只需要把第二個判斷條件,放在第一個判斷條件的後面,然後中間用一組叫做「AND」或稱作「而且」的邏輯運算符號 && 連接起來,你的任務就完成了。
這個新的判斷式,我們可以解讀成:如果接腳7的按鈕被按下去,而且接腳 8 的按鈕也被按下去,我就切換一次 LED 的狀態。換句話說,這個 if 判斷式,只有在兩個條件都成立的時候才算數,缺一不可。
除了 AND 運算子之外,還有另一個很常使用的邏輯運算符號,是長得像兩根管子 || 的「OR」,它代表的就是「或者」的概念。如果我把剛剛判斷式裡的 AND 符號替換成 OR,這段敘述就會變成:如果接腳7的按鈕被按下去,或者接腳 8 的按鈕被按下,程式就切換 LED 的狀態。
也就是說,只要有任何一個與 OR 相連的條件成立,不管是你只按下一顆按鈕,或是兩顆按鈕都按,這個 if 判斷式都會是成立的。
這邊要特別注意的是,邏輯運算符號跟雙等號一樣,我們必須一次輸入兩個符號,中間不能有空格。如果你不小心手滑,只輸入了一個,就會變成「位元運算符號 (Bitwise Operators)」,它代表的意義跟邏輯運算完全不同,這是很容易出錯的地方,一定要特別小心喔!
小專案:透過旗標設計人性化開關
現在,來到今天的重頭戲!也就是學習「旗標」技巧的使用。我們知道,如果要設計一個比較人性化的開關,除了要考慮有沒有人去按這顆按鈕之外,更重要的是,使用者必須先經過「放開按鈕」這個動作,才能再一次透過「按下按鈕」來切換 LED 的狀態。
所以,這就是我們要對 Class 8 的程式碼動刀的地方囉!我們先把 loop() 裡面的東西清乾淨,只留下一個 if 判斷式。接著,在程式的最上面,我們要宣告第二個 boolean 型態的變數,比如說叫 buttonUp,預設為 true。這個 buttonUp 就是用來紀錄「按鈕放開了嗎?」這件事情,你可以把它想像成一個告示牌,如果上面寫的是 true,代表按鈕曾經被放開過了;如果是 false,則代表按鈕還沒有被放開。
前置作業完成之後,我們就要來處理 if 判斷式 。想要切換 LED 的狀態,我們必須「同時」滿足兩個條件:第一,有人去按了這顆按鈕;第二,就是從上一次 LED 的狀態被切換之後,這個按鈕「曾經」被放開過。把剛才那段話轉換成程式,就會變成如果 digitalRead(7) 不等於 HIGH,而且 buttonUp 為 true。
只要這兩個條件都成立了,我們就切換一次 LED 的狀態。還沒結束喔!接下來我們必須將 buttonUp 從 true 更改為 false。這麼做的目的是,在 LED 的狀態被切換以後,即使程式回到 loop() 開頭,發現按鈕還沒放開,這個 if 條件式也會因為 buttonUp 被替換成 false 而無法成立,當然,就不會去改變 LED 的狀態!
好了。下一個最重要的事情,就是:如果按鈕被放開了,該怎麼辦?這時候,我們就需要第二個判斷式,在按鈕被放開的時候,將告示牌上的 false 更改回 true。所以囉!我們可以將剛才 if 設定的條件通通相反,當作 else if 的成立條件。當 else if 成立的時候,我們只需要做一件事情,就是將 buttonUp 從 false 更改回 true。
旗標技巧步驟分解
我們來實際跟著程式走一遍,你就會知道為什麼加上了 buttonUp 這個旗標,可以讓我們設計出一個非常人性化的電子開關。我們先假設一開始沒有人去按這顆按鈕。當程式做完一系列初始化的工作之後,進入 loop() 迴圈。
我們可以看到第一個 if 條件式不成立,else if 也不成立,所以 Arduino 等於是在閒置的狀態,或者你也可以說它在裝忙啦。但是!當我按下按鈕時,loop() 當中的 if 判斷式就成立了,除了把 LED 的狀態相反之外,還把 buttonUp 從 true 更改為 false。
這樣一來,即使按鈕按著不放,兩個判斷式也都不會成立,Arduino 又開始進入裝忙的狀態。
最後,當我們把按鈕放開,loop() 當中的 else if 就成立了,把 buttonUp 從 false 更改回 true。
於是,Arduino 又因為兩個判斷式都不成立,回到裝忙的狀態,然後等待使用者再次按下按鈕時,重複前面的這些步驟。
這個新設計的開關,因為使用了旗標而擁有非常好的穩定性,如果你在按按鈕的過程中,發現 LED 仍然有不穩定、會閃爍的情況,不妨在 loop() 裡面加上一個 10 毫秒的 delay,可以避免開關抖動造成的機械彈跳唷!
當然,這種人性化的防彈跳開關有非常多不同的設計方法,就有待朋友們自己去發掘囉!
ONE LAST THING
還記得在 Arduino SpeedUp 系列的 Class 1 當中,我們有提到「模組」的概念嗎?在下一堂課程 ,我們要整合今天介紹的旗標技巧,以及兩個容易操作的模組,來製作簡單有趣的互動作品,請千萬別錯過下一集按鈕特輯 3 的精彩內容唷!
這一集的 Arduino SpeedUp 就到這裡囉!我們下次見,掰掰!
請問用Blynk的virtualpin建立的虛擬按鈕(swicth mode),我想讓”多個”虛擬按鈕”同時”手動點一下on的狀態持續3分鐘後自動關閉變off狀態(不必手動再點一下),用旗標能達成嗎?boolean該設什麼名稱?謝謝
您好~番茄沒有使用過 Blynk,不過非常感謝你分享的資訊,我們有機會來研究看看哦!