はじめに
新しいI2CセンサーやディスプレイをArduinoに接続したとき、「このデバイスのアドレスは何だろう?」と疑問に思ったことはありませんか?あなただけではありません!I2Cプロトコルは、たった2本のワイヤーで複数のデバイスと通信できる強力な方法ですが、すべてのデバイスには固有のアドレスがあり、そのアドレスがデータシートからすぐにわからないこともあります。そこで役立つのがI2Cスキャナーです。これは、可能なすべてのアドレスを調べ、応答があったアドレスを報告するシンプルなスケッチです。
このチュートリアルでは、Arduino UnoとSSD1306 OLEDディスプレイ(バス上の既知のデバイスとしても機能します)を使ってI2Cスキャナーを構築します。すべてをVelxioのブラウザ内シミュレーターで実行するため、ハードウェアは必要ありません。最後には、I2Cバスの仕組み、デバイスの配線方法、そしてそれらをスキャンするコードの書き方を理解できるでしょう。
さあ、始めましょう!
回路の解説

この回路は驚くほどシンプルです。必要なコンポーネントはたった2つです:
- Arduino Uno – 操作の頭脳。
- SSD1306 OLEDディスプレイ – I2C通信を使用する128x64ピクセルのモノクロディスプレイ。デフォルトアドレスは
0x3Cです。
配線の詳細
4本のワイヤーでOLEDをArduinoに接続します:
| Arduinoピン | OLEDピン | ワイヤーの色 |
|---|---|---|
| A4 (SDA) | DATA | 青 |
| A5 (SCL) | CLK | 橙 |
| GND | GND | 黒 |
| 5V | VIN | 赤 |
- SDA (A4) はデータラインです。マスター(Arduino)とスレーブ(OLED)の間で実際のデータを運びます。
- SCL (A5) はクロックラインです。データ転送を同期します。
- GND と 5V はOLEDに電力を供給します。
注記: Arduino Unoでは、A4とA5が専用のI2Cピンです。他のボードでは異なるピンを使用する場合があります(例:ESP32のSDA/SCL)。
Velxioシミュレーターでは、コンポーネントピッカーからOLEDを追加し、ピンをクリックして配線できます。キャンバスツールバーは、接続を容易にするためのズームやパンに役立ちます。

コードの解説

