シリアルプロトコル

I2CとSPI、UARTシリアルプロトコルを学びます。


Author: Karl Söderby、Last revision: 2024/02/05


シリアルプロトコルは、異なる回路や機器間でデータを受け渡しする手段なので、電気設計の基本です。

シリアルプロトコルはデジタル信号で構成され、システム間で1と0を巧妙な方法です。多くのシリアルプロトコルがありますが、この章では、Arduinoで動作する、I2CとSPI、UARTの3つの重要なプロトコルに着目します。

この章では以下を学びます。

  • I2CとSPI、UARTとは何かと、動作方法の簡単な説明
  • I2Cを使ったセンサーデータの読み取り方法
i
この章では、以前の章よりも高度なトピックを紹介します。しかし、より複雑な(しかし、より楽しい)デバイスとのやりとりを少し簡単にするために、いくつかの重要な知識を学びます。

シリアルプロトコル

シリアルプロトコルは、直列に1ビットずつ電気データを送信するための技術の総称です。デジタル信号について以前、2つの状態(1: HIGI、0: LOW)しか持たないことを学びました。

ここでは、超高速でデータを正確に転送するのに、どのようにデジタル信号が使われるかを見ていきます。これは、Arduinoだけの基本技術ではなく、世界中のコンピュータシステムで実際に使われています。

シリアルプロトコルを理解するために、ビットと二進数が何かを簡単に紹介します。

ビットと二進数

ビットは、1つの情報で、0か1のどちらかの値だけを保持します。デジタル信号は、0か1を生成したり、読み取ったりするなどできます。

しかし、何かがオンで、何かがオフという、2つの値だけを使うのは原始的です。ここで二進数を紹介します。この方式は以下の例のように、0と1とで表現します。

  • 0101

十進数には慣れています。例えば、数値を5と設定すると、数値は5だとわかります。しかし、二進数では、十進数の5は、0101と表します。

これはなぜ重要なのでしょうか? 0101=5ということは知っています。この知識を使えば、デジタル信号で実際に数字の5を以下のように送信できます。

  • 最初にLOW信号(0)を送る
  • 次にHIGH信号(1)を送る
  • 次にLOW信号(0)を送る
  • 最後にHIGH信号(1)を送る

これを、このパターンを受信するよう設定されているシステムに送信すると、数字の5を受信し、シリアル経由でデータを送ったことになります。これが、コンピュータが互いにデータをやり取りする方法です。

上記は、シリアルプロトコルの動作方法の大まかな説明です。実際には、もっと複雑です。幸運にも、簡単な方法でデータを送信するためのシリアルプロトコルがあります。

この基本的な知識で、I2CとSPI、UARTプロトコルについて学び始めることができます。この章で紹介する全てのプロトコルは、双方向通信をサポートしています。つまり、データはどちらの方向にでも送信できます。

Inter-Integrated Circuit(I2C)

I2Cデバイスの接続方法

I2Cデバイスの接続方法

I2Cは、最大128までのデバイスを、同じ2本の線で接続できるプロトコルです。これらの線は、Serial Data(SDA)とSerial Clock(SCL)と呼ばれています。

I2Cを使う機器は、異なるアドレス(0x0cのような)を持っています。I2Cプロトコルでは、そのアドレスにだけアクセスしたり、他のアドレスを使いデータを送受信できます。

例えば、センサーとディスプレイを同じピンに接続でき、センサーデータを読み取り、ディスプレイにその値を表示できます。

これはArduinoで最も使われているプロトコルで、多くのセンサーはコのプロトコルの機能に依存しています。

Serial Peripheral Interface (SPI)

SPIデバイスの接続方法

SPIデバイスの接続方法

SPIは、4線式のプロトコルで、システム間の通信に使われます。一般的にI2Cno2倍速いので、ディスプレイなどの多くのセンサーがSPIプロトコルを使っています。しかし、デバイスの追加は複雑です。

SPIを使うためには、以下の4本の専用ピンが必要です。

  • COPI - Controller Out, Peripheral In
  • CIPO - Controller In, Peripheral Out
  • SCK - Serial Clock
  • CS - Chip Select

COPI/CIPOはデータ転送に使われます。SCKはデータ転送の同期に使われます。

最後に、チップ選択(CS)ピンは、どのデバイスとコントローラーが通信するかを決めるのに使われます。

