I2C・SPI・UART通信入門:初心者でも分かる通信プロトコル完全ガイド

投稿者: | 2025年7月19日



Arduino・Raspberry Pi・ESP32で必須の3つの通信方式を実例付きで徹底解説

目次

🎯 この記事で学べること

  • I2C・SPI・UARTの基本的な仕組み
  • 各通信方式の使い分け方法
  • 実際の配線方法とプログラミング例
  • よくあるトラブルと解決方法
  • おすすめセンサーと活用例

📡 通信プロトコルって何?

マイコンボード(Arduino、Raspberry Pi、ESP32など)を使って電子工作をするとき、必ず出てくるのが「通信」です。

通信プロトコルとは、マイコンとセンサーやディスプレイなどの部品が「どうやって情報をやり取りするか」の約束事のこと。人間同士の会話に「言語」があるように、電子部品同士にも「共通言語」が必要なんです。

身近な例で考えてみよう

例えば、温度センサーがマイコンに「今の温度は25.3℃です」と伝えたい場合:

  • 人間なら:「25.3℃」と口で言う
  • 電子部品なら:電気信号のパターンで伝える

この「電気信号のパターン」のルールが通信プロトコルです!

3つの主要通信プロトコル概要

通信方式 配線数 複数接続 速度 主な用途 難易度
UART 2本 1対1のみ 中速 PCとの通信、GPS 簡単
I2C 2本 複数OK 低速 センサー、RTC ⭐⭐ 普通
SPI 4本 複数OK 高速 ディスプレイ、SD ⭐⭐⭐ やや難

📞 UART通信:シンプルで確実

UARTとは?

UART(Universal Asynchronous Receiver Transmitter)は、最もシンプルな通信方式です。2本の線だけで、1対1の通信ができます。

🔌 UART配線図

必要な配線(たった2本!):

  • TX(送信) ← → RX(受信)
  • RX(受信) ← → TX(送信)

※ TXとRXは交差して接続することがポイント!

UARTの良いところ

  • 配線が簡単(2本だけ)
  • 理解しやすい
  • 確実に動作する
  • 長距離通信も可能

UARTの注意点

  • 1対1通信のみ
  • 複数のセンサーには不向き
  • 速度がそれほど速くない

UART実装例:GPSモジュールとの通信

Arduino コード例

// GPSモジュール(NEO-6M)からデータ受信
#include <SoftwareSerial.h>

SoftwareSerial gpsSerial(4, 3);  // RX=4, TX=3

void setup() {
  Serial.begin(9600);      // PCとの通信用
  gpsSerial.begin(9600);   // GPSとの通信用
  
  Serial.println("GPS データ受信開始");
}

void loop() {
  // GPSからデータが来た場合
  if (gpsSerial.available()) {
    String gpsData = gpsSerial.readString();
    Serial.print("GPS: ");
    Serial.println(gpsData);
  }
  
  // PCからコマンドが来た場合
  if (Serial.available()) {
    String command = Serial.readString();
    gpsSerial.println(command);  // GPSにコマンド送信
  }
}
Raspberry Pi(Python)コード例

import serial
import time

# シリアルポート設定
gps = serial.Serial('/dev/ttyS0', 9600, timeout=1)

def read_gps_data():
    if gps.in_waiting > 0:
        data = gps.readline().decode('utf-8').strip()
        
        # NMEA形式の位置情報を解析
        if data.startswith('$GPGGA'):
            parts = data.split(',')
            if len(parts) > 6 and parts[2] and parts[4]:
                lat = float(parts[2][:2]) + float(parts[2][2:]) / 60
                lng = float(parts[4][:3]) + float(parts[4][3:]) / 60
                print(f"位置: 緯度 {lat}, 経度 {lng}")

while True:
    read_gps_data()
    time.sleep(1)

UART活用例

  • GPS位置情報取得:カーナビ、ドローン
  • PCとの通信:デバッグ情報表示
  • 他のマイコンとの通信:システム分散
  • Bluetoothモジュール:スマホ連携

