2026-07-04 · 7 min read
IoT: LCD I2C và Morse Code
Ghi chú cách nối LCD 16x2 I2C, các hàm thường dùng và bài thực hành nhập Morse bằng nút bấm.
LCD I2C giúp mạch IoT dễ quan sát hơn
Serial Monitor rất hữu ích khi debug, nhưng không phải lúc nào thiết bị IoT cũng cắm với máy tính. Một màn hình LCD 16x2 giúp hiển thị trạng thái ngay trên mạch: giá trị cảm biến, chế độ hoạt động, lỗi kết nối hoặc dữ liệu người dùng nhập.
Bài này giới thiệu LCD 16x2 dùng module I2C và một bài thực hành nhỏ: nhập Morse code bằng nút bấm rồi hiển thị lên LCD.
LCD 16x2 nghĩa là gì?
LCD 16x2 có 16 cột và 2 hàng. Mỗi ô hiển thị một ký tự.
ABCDEFGHIJKLMNOP
1234567890123456
LCD song song truyền thống có nhiều chân dữ liệu và chân điều khiển. Khi gắn thêm module I2C, việc nối dây đơn giản hơn nhiều vì chỉ cần bốn chân.
| Chân | Vai trò |
|---|---|
GND | Cực âm, nối về mass |
VCC | Nguồn cấp, thường là 5V |
SDA | Đường dữ liệu I2C |
SCL | Đường clock I2C |
Cách nối dây
Với Arduino Uno:
LCD -> Arduino Uno
GND -> GND
VCC -> 5V
SDA -> A4
SCL -> A5
Với ESP32 phổ biến:
SDA -> GPIO21
SCL -> GPIO22
Với ESP32-C3 Super Mini, nhiều board dùng:
SDA -> GPIO8
SCL -> GPIO9
Nếu LCD không hiển thị, đừng sửa code ngay. Hãy kiểm tra nguồn, dây SDA/SCL, địa chỉ I2C và biến trở chỉnh tương phản trên module trước.
Các hàm LCD thường dùng
| Hàm | Công dụng |
|---|---|
lcd.init() | Khởi tạo LCD |
lcd.backlight() | Bật đèn nền |
lcd.noBacklight() | Tắt đèn nền |
lcd.clear() | Xóa toàn bộ màn hình |
lcd.home() | Đưa con trỏ về góc trái dòng đầu |
lcd.setCursor(column, row) | Đặt vị trí in ký tự |
lcd.cursor() / lcd.noCursor() | Hiện hoặc ẩn con trỏ |
lcd.blink() / lcd.noBlink() | Bật hoặc tắt nháy con trỏ |
lcd.scrollDisplayLeft() | Cuộn nội dung sang trái |
lcd.scrollDisplayRight() | Cuộn nội dung sang phải |
Ví dụ đặt con trỏ ở cột đầu tiên, hàng thứ hai:
lcd.setCursor(0, 1);
lcd.print("Hello IoT");
Bài thực hành: Morse code với LCD và nút bấm
Mục tiêu là dùng một nút bấm để nhập tín hiệu Morse:
- Nhấn ngắn tạo dấu chấm
. - Nhấn dài tạo dấu gạch
- - LCD hiển thị chuỗi Morse đã nhập
Sơ đồ tư duy:
Nut bam -> Do thoi gian nhan -> Phan loai . hoac - -> Hien thi LCD
Code mẫu:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int btn = 3;
const unsigned long dotThreshold = 300;
String morse = "";
unsigned long pressStart = 0;
bool lastState = HIGH;
void setup() {
pinMode(btn, INPUT_PULLUP);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Morse Input");
lcd.setCursor(0, 1);
lcd.print("Press button");
}
void loop() {
bool currentState = digitalRead(btn);
if (lastState == HIGH && currentState == LOW) {
pressStart = millis();
}
if (lastState == LOW && currentState == HIGH) {
unsigned long duration = millis() - pressStart;
if (duration < dotThreshold) {
morse += ".";
} else {
morse += "-";
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Morse:");
lcd.setCursor(0, 1);
lcd.print(morse);
}
lastState = currentState;
}
Vì dùng INPUT_PULLUP, nút đang nhấn sẽ đọc là LOW. Hàm millis() giúp đo thời gian nhấn mà không làm chương trình bị đứng như khi dùng delay().
Lỗi thường gặp
| Hiện tượng | Nguyên nhân có thể |
|---|---|
| Chỉ sáng nền xanh | Chưa gọi lcd.init() hoặc lcd.backlight(), sai địa chỉ I2C, tương phản chỉnh chưa đúng |
| Không hiện gì | Sai dây SDA/SCL, chưa cấp nguồn, sai địa chỉ I2C |
| Ô vuông đen | LCD có nguồn nhưng chưa giao tiếp được với board |
| Chữ loạn | Sai thư viện, nhiễu nguồn, dây lỏng hoặc tốc độ I2C không ổn định |
| Không upload được | Chọn sai board, sai cổng COM hoặc board chưa vào chế độ nạp |
Hướng phát triển
Sau khi hiển thị được dấu chấm và dấu gạch, có thể nâng cấp bài này theo nhiều hướng:
- Thêm nút xóa ký tự cuối.
- Thêm nút xác nhận để dịch Morse sang chữ cái.
- Tự xuống dòng hoặc cuộn khi chuỗi dài hơn 16 ký tự.
- Hiển thị thời gian nhấn để tinh chỉnh ngưỡng
dotThreshold.
Đây là một bài nhỏ nhưng gom được nhiều kỹ năng quan trọng: đọc input, đo thời gian, xử lý trạng thái và hiển thị output.