前回の記事から少し間が空きましたが、ラズパイPico+MicroPythonを用いた電子工作入門を再開していきます
今回からシリアル通信を試していきたいと思います。初めにUARTによる通信を試していきます。
UARTの概要
UART は I2C、SPI と並んで、マイコンで最も一般的に利用されるシリアル通信方式です。 シリアル通信は、1 本の信号線を用いて(双方向通信の場合は 2 本)、データを 1 ビットずつ送受信する方式です。送信側が 1 ビットを送り、受信側がそれを受け取るという単純な動作を繰り返すことでデータを伝送します。 このような通信を行うには、受信側・送信側ともに共通の信号(クロック)に従って動作する必要があります。 クロック信号を送受信側で共有する方式を同期通信、共有しない方式を非同期通信と呼び、UART は名称の “Universal Asynchronous Receiver Transmitter” の通り非同期通信に分類されます。
UARTのメリット
非同期通信である UART ではクロック信号を共有しないため、送受信間の配線は信号線と GND のみで済みます。 実装がシンプルで、クロック同期を気にする必要がないため長距離通信にも向いています。 I2C や SPI と比べると通信速度は遅いものの、扱いやすさから産業用の計測機器などで未だに使用する場面があります。
UARTの通信方式
クロックを共有しないため、送受信側であらかじめ1ビットの時間幅(ボーレート)やデータ長を一致させておく必要があります。 また、通信の開始と終了を示すために、データにスタートビットとストップビットを付与する必要があり、オーバーヘッドが大きく効率はあまり良くありません。 一般的には、スタートビット 1bit、データビット 8bit(パリティを含む場合は 7bit)、ストップビット 1〜2bit といった構成がよく使われます。
一般的に無信号区間は"1"の状態を維持するため、スタートビットは"0", ストップビットは"1"で固定となります。
ラズパイPicoによるUART
ラズパイPicoに搭載されたマイコンRP2040は2個のUARTコントローラーを持ち、以下のGPIOピンにマッピングすることが出来ます。
| id | TX | RX |
|---|---|---|
| 0 | GPIO 0, 12, 16 | GPIO 1, 13, 17 |
| 1 | GPIO 4, 8 | GPIO 5, 9 |
UARTのid番号、ボーレート、TX, RXとして使用するPinオブジェクトなどを引数にしてUARTオブジェクトを作成して通信を開始します。
uart1 = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
サンプルプログラム
2 台の Pico を使って送受信を確認するのが分かりやすいのですが、今回は都合により 1 台の Pico 内で通信を行います。uart0 と uart1 の 2 つの UART オブジェクトを作成し、uart0 から送信したデータを uart1 で受信します。 例として、Pico 内蔵の CPU 温度センサの値を読み取り、その値を UART で送受信してみます。 ジャンパピンの接続は、2 つの UART 間で TX と RX がクロスするように接続します(2 台の Pico を使う場合は GND を共通にする必要があります)。
# Raspberry Pi PicoのCPU温度を読み込み、UARTで送信/受信する import time, utime from machine import Pin, ADC, UART temp_sensor = ADC(4) led = Pin("LED", Pin.OUT, value=0) uart0 = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1)) uart1 = UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5)) def send_temp(): read_value = temp_sensor.read_u16() * (3.3 / 65535) temp = 27 - (read_value - 0.706) / 0.001721 message = f"temperature: {temp:.1f} degree\n" uart0.write(message) time.sleep(1) def receive_temp(): if uart1.any(): led.value(1) print(uart1.readline()) utime.sleep_ms(50) led.value(0) else: utime.sleep_ms(50) while True: send_temp() receive_temp()
1秒ごとに温度が受信できればOKです!






