IoTLabs

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

Series 37 Module Cảm Biến – 7-Segment 1 Chữ Số: Mã Segment 0x3F-0x7F, Common Anode vs Cathode & Đếm 0-9

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]
SegmentVị tríVí dụ dùng
aNgang trên0, 2, 3, 5, 6, 7, 8, 9
bDọc trên phải0, 1, 2, 3, 4, 7, 8, 9
cDọc dưới phải0, 1, 3, 4, 5, 6, 7, 8, 9
dNgang dưới0, 2, 3, 5, 6, 8, 9
eDọc dưới trái0, 2, 6, 8
fDọc trên trái0, 4, 5, 6, 8, 9
gNgang giữa2, 3, 4, 5, 6, 8, 9
dpChấm thập phânTù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:

  1. Đọc datasheet/nhãn: ký hiệu CC hoặc CA
  2. 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ạiLED 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 segment10-20mA
Điện áp hoạt động3.3V hoặc 5V (với điện trở phù hợp)
Số GPIO cần7 (segment a-g) + 1 tuỳ chọn (dp)
Kích thước phổ biến0.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ânKý hiệuMô tả
COMVCC (CA) hoặc GND (CC)Chân chung
a-gSegment a đến gĐiều khiển từng đoạn
dpDecimal PointChấ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ụngMô tả
Đồng hồ đếm ngượcKế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ẩmTăng 1 khi cảm biến IR phát hiện vật
Hiển thị tầng thang máyKết hợp 4 module 7-seg (4 tầng)
Score game đơn giảnTă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.

Bài tiếp theo: