ArduinoVN
Đăng nhập Tham gia
Thư viện Code /u/linucat /09/05/2026

Thư viện Wire.h: API I2C đầy đủ với ví dụ

Thảo luận

Wire.h là thư viện I2C tích hợp sẵn trong Arduino IDE, không cần cài thêm. Bài viết này liệt kê toàn bộ API kèm ví dụ thực tế — từ master scan bus đến slave responder, để bạn dùng làm tham khảo nhanh.

1. Khởi tạo

#include 

Wire.begin();           // Master mode
Wire.begin(addr);       // Slave mode với địa chỉ 7-bit
Wire.begin(sda, scl);   // ESP32 / ESP8266: chỉ định chân

Wire.setClock(400000);  // 100k (chuẩn), 400k (fast), 1M (fast+, ESP32)
Wire.end();             // Giải phóng bus (ESP32)

2. Master — gửi dữ liệu

Wire.beginTransmission(0x68);   // chọn slave
Wire.write(0x1A);               // địa chỉ thanh ghi
Wire.write(0xFF);               // giá trị
uint8_t err = Wire.endTransmission();
// Trả về:
//  0 = thành công
//  1 = buffer overflow
//  2 = NACK trên địa chỉ (slave không tồn tại)
//  3 = NACK trên data
//  4 = lỗi khác

Buffer mặc định 32 byte trên AVR — gửi nhiều hơn sẽ truncate. Trên ESP32 buffer 128 byte.

3. Master — đọc dữ liệu

uint8_t n = Wire.requestFrom(0x68, (uint8_t)6);
while (Wire.available()) {
  uint8_t b = Wire.read();
  Serial.println(b, HEX);
}
// requestFrom() có overload thứ 3:
Wire.requestFrom(addr, len, true);   // stop sau đọc (mặc định)
Wire.requestFrom(addr, len, false);  // restart, không thả bus

4. Pattern "chọn thanh ghi rồi đọc" — chuẩn nhất

uint8_t readReg(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire.write(reg);
  Wire.endTransmission(false);   // restart, GIỮ bus
  Wire.requestFrom(addr, (uint8_t)1);
  return Wire.read();
}

void writeReg(uint8_t addr, uint8_t reg, uint8_t val) {
  Wire.beginTransmission(addr);
  Wire.write(reg);
  Wire.write(val);
  Wire.endTransmission();
}

5. Đọc 16-bit (cảm biến nhiệt, áp suất...)

int16_t readReg16(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire.write(reg);
  Wire.endTransmission(false);
  Wire.requestFrom(addr, (uint8_t)2);
  int16_t hi = Wire.read();
  int16_t lo = Wire.read();
  return (hi << 8) | lo;
}

Tuỳ chip, có thể little-endian (đảo thứ tự).

6. Slave mode — Arduino làm slave

const uint8_t MY_ADDR = 0x42;
volatile uint8_t lastCmd = 0;

void onReceive(int n) {
  while (Wire.available()) lastCmd = Wire.read();
}

void onRequest() {
  Wire.write(millis() & 0xFF);  // gửi 1 byte timestamp
}

void setup() {
  Wire.begin(MY_ADDR);
  Wire.onReceive(onReceive);
  Wire.onRequest(onRequest);
}
void loop() {}

7. I2C Scanner — code mẫu

void scanI2C() {
  Serial.println("Scan...");
  for (uint8_t a = 1; a < 127; a++) {
    Wire.beginTransmission(a);
    if (Wire.endTransmission() == 0) {
      Serial.print("  Found 0x");
      Serial.println(a, HEX);
    }
  }
}

8. Đa bus I2C trên ESP32

ESP32 có 2 bus I2C phần cứng (Wire và Wire1):

TwoWire I2C_A = TwoWire(0);
TwoWire I2C_B = TwoWire(1);

void setup() {
  I2C_A.begin(21, 22, 400000);   // bus 0
  I2C_B.begin(25, 26, 400000);   // bus 1
}

Dùng khi 2 slave trùng địa chỉ (vd 2 cảm biến MPU-6050 cùng 0x68).

9. Bảng nhanh các API

HàmVai trò
begin([addr])Khởi tạo master / slave
beginTransmission(addr)Bắt đầu gửi (master)
write(b) / write(buf, n)Đẩy byte vào buffer
endTransmission([stop])Gửi đi, nhận ACK/NACK
requestFrom(addr, n)Yêu cầu n byte từ slave
available()Số byte còn trong buffer nhận
read()Đọc byte tiếp theo
onReceive(handler)Callback khi slave nhận
onRequest(handler)Callback khi master xin data
setClock(hz)Đổi tốc độ bus

10. Lỗi thường gặp

  • endTransmission trả 2 — slave không tồn tại (sai địa chỉ, chưa cấp nguồn, dây đứt).
  • available() luôn 0 — quên requestFrom hoặc slave không trả lời.
  • Treo cả vòng loop — bus bị slave "giữ" SDA mãi LOW. Reset module hoặc tự bit-bang SCL 9 xung để giải phóng.
  • Đọc ra rác — sai endian hoặc sai địa chỉ thanh ghi.

Liên quan

Đọc bài I2C trên Arduino: Wire.h căn bản nếu bạn mới làm quen. Để dùng OLED, xem Adafruit SSD1306: vẽ pixel, text, hình.

Thảo luận (0)

Đăng nhập để tham gia thảo luận.
Chưa có bình luận nào. Hãy là người đầu tiên!