🧩 1. ความหมายของ I²C และ SPI

ทั้ง I²C (Inter-Integrated Circuit) และ SPI (Serial Peripheral Interface) คือ “โปรโตคอลการสื่อสารแบบอนุกรม” ที่ออกแบบมาเพื่อให้ ไมโครคอนโทรลเลอร์ สามารถเชื่อมต่อกับ “อุปกรณ์หลายตัว” ได้โดยใช้ สายไม่มาก


🔸 I²C (อ่านว่า “ไอ-สแควร์-ซี” หรือ “ไอทูซี”)

  • ใช้สายเพียง 2 เส้น:
    • SCL (Serial Clock) → สัญญาณนาฬิกา
    • SDA (Serial Data) → สัญญาณข้อมูล
  • เป็นระบบ Master–Slave
    • 1 Master (ไมโครคอนโทรลเลอร์)
    • หลาย Slave (เซนเซอร์, จอ ฯลฯ)
  • แต่ละ Slave มี “หมายเลขประจำตัว” เรียกว่า Address (ที่อยู่ I²C)

📘 ตัวอย่าง:
ESP32 (Master) → BME280 (Addr: 0x76), OLED (Addr: 0x3C)


🔹 SPI (Serial Peripheral Interface)

  • ใช้สาย 4 เส้น (หรือมากกว่าเล็กน้อย)
    • MOSI → Master Out Slave In
    • MISO → Master In Slave Out
    • SCK → Clock
    • SS → Slave Select (เลือกอุปกรณ์แต่ละตัว)
  • ความเร็วสูงกว่า I²C มาก (ระดับ MHz)
  • เหมาะสำหรับงานที่ต้องการความเร็ว เช่น จอสี TFT, SD Card, เซนเซอร์วัดความเร็วสูง

⚙️ 2. สรุปความแตกต่างระหว่าง I²C กับ SPI

รายการI²CSPI
จำนวนสาย2 เส้น (SCL, SDA)4 เส้น (MISO, MOSI, SCK, SS)
การต่ออุปกรณ์หลายตัวง่าย (ระบุ Address)ต้องมี SS แยกแต่ละอุปกรณ์
ความเร็วปานกลาง (100k–400kHz)สูง (1–20 MHz)
โครงสร้างMaster–SlaveMaster–Slave
การเชื่อมต่อใช้ Addressใช้ขา SS
ตัวอย่างอุปกรณ์OLED, RTC, BME280, EEPROMSD Card, TFT, Flash Memory

🔹 3. I²C Communication ใน Arduino / ESP32

Arduino และ ESP32 มี ไลบรารี Wire.h สำหรับใช้งาน I²C ได้ง่ายมาก

✅ ขา I²C พื้นฐาน

บอร์ดSDASCL
Arduino UNOA4A5
Arduino MEGA2021
ESP32 (default)2122

แต่ใน ESP32 สามารถกำหนดขา SDA/SCL เองได้ด้วย


🔹 4. ตัวอย่าง: I²C Scanner (ตรวจหา Address ของอุปกรณ์)

📘 โปรแกรมนี้ใช้หาว่าอุปกรณ์ I²C ต่ออยู่ไหม และมี Address อะไร

C++
#include <Wire.h>

void setup() {
  Wire.begin();               // เริ่ม I2C (SDA=21, SCL=22)
  Serial.begin(115200);
  Serial.println("\nI2C Scanner Running...");
}

void loop() {
  byte error, address;
  int nDevices = 0;

  for (address = 1; address < 127; address++) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at 0x");
      if (address < 16) Serial.print("0");
      Serial.print(address, HEX);
      Serial.println();
      nDevices++;
    }
  }

  if (nDevices == 0) Serial.println("No I2C devices found.\n");
  else Serial.println("Scan done.\n");

  delay(2000);
}

ผลลัพธ์ใน Serial Monitor เช่น:

C++
I2C device found at 0x3C
I2C device found at 0x76

หมายถึงมีจอ OLED (0x3C) และ BME280 (0x76) ต่ออยู่


