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ếp | I2C Adapter | |
|---|---|---|
| Số dây tín hiệu | 6–8 dây | 2 dây (SDA + SCL) |
| Chân Arduino dùng | 6–8 chân digital | A4 (SDA) + A5 (SCL) |
| Nhiều LCD một lúc | Khô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àm | Chứ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


