# MicroPython按鈕控制

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

```python
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按下事件）就恢復成愛心圖案的話，也許你會想到以下此種方式：

{% hint style="danger" %}
請注意，以下的程式是錯誤的！
{% endhint %}

```python
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按鈕有沒有其中一個被按下去。修正後的程式如下：

{% hint style="warning" %}
請注意，底下的程式仍然有一些問題喔
{% endhint %}

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

```python
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秒鐘，在這段期間內，程式是沒有在運作的，如果你在這段暫停時間內按下按鈕的話，這個按下去的動作會被忽略掉，這也是為什麼下面這個程式在執行的時候，你會覺得按鈕好像不太靈敏的樣子，有時候可以換圖案，有時候又不行：

```python
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，如此就可以改善前一個程式所遇到的問題了。

```python
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總共被按了幾次：

```python
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)
```
