【Raspberry Pi Pico W】UARTの使い方(micropython×Thonny)
1. はじめに
1.1 この記事について
- Raspberry Pi Pico W(以下、Pico)のUARTを使ったサンプルプログラムを記載する
- 細かい解説というより、備忘録とプログラム+回路図のサンプル重視
- 入門・解説というより備忘録に近い
1.2 対象読者
- Picoを使ったことがある
- Thonnyを使ってPicoにプログラムを書き込み・実行ができる
- プログラム言語(特にmicropython)が多少読める、書ける
1.3 動作環境
- PC
- OS:Windows 11 Home
- プログラミング環境:Thonny(v4.1.4)
- Python 3.12.5
- pyserial : 3.5
- Raspberry Pi Pico W
- ファームウェア:v1.24
2. UARTについて
- UART(Universal Asynchronous Receiver/Transmitter)とは、デバイス間の通信プロトコルの1つ
- 送信側と受信側のデバイスで、baud rate(ボー・レート)を同じにしておく必要がある(許容誤差は最大10%)
- 通信に使用する配線は、以下の2種類
- TX : トランスミッター(送信用)
- RX : レシーバー(受信用)
詳しくは...
Analog Devicesさんの記事が分かりやすかったので、こちらをご覧ください。
3. 実験
UARTは通常、2つのデバイス間で通信を行います。
しかし、そのためにはpicoが2つ必要ですが、1つでもUARTの動作確認はできます
pico上では、以下のpinでUARTが使用可能です
- | id | TX | RX |
---|---|---|---|
default | 0 | GP0 | GP1 |
_ | 0 | GP12 | GP13 |
_ | 0 | GP16 | GP17 |
_ | 1 | GP4 | GP5 |
_ | 1 | GP8 | GP9 |
参考:Pico-series Microcontrollers - Raspberry Pi Documentation
3.1 picoでUARTセルフチェック
picoでTXとRXを直結して、自分で送信した信号を受信させてみます。
3.1.1 配線図
TXとRXを直接つなぎます
3.1.2 実際の動画
BOOTSELボタンを押すと、LEDが1秒付きます
3.1.3 プログラム
- BOOTSELボタンを押下したら、データを送信する
- UARTで何かデータを受信したら、割り込みが発生しshow_received_message関数が呼ばれる
from machine import Pin, UART
from time import sleep_ms
led = Pin("LED", Pin.OUT, value=0) # LEDピンをOFF状態で定義
uart = UART(0, 9600) # 与えたボーレートで初期化
def show_received_message(uart):
led.on()
received_txt = uart.read()
sleep_ms(1000)
led.off()
print(type(received_txt), received_txt)
uart.irq(handler=show_received_message, trigger=UART.IRQ_RXIDLE)
send_data = 0
while True:
if rp2.bootsel_button() == 1:
uart.write(str(send_data))
send_data += 1
sleep_ms(100)
3.2 別のデバイスにデータを送信する
さて本番ですが、picoを2つ使ってUARTで通信させてみます。
これによりBOOTSERボタンを押した際に、反対側のpicoのLEDが点灯するようになります
3.2.1 配線図
GNDもpico同士で繋いだほうが、動作が安定します
3.2.2 動画
3.2.3 プログラム
※3.1.3の「UART_selfcheck.py」と同じのため省略
3.3 PCからpicoに指示を送る
最後に、PCからPicoにUART経由でデータを送ってみます
ライブラリはpyserialを使用します
3.3.0 PC側の準備
CP2102を使って通信するために、PC側のセットアップを行います
CP2102のドライバを更新
CP2102のドライバを更新するために、PowerShellを管理者権限で開き、
以下のコマンドを入力・実行します
Invoke-WebRequest -Uri "https://www.silabs.com/documents/public/software/CP210x_Universal_Windows_Driver.zip" -OutFile "$env:TEMP\CP210x_Driver.zip"; Expand-Archive -Path "$env:TEMP\CP210x_Driver.zip" -DestinationPath "$env:TEMP\CP210x_Driver"; pnputil /add-driver (Get-ChildItem -Path "$env:TEMP\CP210x_Driver" -Filter "*.inf" -Recurse).FullName /install; Remove-Item "$env:TEMP\CP210x_Driver.zip"; Remove-Item -Path "$env:TEMP\CP210x_Driver" -Recurse
参考:PowerShellを使用したCP2102ドライバのインストール方法
出力(参考)
port(COM)の確認方法
CP2102をPCに接続した状態で、「デバイスマネージャー」で確認できます
私の環境では、「COM6」でした
pyserialのインストール
PCのpython環境(Not microPython)にpipで入れました
python -m pip install pyserial
参考:pySerial — pySerial 3.4 documentation
3.3.1 配線図
3.3.2 動画
実行時のPC画面
PC側がデータ「moge」を送信した後、picoが送信したデータ「data_from_pico」を受信している
実行時のpico
LEDが1秒点灯するのと、データ送信時にCP2102のLEDが一瞬光ります
3.3.3 プログラム
PC側
実行すると、"moge"という文字列をpico側へ送付します(文字列は何でもよいです)
私の環境では「COM6」だったのですが、もし違ったらportのCOMを適当に変更してください
import serial
import serial.tools.list_ports
# for port in serial.tools.list_ports.comports(): # COMポート確認時に使用
# print(f"{port.name=}, {port.device=}") # COMポート確認時に使用
send_data = b"moge\n" # 送る文字列(byte型)
with serial.Serial(port="COM6", baudrate=9600, timeout=3) as ser:
# 送信:TX
ser.write(send_data) # picoへデータを送信
# 受信:RX
res_data = ser.readline() # picoへデータを受信
print(type(res_data), f"{res_data=}")
pico側
外部電源などで動かす際は「main.py」にして電源ON時に実行されるようにしておきましょう
from machine import Pin, UART
from time import sleep_ms
led = Pin("LED", Pin.OUT, value=0) # LEDピンをOFF状態で定義
uart = UART(0, 9600) # 与えたボーレートで初期化
def show_received_message(uart):
led.on()
received_txt = uart.read() # PCからデータを受信
print(type(received_txt), received_txt)
sleep_ms(1000)
led.off()
uart.write(b'data_from_pico\n') # PCへデータを送信
uart.irq(handler=show_received_message, trigger=UART.IRQ_RXIDLE)
while True:
sleep_ms(100)
備考
受信したデータは「class 'bytes'」なので、bytes型で比較演算したほうがよさそうです
- 17行目:str型に変換して==で比較 => False
- 18行目:bytes型のまま==で比較 => True
4. まとめ
- UART通信を使ったサンプルコードをまとめた
- デバイス同士での通信はもちろん、PCからUSB経由でpicoへ指示を送ることもできる
- UARTで動作するデバイス(DFT Playerなど)もあるため、そちらも今後試してみたい
Discussion