PUBLIC
PRACTICEI2C DISPLAY10 MIN READ

I2C で OLED に表示する2 本の線で小さな画面をつなぎ、センサーの値を出す

センサーの値を PC のシリアルモニタではなく、その場で見たい。0.96 インチの OLED(SSD1306)は 4 本の線(電源 2 本 + I2C の 2 本)でつながり、数百円で買えます。I2C は温湿度センサーや ADC モジュールもつなぐ規格なので、ここで覚えると一気に世界が広がります。

  • ESP32-S3
  • Raspberry Pi 5 8GB
  • M5Stack CoreS3
CONTENTSこの記事の目次

01 — I2C

I2C とは

SDA (データ)SCL (クロック)MASTERESP32 / Pi 50x3COLED 表示器0x44温湿度 SHT400x48ADC ADS11152本の線を全員で共有し、7bitアドレスで呼び分けるため、部品が増えてもピンを消費しない
DIAGRAM

SDA(データ)とSCL(クロック)の2本を全員で共有し、7bitアドレス(OLEDは0x3Cなど)で呼び分けます。デバイスが増えても線の数は増えません。

  • 2 本の線:SDA(データ)と SCL(クロック)。それに VCC と GND
  • 1 組の線に複数のデバイスをぶら下げられる。それぞれ 7bit のアドレスを持つ(OLED は 0x3C が多い)
  • マイコンが「マスター」、センサーや表示器が「ターゲット」。マスターがアドレスを呼んで読み書きする
  • 速度は 100kHz(標準)か 400kHz。配線は数十 cm まで
  • SDA / SCL にはプルアップ抵抗が必要。モジュールにはたいてい載っている(4.7kΩ〜10kΩ)

02 — WIRING

配線

OLED のピンESP32-S3Raspberry Pi 5CoreS3(Port A)
VCC3V3物理 1(3.3V)Grove 赤(5V。モジュールが 5V 対応か確認)
GNDGND物理 6Grove 黒
SCLGPIO9GPIO3(物理 5)G1(Grove 黄)
SDAGPIO8GPIO2(物理 3)G2(Grove 白)

I2C は「SDA 同士、SCL 同士」をつなぎます。UART のように交差させません。ESP32-S3 の GPIO8 / 9 は Arduino の Wire.begin() が既定で使うピンです。

03 — SCAN

まずアドレスを確認する

CPPi2c_scan.ino(ESP32-S3)
#include <Wire.h>

void setup() {
  Serial.begin(115200);
  Wire.begin();                          // ESP32-S3: SDA=GPIO8, SCL=GPIO9
  for (uint8_t addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.printf("found: 0x%02X\n", addr);
    }
  }
}

void loop() {}

Raspberry Pi 5 では sudo raspi-config → Interface Options → I2C を有効にしてから、i2cdetect -y 1 で表が出ます。3c が見えれば OK です。

何も見つからないときは、SDA と SCL が逆、VCC が来ていない、プルアップがない、のどれかです。

04 — DISPLAY

文字を出す(Adafruit SSD1306)

ライブラリマネージャで「Adafruit SSD1306」を入れます(Adafruit GFX も一緒に入ります)。

CPPoled_hello.ino
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(128, 64, &Wire);

void setup() {
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);   // スキャンで見えたアドレス
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello");
  display.display();                            // ここで初めて画面に反映
}

void loop() {}
  • display.display() を呼ぶまで画面は変わらない(描画はメモリ上で行われる)
  • 数値を出すなら display.print(value)。更新するときは clearDisplay() → 描画 → display()
  • 128×32 のモジュールなら高さを 32 にする
  • Raspberry Pi 5 では Python の luma.oled ライブラリ。準備が多いので、まずは ESP32 で試すのがおすすめ

05 — SENSOR → DISPLAY

センサーの値を表示する

CPPoled_light.ino(loop の部分)
void loop() {
  int light = analogRead(2);        // CdS(→ ADC でセンサーを読む)
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Light");
  display.setCursor(0, 32);
  display.print(light);
  display.display();
  delay(200);
}

これで PC なしで動く「測定器」になります。CoreS3 なら OLED は不要で、M5.Display に同じように出せます。

06 — WATCH OUT

注意点

アドレスの重複

同じアドレスのデバイスは 1 本の I2C 線に 2 つつなげません(OLED 2 枚など)。アドレス変更ジャンパか、もう 1 組の I2C(Wire1)を使います。

電圧

5V 専用の I2C モジュールを 3.3V の SDA / SCL に直結しないようにします。大抵は 3.3V 対応ですが、確認します。

長い配線

数十 cm を超えると通信エラーが増えます。速度を 100kHz に落とすか、配線を短くします。

07 — CHECK YOURSELF

理解チェック

Q1I2C の 2 本の線の名前と役割は?

SDA(データ)と SCL(クロック)。

Q2OLED に print したのに何も出ない。よくある原因は?

display.display() を呼んでいない。またはアドレスが 0x3C ではない(スキャンで確認)。