Universal Asynchronous Receiver-Transmitter (UART)

UARTは、最も古く歴史があり、よく使われるシリアルプロトコルです。UARTコントローラーは2線(TX/RX)で、2つのデバイスを接続します。

ビットの情報は、あるデバイスから他のデバイスに逐次送信され、受信側ではビットを完全なバイトに再構築します。

UARTは、2デバイス間の1対1通信には理想的で、2線と追加のクロックだけを必要とします。SPIよりは非常に遅いですが、設定と利用が簡単で、もちろん、少ない線を使います。

UARTデバイスの接続方法

UARTデバイスの接続方法

演習: I2Cセンサー

この演習では、I2C経由で接続されたセンサーの値を読み取ります。LIS3DHTRという有名な加速度センサーを使います。

加速度センサーをボードに接続するには、以下の図に従ってください。

LIS3DHTR回路

LIS3DHTR回路

このモジュールを使うには、lis3dhモジュールをインストールする必要があります。以下のコマンドを実行して、インストールしてください。

1
mip.install("https://raw.githubusercontent.com/tinypico/tinypico-micropython/master/lis3dh%20library/lis3dh.py")
i
mip.install()の使い方は、MicroPythonの紹介セクションの、“外部モジュールをインストールする"を参照してください。

コードエディタを起動し、以下のスクリプトをmain.pyにコピー・ペーストします。そして、“Run"ボタンをクリックし、実行します。

import lis3dh, time, math
from machine import Pin, I2C

i2c = I2C(sda=Pin(8), scl=Pin(9))
imu = lis3dh.LIS3DH_I2C(i2c, address=0x19)

last_convert_time = 0
convert_interval = 100 #ms
pitch = 0
roll = 0


# Convert acceleration to Pitch and Roll
def convert_accell_rotation( vec ):
    x_Buff = vec[0] # x
    y_Buff = vec[1] # y
    z_Buff = vec[2] # z

    global last_convert_time, convert_interval, roll, pitch

    # We only want to re-process the values every 100 ms
    if last_convert_time < time.ticks_ms():
        last_convert_time = time.ticks_ms() + convert_interval

        roll = math.atan2(y_Buff , z_Buff) * 57.3
        pitch = math.atan2((- x_Buff) , math.sqrt(y_Buff * y_Buff + z_Buff * z_Buff)) * 57.3

    # Return the current values in roll and pitch
    return ( roll, pitch )

# If we have found the LIS3DH
if imu.device_check():
    # Set range of accelerometer (can be RANGE_2_G, RANGE_4_G, RANGE_8_G or RANGE_16_G).
    imu.range = lis3dh.RANGE_2_G

    # Loop forever printing values
    while True:
        # Read accelerometer values (in m / s ^ 2).  Returns a 3-tuple of x, y,
        # z axis values.  Divide them by 9.806 to convert to Gs.
        x, y, z = [value / lis3dh.STANDARD_GRAVITY for value in imu.acceleration]
        print("x = %0.3f G, y = %0.3f G, z = %0.3f G" % (x, y, z))

        # Convert acceleration to Pitch and Roll and print values
        p, r = convert_accell_rotation( imu.acceleration )
        print("pitch = %0.2f, roll = %0.2f" % (p,r))

        # Small delay to keep things responsive but give time for interrupt processing.
        time.sleep(0.1)

端末には、加速度センサーからのデータが1秒ごとに送信されているのがわかります。これは、I2Cプロトコルを使い、センサーから直接データを取得したデータです。

おめでとうございます。2つの複雑なシステムを接続し、互いに通信できるようになりました。

まとめ

この章では、Arduinoでの3つの一般的なシリアルプロトコルである、I2CとSPI、UARTを学びました。これらのシリアルプロトコルの基本を取り上げ、I2Cでセンサーデータを読み取る例を紹介しました。

シリアルプロトコルは高度なトピックで、この章では、例がどのように動作するかがわかるように、一部だけを取り上げました。

シリアルプロトコルの詳細を学ぶには、“communication” section in docs.arduino.cc.を参照してください。

次の章: MicroPythonでIoT

オリジナルのページ

https://docs.arduino.cc/micropython/micropython-course/course/serial/

最終更新日

April 14, 2024

inserted by FC2 system