🔹 5. ตัวอย่าง: แสดงข้อความบนจอ OLED (I²C)

📘 ใช้ไลบรารี Adafruit_SSD1306 + Adafruit_GFX

C++
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(115200);
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println("OLED not found");
    for (;;);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 25);
  display.println("ESP32!");
  display.display();
}

void loop() {}

แสดงข้อความ “ESP32!” บนจอ OLED ขนาด 0.96 นิ้ว


🔹 6. การใช้ I²C หลายอุปกรณ์

ต่อขา SDA, SCL ร่วมกันได้เลย
แต่ต้องไม่ซ้ำ Address

📘 ตัวอย่าง:

  • OLED (0x3C)
  • BME280 (0x76)
C++
Wire.beginTransmission(0x3C);
Wire.write(...);
Wire.endTransmission();

Wire.beginTransmission(0x76);
Wire.write(...);
Wire.endTransmission();

ระบบจะเลือกคุยกับอุปกรณ์ตาม Address ที่ระบุ


🔹 7. SPI Communication

Arduino และ ESP32 มีไลบรารี SPI.h สำหรับใช้งาน SPI

บอร์ดMISOMOSISCKSS
Arduino UNO12111310
ESP32 (default)1923185

แต่ ESP32 สามารถกำหนดขาใหม่ได้ทั้งหมด


🔹 8. ตัวอย่าง: SPI อ่านข้อมูลจาก SD Card

📘 ใช้ไลบรารี SD.h

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

#define CS_PIN 5

void setup() {
  Serial.begin(115200);
  if (!SD.begin(CS_PIN)) {
    Serial.println("SD card not found!");
    return;
  }
  Serial.println("SD card ready!");

  File file = SD.open("/test.txt", FILE_WRITE);
  file.println("Hello ESP32 SPI!");
  file.close();

  Serial.println("Data written to SD card.");
}

void loop() {}

🔹 9. ตัวอย่าง: SPI เชื่อมต่อจอ TFT

📘 ใช้ไลบรารี TFT_eSPI

C++
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();

void setup() {
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_GREEN, TFT_BLACK);
  tft.drawString("Hello SPI!", 40, 60);
}

void loop() {}

🔹 10. การเลือกโปรโตคอลให้เหมาะสม

งาน / อุปกรณ์แนะนำใช้เหตุผล
จอ OLED, RTC, เซนเซอร์หลายตัวI²Cใช้สายร่วมกันได้
จอสี TFT, SD CardSPIต้องการความเร็วสูง
ระบบหลาย NodeI²C (ง่ายต่อการขยาย)Address-based
การส่งข้อมูลปริมาณมากSPIBandwidth สูงกว่า

📚 11. แบบฝึกหัดท้ายบท

1️⃣ เขียนโปรแกรม I²C Scanner เพื่อค้นหา Address ของอุปกรณ์
2️⃣ เชื่อมต่อจอ OLED (I²C) และแสดงข้อความ “Hello LIC”
3️⃣ อ่านค่าจากเซนเซอร์ BME280 และแสดงบน OLED
4️⃣ บันทึกข้อมูลลง SD Card ผ่าน SPI
5️⃣ ทดลองเปลี่ยน Address ของอุปกรณ์ I²C และเชื่อมต่อพร้อมกัน 2 ตัว


🧾 12. สรุปแนวคิดสำคัญ

หัวข้ออธิบาย
I²Cใช้สาย 2 เส้น (SCL, SDA) ติดต่ออุปกรณ์หลายตัว
SPIใช้ 4 เส้น (MISO, MOSI, SCK, SS) เร็วกว่า
Master–SlaveMCU = Master, Sensor/Display = Slave
Addressหมายเลขของอุปกรณ์ใน I²C
Wire.hไลบรารีควบคุม I²C
SPI.hไลบรารีควบคุม SPI
I²C Scannerโปรแกรมค้นหา Address
OLED / BME280ตัวอย่างอุปกรณ์ I²C
SD Card / TFTตัวอย่างอุปกรณ์ SPI