I2CとSPI、UARTシリアルプロトコルを学びます。
Author: Karl Söderby、Last revision: 2024/02/05
シリアルプロトコルは、異なる回路や機器間でデータを受け渡しする手段なので、電気設計の基本です。
シリアルプロトコルはデジタル信号で構成され、システム間で1と0を巧妙な方法です。多くのシリアルプロトコルがありますが、この章では、Arduinoで動作する、I2CとSPI、UARTの3つの重要なプロトコルに着目します。
この章では以下を学びます。
- I2CとSPI、UARTとは何かと、動作方法の簡単な説明
- I2Cを使ったセンサーデータの読み取り方法
シリアルプロトコル
シリアルプロトコルは、直列に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は、最大128までのデバイスを、同じ2本の線で接続できるプロトコルです。これらの線は、Serial Data(SDA)とSerial Clock(SCL)と呼ばれています。
I2Cを使う機器は、異なるアドレス(0x0c
のような)を持っています。I2Cプロトコルでは、そのアドレスにだけアクセスしたり、他のアドレスを使いデータを送受信できます。
例えば、センサーとディスプレイを同じピンに接続でき、センサーデータを読み取り、ディスプレイにその値を表示できます。
これはArduinoで最も使われているプロトコルで、多くのセンサーはコのプロトコルの機能に依存しています。
Serial Peripheral Interface (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よりは非常に遅いですが、設定と利用が簡単で、もちろん、少ない線を使います。
演習: I2Cセンサー
この演習では、I2C経由で接続されたセンサーの値を読み取ります。LIS3DHTRという有名な加速度センサーを使います。
加速度センサーをボードに接続するには、以下の図に従ってください。
このモジュールを使うには、lis3dh
モジュールをインストールする必要があります。以下のコマンドを実行して、インストールしてください。
|
|
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