🔗 I2C通信:複数接続の便利屋

I2Cとは?

I2C(Inter-Integrated Circuit)は、2本の線で複数のデバイスと通信できる賢い方式です。各デバイスには「アドレス」があり、まるで住所のように使い分けできます。

🔌 I2C配線図

必要な配線(2本で複数接続):

  • SDA(データ線):実際のデータのやり取り
  • SCL(クロック線):タイミングを合わせる

※ 複数のセンサーを並列に接続可能!

I2Cアドレスって何?

I2Cでは、各デバイスに固有のアドレス(7ビットの数字)が割り当てられています。

  • 温度センサー BME280:0x76
  • 加速度センサー MPU6050:0x68
  • リアルタイムクロック DS3231:0x68

アドレスが被った場合は、別の部品を選ぶか、アドレス変更可能な部品を選びます。

I2Cの良いところ

  • 配線が少ない(2本で複数接続)
  • アドレスで識別できる
  • センサーに最適
  • ライブラリが豊富

I2Cの注意点

  • 速度がやや遅い
  • プルアップ抵抗が必要
  • 長距離通信には不向き
  • アドレス重複に注意

I2C実装例:温湿度センサー(BME280)

Arduino コード例

#include <Wire.h>
#include <Adafruit_BME280.h>

Adafruit_BME280 bme; // I2Cアドレス 0x76

void setup() {
  Serial.begin(9600);
  
  // I2C初期化
  if (!bme.begin(0x76)) {
    Serial.println("BME280 センサーが見つかりません");
    while (1);
  }
  
  Serial.println("BME280 センサー準備完了");
}

void loop() {
  // センサー値読み取り
  float temperature = bme.readTemperature();
  float humidity = bme.readHumidity();
  float pressure = bme.readPressure() / 100.0F;
  
  // シリアルモニターに出力
  Serial.print("温度: ");
  Serial.print(temperature);
  Serial.print("°C, 湿度: ");
  Serial.print(humidity);
  Serial.print("%, 気圧: ");
  Serial.print(pressure);
  Serial.println("hPa");
  
  delay(2000);  // 2秒待機
}
ESP32 複数センサー例

#include <Wire.h>
#include <Adafruit_BME280.h>
#include <MPU6050.h>

Adafruit_BME280 bme;    // 温湿度センサー(0x76)
MPU6050 mpu;            // 加速度センサー(0x68)

void setup() {
  Serial.begin(115200);
  Wire.begin();
  
  // 複数センサー初期化
  if (!bme.begin(0x76)) {
    Serial.println("BME280 初期化失敗");
  }
  
  if (!mpu.begin()) {
    Serial.println("MPU6050 初期化失敗");
  }
  
  Serial.println("複数センサー準備完了");
}

void loop() {
  // 温湿度データ
  Serial.print("温度: ");
  Serial.print(bme.readTemperature());
  Serial.print("°C ");
  
  // 加速度データ
  int16_t ax, ay, az;
  mpu.getAcceleration(&ax, &ay, &az);
  Serial.print("加速度 X:");
  Serial.print(ax);
  Serial.print(" Y:");
  Serial.print(ay);
  Serial.print(" Z:");
  Serial.println(az);
  
  delay(1000);
}

I2C活用例

  • 環境センサー:温度、湿度、気圧、照度
  • 時計モジュール(RTC):正確な時刻管理
  • OLED ディスプレイ:小型画面表示
  • EEPROM:設定値の保存

SPI通信:高速データ転送の王様

SPIとは?

SPI(Serial Peripheral Interface)は、4本の線を使って高速通信を行う方式です。データ量が多いディスプレイやSDカードでよく使われます。

🔌 SPI配線図

必要な配線(4本):

  • MOSI:マスター → スレーブ データ送信
  • MISO:スレーブ → マスター データ受信
  • SCK:クロック信号
  • CS:チップセレクト(デバイス選択)

