I²C(Inter-Integrated Circuit)是一種常見的同步序列匯流排,只需要 SDA 與 SCL 兩條訊號線,就能讓 Arduino 與多個感測器、顯示器或擴充晶片通訊。
本章將從 I²C 的基本原理、Arduino Uno 腳位、裝置位址與上拉電阻開始,接著實作 I²C Scanner 與 LCD1602 I²C 顯示器,建立後續使用 OLED、RTC、BMP280、MPU6050 等模組所需的基礎。
不同模組可能使用不同工作電壓與 I²C 位址。接線前應先確認模組規格,並避免將僅支援 3.3V 的裝置直接接到不相容的 5V 邏輯電位。
本章學習目標
- 了解 I²C 的工作原理與匯流排概念。
- 認識 SDA 與 SCL 的用途。
- 了解 Arduino Uno 的 I²C 腳位。
- 學會使用 Wire.h 函式庫。
- 使用 I²C Scanner 找出模組位址。
- 控制 LCD1602 I²C 顯示器。
- 為 OLED、RTC、BMP280 等 I²C 模組建立通訊基礎。
什麼是 I²C?
I²C 是 Inter-Integrated Circuit 的縮寫,最初由 Philips Semiconductor 提出,後來由 NXP 延續發展。它是一種同步序列通訊匯流排,常用於同一塊電路板或短距離配線中的晶片與模組通訊。
I²C 最大的特色是只需要兩條訊號線,就能讓一個控制器與多個裝置共享同一組通訊線路。Arduino 專案中的 LCD1602 I²C、OLED SSD1306、RTC DS3231、BMP280、BME280、MPU6050、ADS1115、PCF8574、EEPROM、INA219 與 PCA9685 等模組,都常使用 I²C。
| 項目 | 說明 |
|---|---|
| 全名 | Inter-Integrated Circuit |
| 中文常見名稱 | 積體電路間通訊 |
| 訊號線 | SDA、SCL |
| 通訊方式 | 同步序列通訊 |
| Arduino 函式庫 | Wire.h |
| Arduino Uno 腳位 | SDA:A4、SCL:A5 |
為什麼 Arduino 專案常使用 I²C?
傳統平行介面的 LCD1602 通常需要 RS、E、D4、D5、D6、D7 等多條控制與資料線。當專案同時加入顯示器、感測器與時鐘模組時,Arduino 可用腳位很快就會不足。
改用 I²C 後,多個裝置可以共用 SDA 與 SCL。只要裝置位址不衝突,Arduino 就能透過位址選擇要通訊的模組,大幅節省腳位並簡化配線。
| 比較項目 | 傳統 4-bit 平行介面 | I²C 介面 |
|---|---|---|
| 主要訊號線數量 | 通常需要 6 條控制與資料線 | 只需要 SDA、SCL 兩條訊號線 |
| Arduino 腳位占用 | 較多 | 較少 |
| 配線複雜度 | 較高 | 較低 |
| 多裝置擴充 | 需另外分配腳位 | 可共用同一條 I²C 匯流排 |
I²C 的兩條訊號線
SDA:序列資料線
SDA 是 Serial Data 的縮寫,用來傳送位址、資料與確認訊號。SDA 上的資料變化必須配合 SCL 時脈,通訊雙方才能正確判讀每一個位元。
SCL:序列時脈線
SCL 是 Serial Clock 的縮寫,由控制器提供時脈,使匯流排上的裝置依照相同節奏傳送與接收資料。
Arduino Uno 的 I²C 腳位
Arduino Uno 的 SDA 位於 A4,SCL 位於 A5。Uno R3 也在板子上另外提供標示為 SDA 與 SCL 的接腳,但電氣上仍與 A4、A5 相連。
同一條 I²C 匯流排上的所有裝置,通常需要共用 SDA、SCL 與 GND。各模組的 VCC 則必須依照模組規格連接 5V 或 3.3V。
| 模組接腳 | Arduino Uno 接腳 | 用途 |
|---|---|---|
| VCC | 依模組規格接 5V 或 3.3V | 模組供電 |
| GND | GND | 共用接地 |
| SDA | A4 或 SDA | 序列資料 |
| SCL | A5 或 SCL | 序列時脈 |
I²C 匯流排架構與裝置位址
I²C 採用控制器與受控裝置的匯流排架構。Arduino 在多數入門專案中扮演控制器,LCD、RTC、OLED、BMP280 或 MPU6050 等模組則是受控裝置。
每個 I²C 裝置都有位址。Arduino 傳送資料前,會先指定目標位址,再與對應裝置交換資料。常見 LCD1602 I²C 背板可能使用 0x27 或 0x3F,BMP280 常見位址則可能是 0x76 或 0x77,但實際位址仍應以模組規格或掃描結果為準。
使用 I²C Scanner 找出模組位址
當 LCD 沒有畫面,或感測器程式無法讀取資料時,位址設定錯誤是常見原因。I²C Scanner 會依序測試常用的 7-bit 位址範圍,並在 Serial Monitor 顯示有回應的裝置位址。
上傳程式前,先確認模組已正確供電、SDA 與 SCL 未接反,而且 Arduino 與模組已共用 GND。
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
Serial.println("I2C Scanner");
}
void loop()
{
byte error;
for (byte address = 1; address < 127; address++)
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("Found: 0x");
if (address < 16)
{
Serial.print("0");
}
Serial.println(address, HEX);
}
}
delay(5000);
}
預期掃描結果
開啟 Serial Monitor 並設定為 9600 baud。若模組位址是 0x27,預期會看到 Found: 0x27。若沒有找到任何位址,應先檢查供電、接地、SDA、SCL、模組電壓與接觸不良問題。
Wire.h 函式庫基礎
Arduino 的 I²C 程式通常需要先加入 Wire.h,並在 setup() 中呼叫 Wire.begin() 初始化 I²C。
#include <Wire.h>
void setup()
{
Wire.begin();
}
void loop()
{
}
- Wire.begin():初始化 I²C 通訊。
- Wire.beginTransmission(address):開始對指定裝置位址傳送資料。
- Wire.write():將資料放入傳送緩衝區。
- Wire.endTransmission():結束傳送並取得通訊狀態。
- Wire.requestFrom():向指定裝置要求資料。
- Wire.available():確認接收緩衝區是否還有資料。
- Wire.read():讀取接收到的一個位元組。
實作一:LCD1602 I²C 顯示文字
準備材料
- Arduino Uno。
- LCD1602 顯示器。
- 相容的 I²C 轉接模組或已整合 I²C 背板的 LCD1602。
- 杜邦線。
接線方式
| LCD1602 I²C | Arduino Uno |
|---|---|
| VCC | 5V,仍應以模組規格為準 |
| GND | GND |
| SDA | A4 或 SDA |
| SCL | A5 或 SCL |
顯示 Hello Arduino
下列範例使用常見的 LiquidCrystal_I2C 函式庫。不同函式庫的建構子或初始化函式可能不同,安裝前應確認函式庫文件與模組相容性。程式中的 0x27 必須改成 Scanner 實際找到的位址。
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup()
{
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Hello Arduino");
}
void loop()
{
}
程式上傳後,LCD 第一行預期顯示 Hello Arduino。若背光亮起但沒有文字,可先調整 I²C 背板上的對比旋鈕,再確認位址與函式庫是否正確。
實作二:在 LCD 顯示 ADC 數值
此實作可搭配第 9 章的 analogRead()。將可變電阻中間腳接到 A0,另外兩腳接 5V 與 GND,再把讀到的 ADC 數值顯示在 LCD 第二行。
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup()
{
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Analog Input");
}
void loop()
{
int adcValue = analogRead(A0);
lcd.setCursor(0, 1);
lcd.print("ADC=");
lcd.print(adcValue);
lcd.print(" ");
delay(200);
}
LCD 每 200 毫秒更新一次 A0 的 ADC 數值。程式在數值後補上空白,用來清除前一次顯示留下的多餘字元。
一條 I²C 匯流排可以連接多少模組?
I²C 可以讓多個裝置共用 SDA 與 SCL,例如同時連接 LCD、OLED、RTC、BMP280 與 MPU6050。能否正常共存,主要取決於裝置位址是否衝突、電壓是否相容、上拉電阻配置、線路長度、匯流排負載與供電品質。
若兩個模組使用相同且無法更改的位址,就不能直接在同一條 I²C 匯流排上獨立存取。可先查看模組是否提供位址選擇焊點,或使用 I²C 多工器等方式處理。
I²C 為什麼需要上拉電阻?
I²C 的 SDA 與 SCL 通常採用開漏極或開集極輸出。裝置主要負責把訊號線拉低,訊號線回到高電位則需要上拉電阻。
常見模組可能已內建約 4.7kΩ 的上拉電阻,因此單一模組短線測試通常不需要另外加裝。多個模組都內建上拉電阻時,等效阻值會下降;匯流排較長、模組較多或速度較高時,應依電壓、總電容與實際波形評估,不宜只憑固定阻值判斷。
I²C 通訊速度與配線限制
Arduino Wire 函式庫常以 100 kHz 標準模式運作,部分裝置也支援 400 kHz Fast Mode。是否能提高速度,必須同時確認控制器、所有受控裝置與配線條件。
速度越高,越需要縮短線材、降低雜訊、維持良好接地並正確配置上拉電阻。I²C 原本主要用於板級或短距離通訊,不適合直接當作長距離外部傳輸介面。
常見問題與故障排除
Scanner 找不到任何裝置
- 確認模組 VCC 與 GND 接線正確。
- 確認 Arduino 與模組共用 GND。
- 確認 SDA 接 A4 或 SDA,SCL 接 A5 或 SCL。
- 檢查 SDA 與 SCL 是否接反。
- 確認模組工作電壓與 Arduino 相容。
- 更換杜邦線或重新插拔,排除接觸不良。
- 確認程式已呼叫 Wire.begin()。
- 若模組允許更改位址,確認位址設定焊點或跳線狀態。
LCD 背光亮但沒有文字
- 使用 I²C Scanner 確認實際位址。
- 把程式中的 0x27 改成掃描結果。
- 調整 I²C 背板上的對比旋鈕。
- 確認 LCD 尺寸參數為 16 欄、2 列。
- 確認 LiquidCrystal_I2C 函式庫與範例程式相容。
多個模組接上後通訊不穩定
- 逐一接回模組,找出造成問題的裝置。
- 使用 Scanner 檢查是否有位址衝突。
- 縮短 SDA 與 SCL 線路,避免與馬達或高電流線路平行。
- 確認所有模組的邏輯電壓相容。
- 檢查多個模組內建上拉電阻造成的等效阻值是否過低。
- 先使用 100 kHz 測試,不要一開始就提高時脈。
本章實作練習
- 執行 I²C Scanner,記錄 LCD1602 I²C 模組的位址。
- 讓 LCD 第一行顯示 Hello Arduino。
- 將 analogRead(A0) 的 ADC 數值顯示在 LCD 第二行。
- 再接上一個 OLED、RTC 或感測器模組,重新掃描並記錄每個位址。
- 說明多個模組共用 SDA、SCL,卻能透過不同位址分別通訊的原因。
本章重點整理
- I²C 是使用 SDA 與 SCL 的雙線同步序列匯流排。
- Arduino Uno 的 SDA 是 A4,SCL 是 A5。
- 多個 I²C 裝置可以共用同一組 SDA 與 SCL。
- Arduino 透過裝置位址選擇通訊目標。
- I²C Scanner 可以快速確認模組是否被偵測及其實際位址。
- Wire.h 與 Wire.begin() 是 Arduino I²C 程式的基礎。
- 穩定性除了位址之外,也受到工作電壓、上拉電阻、線路長度與匯流排速度影響。
下一章預告
第 13 章將介紹 SPI(Serial Peripheral Interface)高速序列通訊,包括 MOSI、MISO、SCK、SS 的用途、Arduino Uno 的 SPI 腳位,以及 SPI 與 I²C 的差異。