Màn hình 7-segment 1 chữ số là module hiển thị đơn giản nhất trong thế giới nhúng — 7 đoạn LED xếp thành hình số 8, bật/tắt các tổ hợp để tạo chữ số 0-9. Bài này giải thích tại sao cùng module nhưng logic điều khiển ngược nhau (common anode vs cathode), bảng mã segment đầy đủ, và cách viết code đếm cho Arduino Uno và ESP32.
Nguyên Lý Hoạt Động
1. Cấu Trúc 7 Đoạn LED
Một module 7-segment chứa 7 LED (gọi là “segment”) xếp theo hình chữ số:
Vị trí 7 segment:
aaa
f b
f b
ggg
e c
e c
ddd [dp]
| Segment | Vị trí | Ví dụ dùng |
|---|---|---|
| a | Ngang trên | 0, 2, 3, 5, 6, 7, 8, 9 |
| b | Dọc trên phải | 0, 1, 2, 3, 4, 7, 8, 9 |
| c | Dọc dưới phải | 0, 1, 3, 4, 5, 6, 7, 8, 9 |
| d | Ngang dưới | 0, 2, 3, 5, 6, 8, 9 |
| e | Dọc dưới trái | 0, 2, 6, 8 |
| f | Dọc trên trái | 0, 4, 5, 6, 8, 9 |
| g | Ngang giữa | 2, 3, 4, 5, 6, 8, 9 |
| dp | Chấm thập phân | Tùy chọn |
2. Common Cathode vs Common Anode
Đây là điểm dễ nhầm nhất khi dùng 7-segment:
Common Cathode (CC):
- Tất cả cathode (-) của 7 LED nối chung → nối xuống GND
- Anode (+) của từng LED nối với GPIO qua điện trở
- HIGH = LED sáng, LOW = LED tắt
Common Cathode:
GPIO ──[R]── Anode (+) LED ── Cathode (–) ── GND
│
(tất cả chung)
Common Anode (CA):
- Tất cả anode (+) của 7 LED nối chung → nối lên VCC
- Cathode (–) của từng LED nối với GPIO qua điện trở
- LOW = LED sáng, HIGH = LED tắt (logic ngược!)
Common Anode:
VCC ── Anode (+) LED ── Cathode (–) ──[R]── GPIO
│
(tất cả chung)
Cách nhận biết loại module:
- Đọc datasheet/nhãn: ký hiệu CC hoặc CA
- Thử điện: cắm VCC vào chân COM và GND vào chân segment bất kỳ qua 470Ω → sáng = Common Anode; làm ngược lại → sáng = Common Cathode
3. Bảng Mã Segment (0-9)
Mỗi chữ số được encode thành 7 bit (a=bit0, b=bit1, …, g=bit6):
Chữ số — Segment cần sáng — Mã hex (Common Cathode: 1=sáng)
Digit a b c d e f g HEX (gfedcba)
0 1 1 1 1 1 1 0 0x3F ← 6 đoạn, không có g (giữa)
1 0 1 1 0 0 0 0 0x06 ← chỉ b, c
2 1 1 0 1 1 0 1 0x5B
3 1 1 1 1 0 0 1 0x4F
4 0 1 1 0 0 1 1 0x66 ← b, c, f, g
5 1 0 1 1 0 1 1 0x6D
6 1 0 1 1 1 1 1 0x7D
7 1 1 1 0 0 0 0 0x07 ← a, b, c
8 1 1 1 1 1 1 1 0x7F ← tất cả
9 1 1 1 1 0 1 1 0x6F
Common Anode: đảo bit → mã = (~CC_mã) & 0x7F. Ví dụ: 0 → 0x3F → ~0x3F & 0x7F = 0x40.
Thông Số Kỹ Thuật
| Thông số | Giá trị |
|---|---|
| Loại | LED 7-segment, 1 chữ số |
| Màu phổ biến | Đỏ, xanh lá, xanh dương, vàng |
| Điện áp forward (Vf) | ~2V (đỏ/vàng), ~3.3V (xanh) |
| Dòng mỗi segment | 10-20mA |
| Điện áp hoạt động | 3.3V hoặc 5V (với điện trở phù hợp) |
| Số GPIO cần | 7 (segment a-g) + 1 tuỳ chọn (dp) |
| Kích thước phổ biến | 0.36″, 0.56″, 1.0″ |
Tính Điện Trở Hạn Dòng
R = (VCC - Vf) / I_target
Arduino Uno (5V), LED đỏ (Vf=2V), I=15mA:
R = (5 - 2) / 0.015 = 200Ω → dùng 220Ω
ESP32 (3.3V), LED đỏ (Vf=2V), I=10mA:
R = (3.3 - 2) / 0.010 = 130Ω → dùng 150Ω
Sơ Đồ Chân (Pinout)
7-Segment 1 chữ số (nhìn từ mặt trước):
Mặt trước:
┌────────────────────┐
│ ┌─────────────┐ │
│ │ Chữ số 8 │ │
│ └─────────────┘ │
└────────────────────┘
Chân dưới (từ trái sang): e d COM c dp
Chân trên (từ trái sang): f COM b a g
| Chân | Ký hiệu | Mô tả |
|---|---|---|
| COM | VCC (CA) hoặc GND (CC) | Chân chung |
| a-g | Segment a đến g | Điều khiển từng đoạn |
| dp | Decimal Point | Chấm thập phân |
Kết Nối Phần Cứng
7-Segment (Common Cathode) với Arduino Uno
Arduino Uno [220Ω] 7-Segment CC
────────── ────── ─────────────
Pin 2 ───────────[220Ω]──→ a
Pin 3 ───────────[220Ω]──→ b
Pin 4 ───────────[220Ω]──→ c
Pin 5 ───────────[220Ω]──→ d
Pin 6 ───────────[220Ω]──→ e
Pin 7 ───────────[220Ω]──→ f
Pin 8 ───────────[220Ω]──→ g
GND ─────────────────────→ COM (GND chung)
7-Segment (Common Cathode) với ESP32
ESP32 DevKit V1 [150Ω] 7-Segment CC
─────────────── ────── ─────────────
GPIO18 ───────────[150Ω]──→ a
GPIO19 ───────────[150Ω]──→ b
GPIO21 ───────────[150Ω]──→ c
GPIO22 ───────────[150Ω]──→ d
GPIO23 ───────────[150Ω]──→ e
GPIO5 ───────────[150Ω]──→ f
GPIO4 ───────────[150Ω]──→ g
GND ─────────────────────→ COM (GND chung)
Code Arduino IDE
Code Đếm 0-9 — Arduino Uno (Common Cathode)
/*
* 7-Segment 1 chữ số — Đếm từ 0 đến 9 liên tục
* Board: Arduino Uno
* Loại: Common Cathode (COM → GND)
* Kết nối: Pin2→a, Pin3→b, Pin4→c, Pin5→d, Pin6→e, Pin7→f, Pin8→g (qua 220Ω)
*/
// Chân GPIO cho từng segment
const int SEG_A = 2;
const int SEG_B = 3;
const int SEG_C = 4;
const int SEG_D = 5;
const int SEG_E = 6;
const int SEG_F = 7;
const int SEG_G = 8;
const int segPins[] = {SEG_A, SEG_B, SEG_C, SEG_D, SEG_E, SEG_F, SEG_G};
const int NUM_SEGS = 7;
/*
* Bảng mã segment cho Common Cathode
* Thứ tự bit: a=bit0, b=bit1, c=bit2, d=bit3, e=bit4, f=bit5, g=bit6
* 1 = sáng, 0 = tắt
*/
const byte digitCode[10] = {
0x3F, // 0: a,b,c,d,e,f sáng — không có g
0x06, // 1: b,c sáng
0x5B, // 2: a,b,d,e,g sáng
0x4F, // 3: a,b,c,d,g sáng
0x66, // 4: b,c,f,g sáng
0x6D, // 5: a,c,d,f,g sáng
0x7D, // 6: a,c,d,e,f,g sáng
0x07, // 7: a,b,c sáng
0x7F, // 8: tất cả sáng
0x6F // 9: a,b,c,d,f,g sáng
};
// Hiển thị chữ số (0-9) lên 7-segment
void displayDigit(int digit) {
if (digit < 0 || digit > 9) return;
byte code = digitCode[digit];
for (int i = 0; i < NUM_SEGS; i++) {
digitalWrite(segPins[i], (code >> i) & 0x01); // Lấy bit thứ i
}
}
// Tắt tất cả segment
void clearDisplay() {
for (int i = 0; i < NUM_SEGS; i++) {
digitalWrite(segPins[i], LOW);
}
}
void setup() {
// Cấu hình tất cả pin segment là OUTPUT
for (int i = 0; i < NUM_SEGS; i++) {
pinMode(segPins[i], OUTPUT);
}
clearDisplay();
Serial.begin(9600);
Serial.println("7-Segment đang chạy...");
}
void loop() {
for (int d = 0; d <= 9; d++) {
displayDigit(d);
Serial.print("Hiển thị: "); Serial.println(d);
delay(1000); // Mỗi chữ số 1 giây
}
}
Code Common Anode — Arduino Uno
/*
* 7-Segment 1 chữ số — Common Anode
* Board: Arduino Uno
* Loại: Common Anode (COM → 5V)
* Logic: LOW = sáng, HIGH = tắt (ngược với Common Cathode!)
* Kết nối: COM→5V, Pin2→a(qua 220Ω), ..., Pin8→g(qua 220Ω)
*/
const int segPins[] = {2, 3, 4, 5, 6, 7, 8}; // a, b, c, d, e, f, g
const int NUM_SEGS = 7;
/*
* Bảng mã cho Common Anode — logic NGƯỢC với CC
* 0 = sáng (LOW output), 1 = tắt (HIGH output)
* Mã = ~(CC_mã) & 0x7F
*/
const byte digitCodeCA[10] = {
0x40, // 0: ~0x3F = 0x40
0x79, // 1: ~0x06 = 0x79
0x24, // 2: ~0x5B = 0x24
0x30, // 3: ~0x4F = 0x30
0x19, // 4: ~0x66 = 0x19
0x12, // 5: ~0x6D = 0x12
0x02, // 6: ~0x7D = 0x02
0x78, // 7: ~0x07 = 0x78
0x00, // 8: ~0x7F = 0x00 (tất cả LOW = tất cả sáng)
0x10 // 9: ~0x6F = 0x10
};
void displayDigit(int digit) {
if (digit < 0 || digit > 9) return;
byte code = digitCodeCA[digit];
for (int i = 0; i < NUM_SEGS; i++) {
digitalWrite(segPins[i], (code >> i) & 0x01); // 0=LOW=sáng, 1=HIGH=tắt
}
}
void setup() {
for (int i = 0; i < NUM_SEGS; i++) {
pinMode(segPins[i], OUTPUT);
digitalWrite(segPins[i], HIGH); // Tắt tất cả lúc đầu (CA: HIGH=tắt)
}
}
void loop() {
for (int d = 0; d <= 9; d++) {
displayDigit(d);
delay(800);
}
}
Code Đồng Hồ Đếm Ngược — Arduino Uno
/*
* 7-Segment — Đồng hồ đếm ngược 9→0, reset khi bấm nút
* Board: Arduino Uno
* Loại: Common Cathode
* Kết nối: segment như trên; Nút bấm→Pin9 (+ pull-up nội bộ)
*/
const int segPins[] = {2, 3, 4, 5, 6, 7, 8}; // a,b,c,d,e,f,g
const int BTN_PIN = 9;
const int NUM_SEGS = 7;
const byte digitCode[10] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, // 0-4
0x6D, 0x7D, 0x07, 0x7F, 0x6F // 5-9
};
void displayDigit(int d) {
if (d < 0 || d > 9) return;
byte code = digitCode[d];
for (int i = 0; i < NUM_SEGS; i++) {
digitalWrite(segPins[i], (code >> i) & 0x01);
}
}
// Nháy LED cảnh báo khi đếm về 0
void blinkZero() {
for (int i = 0; i < 6; i++) {
displayDigit(0); delay(200);
for (int s = 0; s < NUM_SEGS; s++) digitalWrite(segPins[s], LOW);
delay(200);
}
}
int countdown = 9;
unsigned long lastTick = 0;
void setup() {
for (int i = 0; i < NUM_SEGS; i++) {
pinMode(segPins[i], OUTPUT);
}
pinMode(BTN_PIN, INPUT_PULLUP); // Nút bấm active LOW
displayDigit(countdown);
}
void loop() {
// Reset khi bấm nút
if (digitalRead(BTN_PIN) == LOW) {
countdown = 9;
displayDigit(countdown);
delay(300); // Debounce
}
// Đếm ngược mỗi 1 giây
if (millis() - lastTick >= 1000) {
lastTick = millis();
if (countdown > 0) {
countdown--;
displayDigit(countdown);
} else {
blinkZero(); // Nháy 3 lần khi về 0
countdown = 9; // Reset tự động
displayDigit(countdown);
}
}
}
Code ESP32 — Đếm Và Hiển Thị Số Ngẫu Nhiên
/*
* 7-Segment — ESP32, Common Cathode, lắc xúc xắc (1-6)
* Board: ESP32 DevKit V1
* Kết nối: GPIO18→a, GPIO19→b, GPIO21→c, GPIO22→d,
* GPIO23→e, GPIO5→f, GPIO4→g (qua 150Ω)
* Nút→GPIO0 (nút BOOT trên DevKit)
*/
const int segPins[] = {18, 19, 21, 22, 23, 5, 4}; // a,b,c,d,e,f,g
const int BTN_PIN = 0; // Nút BOOT trên ESP32 DevKit
const int NUM_SEGS = 7;
const byte digitCode[10] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, // 0-4
0x6D, 0x7D, 0x07, 0x7F, 0x6F // 5-9
};
void displayDigit(int d) {
if (d < 0 || d > 9) return;
byte code = digitCode[d];
for (int i = 0; i < NUM_SEGS; i++) {
digitalWrite(segPins[i], (code >> i) & 0x01);
}
}
// Animation: đảo nhanh 0-9 trước khi dừng ở số cuối
void rollAnimation(int finalNum, int rollCount) {
for (int i = 0; i < rollCount; i++) {
displayDigit(i % 10);
delay(80);
}
displayDigit(finalNum); // Hiện số kết quả
}
bool lastBtnState = HIGH;
void setup() {
Serial.begin(115200);
for (int i = 0; i < NUM_SEGS; i++) {
pinMode(segPins[i], OUTPUT);
digitalWrite(segPins[i], LOW);
}
pinMode(BTN_PIN, INPUT_PULLUP);
randomSeed(esp_random()); // ESP32 có hardware RNG
displayDigit(6); // Hiện 6 lúc đầu
Serial.println("Nhấn nút BOOT để lắc xúc xắc");
}
void loop() {
bool btnState = digitalRead(BTN_PIN);
// Phát hiện cạnh xuống (nhấn nút)
if (btnState == LOW && lastBtnState == HIGH) {
int result = random(1, 7); // Số ngẫu nhiên 1-6
Serial.printf("Xúc xắc: %d\n", result);
rollAnimation(result, 20); // Quay 20 frame rồi dừng
delay(200); // Debounce
}
lastBtnState = btnState;
}
Kết Quả Mong Đợi
Serial Monitor:
7-Segment đang chạy...
Hiển thị: 0
Hiển thị: 1
Hiển thị: 2
...
Hiển thị: 9
Hiển thị: 0
(lặp lại)
Ứng Dụng Thực Tế
| Ứng dụng | Mô tả |
|---|---|
| Đồng hồ đếm ngược | Kết hợp nút bấm reset, hiển thị giây |
| Xúc xắc điện tử | Số ngẫu nhiên 1-6 khi lắc cảm biến |
| Bộ đếm sản phẩm | Tăng 1 khi cảm biến IR phát hiện vật |
| Hiển thị tầng thang máy | Kết hợp 4 module 7-seg (4 tầng) |
| Score game đơn giản | Tăng điểm khi chạm đích |
Lưu Ý Khi Sử Dụng
1. Bắt buộc dùng điện trở hạn dòng
Không có điện trở → dòng không giới hạn → LED cháy ngay hoặc kéo GPIO xuống → GPIO hỏng. Mỗi segment cần 1 điện trở riêng (7 điện trở cho 7 segment).
2. Không nhầm Common Anode với Common Cathode
Cách nhanh nhất: thử displayDigit(8) (tất cả sáng). Nếu tất cả tối → sai loại → đổi logic (thêm code = (~code) & 0x7F).
3. GPIO ESP32 bị giới hạn dòng
Mỗi GPIO ESP32: max 40mA tổng, khuyến nghị 12mA/pin. Với 7 segment cùng sáng: 7 × 12mA = 84mA — an toàn nếu dùng điện trở 150Ω+. Tuyệt đối không cắm thẳng không có điện trở.
4. Dùng Multiplexing cho nhiều chữ số
Để hiển thị 4 chữ số, không cần 4×7=28 GPIO. Kỹ thuật multiplexing: chia sẻ 7 chân segment, thêm 4 chân SELECT, quét lần lượt mỗi digit ở tốc độ cao (>100Hz) → mắt không thấy nhấp nháy.