※ 複数デバイスの場合、CSを追加する

⚠️ SPIの用語解説

  • マスター:通信を管理する側(Arduino等)
  • スレーブ:指示を受ける側(センサー等)
  • MOSI/MISO:データの流れる方向を示す

SPIの良いところ

  • 高速通信(MHz級)
  • 全二重通信(同時送受信)
  • データ量が多い用途に最適
  • ノイズに強い

SPIの注意点

  • 配線が多い(4本+CS)
  • 複数接続時はCS信号が増える
  • 距離が長いと不安定
  • 設定項目が多い

SPI実装例:TFTディスプレイ制御

Arduino + TFT ディスプレイ例

#include <SPI.h>
#include <TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();

void setup() {
  Serial.begin(115200);
  
  // TFT ディスプレイ初期化
  tft.init();
  tft.setRotation(1);  // 横向き
  tft.fillScreen(TFT_BLACK);
  
  // 文字表示
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextSize(2);
  tft.drawString("Hello, SPI!", 10, 10);
  
  Serial.println("TFT ディスプレイ初期化完了");
}

void loop() {
  // 温度計風の表示
  static int temperature = 20;
  
  // 前の表示をクリア
  tft.fillRect(10, 50, 200, 30, TFT_BLACK);
  
  // 新しい温度表示
  tft.setTextColor(TFT_GREEN, TFT_BLACK);
  tft.drawString("Temperature:", 10, 50);
  tft.drawString(String(temperature) + "C", 150, 50);
  
  // グラフィック描画
  int barLength = temperature * 3;  // 温度に応じたバーの長さ
  tft.fillRect(10, 90, barLength, 20, TFT_BLUE);
  tft.fillRect(10 + barLength, 90, 150 - barLength, 20, TFT_BLACK);
  
  temperature++;
  if (temperature > 50) temperature = 0;
  
  delay(100);
}
ESP32 + SDカード例

#include <SPI.h>
#include <SD.h>

#define SD_CS_PIN 5

void setup() {
  Serial.begin(115200);
  
  // SDカード初期化
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("SDカードエラー");
    return;
  }
  
  Serial.println("SDカード準備完了");
  
  // ファイル作成・書き込み
  File dataFile = SD.open("/sensor_data.txt", FILE_WRITE);
  if (dataFile) {
    dataFile.println("Timestamp,Temperature,Humidity");
    dataFile.close();
    Serial.println("データファイル作成完了");
  }
}

void loop() {
  // センサーデータ(仮想)
  float temp = 25.5;
  float humidity = 60.2;
  
  // SDカードにデータ保存
  File dataFile = SD.open("/sensor_data.txt", FILE_APPEND);
  if (dataFile) {
    String dataString = String(millis()) + "," + 
                       String(temp) + "," + 
                       String(humidity);
    dataFile.println(dataString);
    dataFile.close();
    
    Serial.println("データ保存: " + dataString);
  }
  
  delay(10000);  // 10秒間隔
}

SPI活用例

  • TFTディスプレイ:カラー画面、高解像度表示
  • SDカード:データロギング、設定保存
  • 無線モジュール:LoRa、WiFi拡張
  • ADC/DAC:高精度アナログ変換

🤔 どの通信方式を選べばいい?

用途別選択ガイド

📱 PCやスマホと通信したい

→ UARTを選択

  • デバッグ情報の表示
  • 設定値の変更
  • リアルタイムデータ送信

🌡️ 複数のセンサーを使いたい

→ I2Cを選択

  • 温度・湿度・気圧センサー
  • 時計モジュール
  • 小型OLEDディスプレイ

🖥️ 画面や大容量データを扱いたい

→ SPIを選択

  • カラーディスプレイ
  • SDカードへのデータ保存
  • 高速データ転送が必要な場合

⚠️ よくあるトラブルと解決法

UART関連のトラブル

文字化けする

原因:ボーレート(通信速度)の不一致

解決法:送信側と受信側のボーレートを合わせる

