# MicroPython無線電通訊

覺得一個micro:bit的顯示LED不夠用？想要把結果傳送到另外一個micro:bit上面的LED顯示器上？想要兩個micro:bit連線對戰？想要在不同的micro:bit之間傳遞訊息？這些都難不倒micro:bit喔，它內建了無線電通訊模組，想要在不同的micro:bit之間交換訊息，只要簡單的幾個指令就可以完成了。

MicroPython有幾個函數負責在不同的micro:bit之間的無線電通訊，詳細的內容可以在以下這個網址中找到相關的說明：

{% embed url="<https://microbit-micropython.readthedocs.io/en/latest/radio.html>" %}

其中radio.config()用來設定一些初始化的參數，最重要的部份是設定在板子之間要互相溝通用的頻道，如此才不會不小心接受到不相關的板子所傳來的無線電訊號，它使用channel參數來進行設定，預設是7，可以用的頻道是0\~83。

第2個重要的函數是radio.on()和radion.off()，它們分別負責開啟和關閉板子的無線電訊號功能，在使用之前一定要利用radio.on()，才能進行後續的傳送和接收訊息的工作。

傳送訊息使用radio.send()，接收訊息使用radio.receive()，在接收端要特別留意，因為無線電訊號傳送的時候只會傳送一次，時間過了並不會保留該訊號，為了確保一定能夠接收到訊息，radio.receive()通常必需編寫在無窮迴圈中。

{% hint style="info" %}
以下的練習要使用兩塊以上的micro:bit板子，而且兩塊板子上都要寫入具有無線電接收作業的程式才行。
{% endhint %}

先來看看以下的程式，透過無線電訊號傳送一個數字到另外一片板子上：

```python
from microbit import *
import radio

radio.on()

while True:
    if button_a.was_pressed():
        radio.send('Hi')
    msg = radio.receive()
    if msg is not None:
        display.scroll(msg)
        sleep(500)
```

這段程式碼在第2行的地方要匯入radio模組才可順利執行無線電通訊。接著，在無窮迴圈中會檢查這片板子上的A按鈕是否曾被按下，如果有的話，就要送出Hi這個字串。接著，利用radio.receive()函數接收目前在同一個頻道中是否有人送出任何的訊息，在第10行的地方檢查訊息內容是否不為空（not None），如果是的話，就把該字串顯示在這片板子上。

執行上面這個程式，當按鈕A按下去之後，除了自己以外，其它位於同一頻道的板子都會出現Hi這個字樣喔。以下這個程式貼不顯示文字，而是以動畫的形式來取代，大家可以同時使用多片板子，看看會有什麼樣有趣的畫面出現！

```python
from microbit import *
import random
import radio
images = [Image().invert()*(i/9) for i in range(10)]

radio.on()
display.show(Image.HAPPY)
while True:
    if button_a.was_pressed():
        radio.send('go')
    incoming = radio.receive()
    if incoming == 'go':
        sleep(random.randint(100, 500))
        display.show(images, delay=50, loop=False)
        display.show(reversed(images), delay=50, loop=False)
        if random.randint(0, 3) == 0:
            sleep(200)
            radio.send('go')

```

為了展示更多有趣的應用，以下的程式利用5片micro:bit，在每一片板子上寫入2種功能，且每一片板子各自有自己的編號，在收到無線電來的訊息的時候，每一個板子自己都要先確定是否自己是被點名到的對象，如果是的話，就執行動作，並在做完動作之後再送出無線電訊息，讓下一片板子開始工作。在這個例子中micro:bit的排列方式如下：

![](https://2988174335-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LMo8UCGGycRFYs2Gx9M%2F-LfSblF8bJ9IFugXn-DA%2F-LfScYCqLJDOES5SveGH%2F2019-05-22%2011.06.32.jpg?alt=media\&token=8bd743b3-0c19-49c7-89e6-fd8a164b459b)

在一開始執行的時候，每一片板子都會顯示自己的編號，方便我們佈置它們的位置。程式設計如下：

```python
from microbit import *
import random
import radio
images = [Image().invert()*(i/9) for i in range(10)]
airplane = list()
airplane.append(Image(
    '00000:'
    '00000:'
    '00000:'
    '00000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '00000:'
    '00009:'
    '00000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '00000:'
    '00099:'
    '00000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '00009:'
    '00999:'
    '00009:'
    '00000'))
airplane.append(Image(
    '00009:'
    '00090:'
    '09999:'
    '00090:'
    '00009'))
airplane.append(Image(
    '00090:'
    '00900:'
    '99999:'
    '00900:'
    '00090'))
airplane.append(Image(
    '00900:'
    '09009:'
    '99999:'
    '09009:'
    '00900'))
airplane.append(Image(
    '09000:'
    '90090:'
    '99990:'
    '90090:'
    '09000'))
airplane.append(Image(
    '90000:'
    '00900:'
    '99900:'
    '00900:'
    '90000'))
airplane.append(Image(
    '00000:'
    '09000:'
    '99000:'
    '09000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '90000:'
    '90000:'
    '90000:'
    '00000'))
airplane.append(Image(
    '00000:'
    '00000:'
    '00000:'
    '00000:'
    '00000'))
my_channel = 1
next = 2
radio.on()
display.show(my_channel)
while True:
    if button_a.was_pressed():
        radio.send('go 1 1')
    elif button_b.was_pressed():
        radio.send('go 1 2')
    incoming = radio.receive()
    if incoming is not None:
        commands = incoming.split()
    else:
        commands = list()
    if len(commands) > 2:
        if commands[0] == 'go' and my_channel == int(commands[1]):
            if int(commands[2]) == 1:
                sleep(random.randint(100, 500))
                display.show(images, delay=50, loop=False)
                display.show(reversed(images), delay=50, loop=False)
                radio.send("go {} 1".format(next))
            elif int(commands[2]) == 2:
                display.show(airplane, loop=False, delay=200)
                radio.send("go {} 2".format(next))
```

在程式開始的地方除了記錄一些要製作動畫的串列變數之外，第78行設定的是自己的編號，第79行設定的next變數則是下一個要動作的號碼，利用next的指定，即可讓一些micro:bit的運用變成無窮的循環動畫。

在第84行送出第一個命令，它決定了開始動作的板子（第1個參數，在這個例子是1）以及要顯示的動畫（第2個參數），如果按下的是A按鈕，則執行第1個動畫，如果按下的是B按鈕，則執行第2個動畫。

在 89行拆解收到的訊息，在第93行的地方檢查是否是自己需要進行動畫，在第94行判斷是否為第1種動畫，第99行則是檢查是否為第2種動畫效果。以下是執行的結果影片：

{% embed url="<https://youtu.be/FYIZOx1KFzE>" %}