それではコードを見てみましょう。Velxioでコードエディターを開きます(シンタックスハイライト付きのMonacoエディターが表示されます)。このスケッチはArduino C++で書かれており、組み込みのWireライブラリを使用しています。
ライブラリのインクルード
#include <Wire.h>
Wireライブラリは、すべての低レベルのI2C通信を処理します。Arduino IDEに含まれているため、追加のインストールは必要ありません。
セットアップ関数
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("===========================");
Serial.println(" I2C Bus Scanner (TWI)");
Serial.println("===========================");
Serial.println("Scanning...");
Serial.println();
int devicesFound = 0;
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
byte error = Wire.endTransmission();
if (error == 0) {
Serial.print(" Device found at 0x");
if (addr < 16) Serial.print("0");
Serial.print(addr, HEX);
// 既知のアドレスを識別
switch (addr) {
case 0x27: Serial.print(" (PCF8574 LCD backpack)"); break;
case 0x3C: Serial.print(" (SSD1306 OLED)"); break;
case 0x48: Serial.print(" (Temperature sensor)"); break;
case 0x50: Serial.print(" (EEPROM)"); break;
case 0x68: Serial.print(" (DS1307 RTC)"); break;
case 0x76: Serial.print(" (BME280 sensor)"); break;
case 0x77: Serial.print(" (BMP180/BMP280)"); break;
}
Serial.println();
devicesFound++;
}
}
Serial.println();
Serial.print("Scan complete. ");
Serial.print(devicesFound);
Serial.println(" device(s) found.");
if (devicesFound == 0) {
Serial.println("No I2C devices found. Check connections.");
}
}
分解してみましょう:
Wire.begin()– ArduinoをI2Cマスターとして初期化します。Serial.begin(9600)– シリアル通信を9600ボーで開始し、シリアルモニターで結果を確認できるようにします。- ループはアドレス1から126(0x01から0x7E)を反復処理します。アドレス0は一般呼び出し用に、127は特別な目的用に予約されています。
Wire.beginTransmission(addr)– 指定されたアドレスへの送信を開始します。Wire.endTransmission()– 送信を終了し、エラーコードを返します。エラーが0の場合、デバイスが応答(ACK)したことを意味します – デバイスが見つかりました!- アドレスの表示 – 読みやすくするために先頭ゼロを付けて16進数形式で表示します。
- switch文 – 既知のアドレスに基づいて一般的なデバイスを識別します。これはオプションですが便利です。
- デバイスのカウント – ACKごとに
devicesFoundをインクリメントします。 - 最終レポート – 見つかったデバイスの総数を表示します。
ループ関数
void loop() {
// 10秒ごとに再スキャン
delay(10000);
Serial.println("\nRescanning...");
setup();
}
loop()関数は単に10秒待機し、その後setup()を再度呼び出して再スキャンします。これは、システムの実行中にデバイスを追加または削除する場合に便利です。
学生向けの重要な概念
I2Cとは?
I2C(Inter-Integrated Circuit)は、TWI(Two-Wire Interface)とも呼ばれ、同期シリアル通信プロトコルです。2本の双方向オープンドレインライン、SDA(データ)とSCL(クロック)を使用します。バス上の各デバイスには固有の7ビットアドレスがあります(10ビットアドレスも存在します)。マスター(Arduino)が通信を開始し、クロック信号を生成します。
スキャナーの仕組み
スキャナーは、スタートコンディションに続いてアドレスバイト(7ビットアドレス+読み取り/書き込みビット)を送信します。そのアドレスのデバイスが存在する場合、9番目のクロックパルス中にSDAをLowにすることでACK(応答)を返します。デバイスが応答しない場合はNACK(非応答)が受信され、endTransmission()はゼロ以外のエラーコードを返します。
なぜスキャナーを使うのか?
- 未知のアドレスを見つける – 多くのI2Cデバイスは設定可能なアドレスを持っています(例:はんだパッドによる)。スキャナーは実際のアドレスを教えてくれます。
- 配線のデバッグ – デバイスが応答しない場合、スキャナーは正しく接続されているか確認するのに役立ちます。
- 競合の確認 – 同じアドレスを持つ2つのデバイスは通信エラーを引き起こします。スキャナーは重複を特定するのに役立ちます。
よくある落とし穴とデバッグのコツ
- 配線ミス – SDAとSCLが正しく接続されているか再確認してください。入れ替えると動作しません。
- プルアップ抵抗の欠落 – I2CラインにはVCCへのプルアップ抵抗(通常4.7kΩ)が必要です。多くのブレイクアウトボードには含まれていますが、ゼロから構築する場合は忘れないでください。
- アドレス競合 – 2つのデバイスが同じアドレスを共有している場合、どちらも確実に動作しません。スキャナーを使用して競合を検出してください。
- ボーレートの不一致 – スキャナーはデフォルトの100 kHz(標準モード)を使用します。一部のデバイスはより低速が必要な場合があります。高速モードにするには
Wire.setClock(400000)で変更できます。 - シリアルモニターに出力が表示されない – シリアルモニターのボーレートが
9600に一致していることを確認してください。
Velxioでは、エディターツールバーからシリアルモニターを開くことができます。出力が表示されない場合は、コードが正常にコンパイルされたか確認してください(コンソールのエラーを確認)。

推奨される拡張機能
基本的なスキャナーが動作したら、次の拡張機能を試してみてください:
- 結果をOLEDに表示 – シリアルに出力する代わりに、SSD1306ディスプレイにアドレスのリストを表示します。
Adafruit_SSD1306とAdafruit_GFXライブラリが必要です。 - スキャンをトリガーするボタンを追加 – プッシュボタンをArduinoピンに接続し、押したときだけスキャンします。
- 特定のデバイスをスキャン – 特定のアドレス範囲(例:PCF8574の0x20-0x2F)のみを探すようにコードを変更します。
- LCDを使用 – OLEDを16x2 I2C LCD(アドレス0x27または0x3F)に置き換えます。
- SDカードにログ – SDカードモジュールがある場合、スキャン結果を後で分析するためにログします。
Velxioでライブラリを追加するには、ライブラリマネージャーを使用します。

結論
これで、任意のArduino互換ボードで動作するユニバーサルI2Cスキャナーを構築しました。このツールは、新しいI2Cモジュールのデバッグや探索に非常に役立ちます。何より素晴らしいのは、ハードウェアなしでブラウザ上のVelxioで今すぐ実行できることです。
自分で試してみませんか?ライブの例を開いてスキャンを始めましょう:
ハッピーハッキング!