IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Hiển Thị LCD 16×2 với Giao Tiếp I2C — Chỉ 2 Dây Tín Hiệu

LCD 16×2 và Vấn Đề Của Kết Nối Song Song

LCD 16×2 truyền thống cần 16 chân để kết nối trực tiếp với Arduino — chiếm gần hết I/O! Module I2C adapter (PCF8574) giải quyết vấn đề này: chuyển 8 bit song song thành giao tiếp I2C chỉ 2 dây.

Kết nối trực tiếpI2C Adapter
Số dây tín hiệu6–8 dây2 dây (SDA + SCL)
Chân Arduino dùng6–8 chân digitalA4 (SDA) + A5 (SCL)
Nhiều LCD một lúcKhông thực tếĐến 127 thiết bị trên cùng bus

📷 [Hình minh hoạ: Sơ đồ Arduino Uno kết nối LCD 16×2 qua I2C module — chỉ 2 dây SDA/SCL, địa chỉ 0x27, teal arrows, nền trắng]

Giao Tiếp I2C — Nguyên Lý Cơ Bản

I2C (Inter-Integrated Circuit) dùng 2 dây:

  • SDA (Serial Data) — truyền/nhận dữ liệu
  • SCL (Serial Clock) — tín hiệu đồng bộ nhịp

Mỗi thiết bị I2C có địa chỉ 7-bit duy nhất (0x00–0x7F). Module PCF8574 thường có địa chỉ 0x27 hoặc 0x3F — có thể thay đổi bằng jumper A0/A1/A2.

Chân I2C trên Arduino Uno:

Arduino A4 (SDA) ── SDA của PCF8574/LCD module
Arduino A5 (SCL) ── SCL của PCF8574/LCD module
Arduino 5V       ── VCC module
Arduino GND      ── GND module

Cài Thư Viện LiquidCrystal_I2C

Trong Arduino IDE 2:

Tools → Manage Libraries → Search "LiquidCrystal I2C" → Install

Chọn thư viện của Frank de Brabander (phổ biến nhất).

Tìm Địa Chỉ I2C của LCD

Trước khi dùng, cần biết địa chỉ I2C của module. Upload sketch I2C Scanner:

#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("Quét I2C...");
}

void loop() {
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    byte error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("Tìm thấy thiết bị tại 0x");
      Serial.println(addr, HEX);
    }
  }
  delay(5000);
}

Kết quả thường là 0x27 hoặc 0x3F.

Sketch Cơ Bản — Hiển Thị Text

#include <LiquidCrystal_I2C.h>

// LiquidCrystal_I2C(địa_chỉ, số_cột, số_hàng)
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();         // Khởi tạo LCD
  lcd.backlight();    // Bật đèn nền

  lcd.setCursor(0, 0);          // Cột 0, hàng 0
  lcd.print("IoTLabs.vn");

  lcd.setCursor(0, 1);          // Cột 0, hàng 1
  lcd.print("Arduino Uno");
}

void loop() {}

Hệ tọa độ LCD:

  • Cột: 0–15 (trái → phải)
  • Hàng: 0 (hàng trên), 1 (hàng dưới)

Hiển Thị Dữ Liệu Cảm Biến

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
const int LDR_PIN = A0;
const int POT_PIN = A1;

void setup() {
  lcd.init();
  lcd.backlight();
}

void loop() {
  int ldr = analogRead(LDR_PIN);
  int pot = analogRead(POT_PIN);

  lcd.setCursor(0, 0);
  lcd.print("Sang:           "); // Xóa hàng trên bằng khoảng trắng
  lcd.setCursor(6, 0);
  lcd.print(ldr);

  lcd.setCursor(0, 1);
  lcd.print("Pot:            ");
  lcd.setCursor(5, 1);
  lcd.print(map(pot, 0, 1023, 0, 100));
  lcd.print("%");

  delay(500);
}

Mẹo: Để xóa nội dung cũ mà không gây nhấp nháy, in khoảng trắng đè lên thay vì lcd.clear() (clear gây nhấp nháy vì clear xong mới in mới).

Đồng Hồ Đơn Giản với millis()

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned long startTime;

void setup() {
  lcd.init();
  lcd.backlight();
  startTime = millis();

  lcd.setCursor(0, 0);
  lcd.print("Thoi gian chay:");
}

void loop() {
  unsigned long elapsed = (millis() - startTime) / 1000; // Giây
  int hours   = elapsed / 3600;
  int minutes = (elapsed % 3600) / 60;
  int seconds = elapsed % 60;

  lcd.setCursor(0, 1);
  // Format: HH:MM:SS
  if (hours < 10)   lcd.print("0");
  lcd.print(hours);   lcd.print(":");
  if (minutes < 10) lcd.print("0");
  lcd.print(minutes); lcd.print(":");
  if (seconds < 10) lcd.print("0");
  lcd.print(seconds);
}

Tạo Ký Tự Tùy Chỉnh

LCD 16×2 cho phép tạo tối đa 8 ký tự tùy chỉnh (5×8 pixel):

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

// Icon nhiệt độ (5 cột × 8 hàng)
byte tempIcon[] = {
  0b00100,
  0b01010,
  0b01010,
  0b01110,
  0b01110,
  0b11111,
  0b11111,
  0b01110
};

// Icon tim
byte heartIcon[] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000,
  0b00000
};

void setup() {
  lcd.init();
  lcd.backlight();

  lcd.createChar(0, tempIcon);   // Lưu vào slot 0
  lcd.createChar(1, heartIcon);  // Lưu vào slot 1

  lcd.setCursor(0, 0);
  lcd.write(byte(0)); // In icon nhiệt độ
  lcd.print(" 28.5C");

  lcd.setCursor(0, 1);
  lcd.write(byte(1)); // In icon tim
  lcd.print(" IoTLabs");
}

void loop() {}

Điều Chỉnh Độ Tương Phản

Trên module PCF8574, có một trimmer nhỏ (biến trở xoáy) điều chỉnh độ tương phản. Nếu LCD sáng nhưng không thấy chữ → vặn trimmer từ từ cho đến khi thấy ký tự rõ.

Tổng Kết

HàmChức năng
lcd.init()Khởi tạo
lcd.backlight() / lcd.noBacklight()Bật/tắt đèn nền
lcd.setCursor(col, row)Đặt vị trí in
lcd.print(value)In text/số
lcd.clear()Xóa màn hình
lcd.createChar(id, bitmap)Tạo ký tự tùy chỉnh

Bài cuối: Dự án tổng kết — kết hợp tất cả kiến thức đã học để xây dựng Trạm Đo Nhiệt Độ và Ánh Sáng hoàn chỉnh!


👉 Bài tiếp theo: Dự Án Tổng Kết: Trạm Đo Nhiệt Độ và Ánh Sáng với Arduino Uno