// 両方を同じ値に設定
Serial.begin(9600);     // Arduino側
# Python側でも9600に設定
ser = serial.Serial('/dev/ttyUSB0', 9600)

I2C関連のトラブル

センサーが認識されない

原因:プルアップ抵抗の不足、配線ミス

解決法:プルアップ抵抗(4.7kΩ)を追加、配線確認

// I2Cスキャナーでアドレス確認
#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("I2C デバイススキャン開始");
}

void loop() {
  for (byte address = 1; address < 127; address++) {
    Wire.beginTransmission(address);
    byte error = Wire.endTransmission();
    
    if (error == 0) {
      Serial.print("デバイス発見: 0x");
      Serial.println(address, HEX);
    }
  }
  delay(5000);
}

SPI関連のトラブル

ディスプレイが表示されない

原因:配線ミス、設定の不一致

解決法:配線を再確認、ライブラリ設定を見直し

// SPI設定確認例
#include <SPI.h>

void setup() {
  SPI.begin();
  
  // SPI設定表示
  Serial.begin(9600);
  Serial.println("SPI設定:");
  Serial.print("MOSI: ");
  Serial.println(MOSI);
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);
}

🛒 おすすめ部品とキット

UART用おすすめ部品

  • GPS モジュール NEO-6M:約1,500円 – 位置情報取得
  • Bluetooth モジュール HC-05:約800円 – スマホ連携
  • USB-Serial 変換モジュール:約500円 – PC接続

I2C用おすすめ部品

  • BME280 温湿度センサー:約1,200円 – 高精度環境測定
  • OLED ディスプレイ 128×64:約800円 – 小型画面
  • DS3231 RTC モジュール:約600円 – 正確な時計
  • MPU6050 6軸センサー:約500円 – 加速度・ジャイロ

SPI用おすすめ部品

  • 2.8インチ TFT ディスプレイ:約2,000円 – カラー表示
  • microSD カードモジュール:約300円 – データ保存
  • LoRa モジュール:約1,500円 – 長距離無線

学習におすすめのキット

通信プロトコル学習キット

「Arduino 通信マスターキット」(約8,000円)

  • Arduino Uno
  • 各種通信対応センサー
  • TFT ディスプレイ
  • ブレッドボード・配線材
  • 詳細な日本語マニュアル

📚 次のステップ:応用プロジェクト

初級:環境モニタリングシステム

使用通信:I2C + UART

  • I2C で複数センサーからデータ取得
  • UART でPCにデータ送信
  • Excel等でグラフ化

中級:IoT データロガー

使用通信:I2C + SPI + WiFi

  • I2C センサーでデータ収集
  • SPI でSDカードに保存
  • WiFi でクラウドに送信

上級:マルチセンサー制御システム

使用通信:全て組み合わせ

  • 複数のArduino間でUART通信
  • 各ArduinoでI2Cセンサー管理
  • SPIディスプレイで状態表示
  • 統合制御システム構築

🎯 まとめ:通信プロトコルマスターへの道

学習の順番

  1. UART:シリアルモニターでHello World
  2. I2C:温度センサーでデータ取得
  3. SPI:ディスプレイに表示
  4. 組み合わせ:複数通信の統合システム

通信プロトコルは最初は難しく感じるかもしれませんが、一度理解すれば電子工作の可能性が大きく広がります。

重要なのは実際に手を動かすこと!まずは簡単なUART通信から始めて、徐々にステップアップしていきましょう。

🚀 今日からできること

  1. Arduino のシリアルモニターで文字表示
  2. 温度センサー(I2C)でデータ読み取り
  3. 小さなOLEDディスプレイ(I2C)で表示
  4. 全部組み合わせて温度計を作成

この4ステップで、通信プロトコルの基本をマスターできます!

皆さんの電子工作ライフが、通信プロトコルの理解でさらに充実したものになることを願っています。質問や作品の報告があれば、ぜひコメントでお聞かせください!


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です