🐥

【Raspberry Pi Pico W】UARTの使い方(micropython×Thonny)

2025/02/01に公開

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さんの記事が分かりやすかったので、こちらをご覧ください。
https://www.analog.com/jp/resources/analog-dialogue/articles/2020/11/24/18/10/uart-a-hardware-communication-protocol.html

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
https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html

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関数が呼ばれる
UART_selfcheck.py
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ドライバのインストール方法
https://qiita.com/hamukun8686/items/aa0b2096a83ff9acccf2

出力(参考)

port(COM)の確認方法

CP2102をPCに接続した状態で、「デバイスマネージャー」で確認できます
私の環境では、「COM6」でした

pyserialのインストール

PCのpython環境(Not microPython)にpipで入れました

python -m pip install pyserial

参考:pySerial — pySerial 3.4 documentation
https://pyserial.readthedocs.io/en/latest/pyserial.html

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を適当に変更してください

send_data_by_pyserial.py
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時に実行されるようにしておきましょう

main.py
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