MicroPython按鈕控制

micro:bit有兩個可程式化按鈕,讓我們可以和micro:bit進行互動,這兩個按鈕在設計小遊戲的時候非常好用。那麼,如果使用MicroPython,要如何去偵測這個按鈕呢?答案是is_pressed()這個函數,而按鈕A是button_a,按鈕B則是button_b,以下是一個簡單的運用按鈕改變圖案的例子:

from microbit import *
display.show(Image.HEART)
while True:
if button_a.is_pressed():
display.show(Image.HAPPY)
elif button_b.is_pressed():
display.show(Image.SAD)

上面這個程式在一開始執行的時候會顯示愛心圖案,如果按下去A按鈕就會變成笑臉,按下去B按鈕則變成哭臉。之後就只能在笑臉和哭臉之間做變化,因為在無窮迴圈中只有這兩種選擇。

假設我們想要讓使用者在同時按下A和B按鈕(也就是積木中的A+B按下事件)就恢復成愛心圖案的話,也許你會想到以下此種方式:

請注意,以下的程式是錯誤的!

from microbit import *
display.show(Image.HEART)
while True:
if button_a.is_pressed():
display.show(Image.HAPPY)
elif button_b.is_pressed():
display.show(Image.SAD)
elif button_a.is_pressed() and button_b.is_pressed():
display.show(Image.HEART)

上面這個程式的邏輯是,如果A按鈕被按下去就顯示笑臉,否則如果B按鈕被按下去的話就顯示哭臉,否則如果A按鈕被按下去而且B按鈕也被按下去的話,就會顯示愛心圖案。

邏輯上看起來沒問題,但其實存在一個嚴重的瑕疵,那就是第9行的條件其實同時包含了第5行和第7行的條件,意思是說,任一個按鈕被按下去時,一定會先滿足第5行或是第7行的條件,如此第9行的那個條件根本就沒有機會被執行到。

改正的方法是,把第9行的條件移到最前面去,先檢查是否兩個按鈕同時被按下,如果有就換成愛心圖案,如果沒有的話,再分別檢查A和B按鈕有沒有其中一個被按下去。修正後的程式如下:

請注意,底下的程式仍然有一些問題喔

from microbit import *
display.show(Image.HEART)
while True:
if button_a.is_pressed() and button_b.is_pressed():
display.show(Image.HEART)
elif button_a.is_pressed():
display.show(Image.HAPPY)
elif button_b.is_pressed():
display.show(Image.SAD)

同學們可以執行上述的程式看看問題在哪裡!

發現了嗎?A按鈕和B按鈕都沒問題,但是當A和B同時按下時的那一瞬間是可以切換成愛心的,可是當手一鬆開按鈕的時候就會發現,圖案馬上又恢復成笑臉或哭臉了,端看你的那一隻手指放得比較慢一些。

造成這個問題的原因在於A和B按鈕同時放開的時候,其中一個按鈕會放得慢一些,而由於程式運行的速度很快,很快地又回到按鈕的判斷,此時很快地又判斷到其中一個按鈕被按下去,因此立刻又被切換成該按鈕的符號了。為了解決這個問題,在換成愛心圖案之後讓程式暫停個一秒鐘,使得們的手指來得及同時鬆開按鈕,就不會有問題了。完成後的程式如下所示:

from microbit import *
display.show(Image.HEART)
while True:
if button_a.is_pressed() and button_b.is_pressed():
display.show(Image.HEART)
sleep(1000)
elif button_a.is_pressed():
display.show(Image.HAPPY)
elif button_b.is_pressed():
display.show(Image.SAD)

以下這個程式執行之後,平時它會以顯示愛心的符號,當按下A按鈕時,則會顯示笑臉,在按下B按鈕後,則會顯示哭臉。然而有一個要讓同學們比較的地方是,在程式中,每顯示一個圖案都會暫停5秒鐘,在這段期間內,程式是沒有在運作的,如果你在這段暫停時間內按下按鈕的話,這個按下去的動作會被忽略掉,這也是為什麼下面這個程式在執行的時候,你會覺得按鈕好像不太靈敏的樣子,有時候可以換圖案,有時候又不行:

from microbit import *
while True:
if button_a.is_pressed():
display.show(Image.HAPPY)
sleep(5000)
elif button_b.is_pressed():
display.show(Image.SAD)
sleep(5000)
else:
display.show(Image.HEART)
sleep(5000)

為了避免上述的問題發生,當然把sleep的時間減少是一個方法,但是,最好的方法是把is_pressed()改成was_pressed(),這個函數不是回傳偵測的當時按鈕被按下去的情形,而是檢查在前一次偵測到這一次的偵測期間按鈕是否曾經被按下過,只要按過就會回傳True,如此就可以改善前一個程式所遇到的問題了。

from microbit import *
while True:
if button_a.was_pressed():
display.show(Image.HAPPY)
sleep(5000)
elif button_b.was_pressed():
display.show(Image.SAD)
sleep(5000)
else:
display.show(Image.HEART)
sleep(5000)

除了is_pressed()以及was_pressed()這兩個函數之外,還有一個函數get_presses()是用來紀錄從上一次呼叫檢查按鈕的函數到現在,某一個按鈕總共被按了幾次。以下的程式例執行的時候會開始倒數10秒,時間到之後會顯示在這期間,按鈕A總共被按了幾次:

from microbit import *
for i in range(9, -1, -1):
display.show(i)
sleep(1000)
display.show(Image.HEART)
sleep(1000)
number = button_a.get_presses()
display.show(number)