Flip-flop, bộ đếm và thanh ghi dịch 74HC595: mở rộng chân ra cho ESP32

Mạch chốt SR, flip-flop D lấy mẫu theo xung nhịp, bộ đếm nhị phân, thanh ghi dịch và IC 74HC595, dạng sóng khi dịch một byte, thí nghiệm ESP32 tự dịch bit ra 8 LED, đếm nhị phân và đèn chạy.

Cổng logic ở bài 27 chỉ phản ứng với đầu vào hiện tại: đầu vào đổi thì đầu ra đổi theo, không nhớ gì. Muốn mạch nhớ, đếm được, hay nhận dữ liệu từng bit một, cần thêm một loại mạch mới: flip-flop. Bài viết đi từ mạch chốt SR hai cổng NOR (một bit bộ nhớ), tới flip-flop D lấy mẫu theo xung nhịp, bộ đếm nhị phân, thanh ghi dịch, rồi tới IC 74HC595 rất hay dùng để mở rộng chân ra: chỉ ba chân ESP32 điều khiển được 8, 16, 24 đèn hay relay. Phần thí nghiệm tự viết hàm dịch từng bit ra 74HC595 để thấy rõ flip-flop làm việc thế nào.

1. Mạch chốt SR: một bit bộ nhớ

Ảnh chụp cận cảnh IC thanh ghi dịch HC595 vỏ TSSOP 16 chân màu đen hàn trên mạch in xanh lá, trên thân in chữ HC595 và các dòng mã, chấm tròn đánh dấu chân 1, hai bên là tụ và điện trở dán ghi 473
IC 74HC595 vỏ TSSOP-16 trên mạch một thiết bị mạng; bên trong là 16 flip-flop. Ảnh: Raimond Spekking, CC BY-SA 4.0, Wikimedia Commons, đã thu nhỏ.
Bên trái sơ đồ mạch chốt SR gồm hai cổng NOR: R vào cổng trên, S vào cổng dưới, ngõ ra Q của cổng trên quay về đầu vào cổng dưới, ngõ ra Q đảo của cổng dưới quay về đầu vào cổng trên; bên phải bảng trạng thái: S 0 R 0 giữ nguyên, S 1 R 0 Q bằng 1 đặt, S 0 R 1 Q bằng 0 xóa, S 1 R 1 cấm; ghi chú nhấn S một lần rồi nhả, Q lên 1 và ở đó tới khi R được nhấn, đây là một bit bộ nhớ
Mạch chốt SR từ hai cổng NOR (hình tự vẽ).

Nối hai cổng NOR sao cho ngõ ra của cổng này quay về đầu vào của cổng kia, ta được một mạch tự giữ trạng thái:

  • Đưa S (set, đặt) lên 1 trong chốc lát: Q lên 1. Khi S về 0, Q vẫn ở 1 vì chính Q đang giữ cổng kia ở trạng thái phù hợp.
  • Đưa R (reset, xóa) lên 1: Q về 0 và cũng ở yên đó.
  • S = R = 0: mạch giữ nguyên trạng thái cũ, tức là nhớ. S = R = 1 cùng lúc là trạng thái không dùng.

Đây là cách bộ nhớ RAM tĩnh (SRAM) trong ESP32 lưu từng bit: mỗi bit là một vòng hai cổng đảo nối chéo, chỉ khác là làm bằng sáu transistor.

2. Flip-flop D: lấy mẫu theo xung nhịp

Bên trái khối flip-flop D với đầu vào D, đầu vào xung nhịp CLK có hình tam giác, ngõ ra Q và Q đảo; bên phải ba dạng sóng CLK, D, Q: Q chỉ đổi tại các cạnh lên của CLK được đánh dấu mũi tên, lấy theo giá trị D lúc đó; khi D có xung ngắn giữa hai cạnh lên, Q không đổi
Flip-flop D và dạng sóng (hình tự vẽ).

Mạch chốt SR phản ứng ngay lập tức. Trong mạch số, ta muốn mọi thứ đổi trạng thái đồng loạt theo nhịp của một xung nhịp (clock). Flip-flop D làm đúng việc đó:

  • Tại cạnh lên của xung nhịp CLK (lúc CLK chuyển từ 0 lên 1), Q chép giá trị đang có ở D.
  • Giữa hai cạnh lên, Q giữ nguyên, D đổi thế nào cũng không ảnh hưởng.
  • Ký hiệu hình tam giác ở chân CLK nghĩa là "tác động theo cạnh". Bên trong flip-flop D là hai mạch chốt nối tiếp.

Điều kiện để flip-flop lấy mẫu đúng: D phải ổn định từ một chút trước tới một chút sau cạnh lên (thời gian thiết lập và giữ, cỡ vài chục nano giây với 74HC). Vì vậy khi lập trình, luôn đặt dữ liệu xong rồi mới tạo cạnh lên của xung nhịp.

3. Bộ đếm nhị phân

Ba flip-flop D FF0, FF1, FF2 nối nối tiếp: mỗi khối có Q đảo nối về D, xung CLK vào FF0, Q đảo của tầng trước làm xung nhịp cho tầng sau, ngõ ra Q0, Q1, Q2; bên dưới dạng sóng CLK, Q0 đổi trạng thái ở mỗi cạnh lên của CLK, Q1 đổi chậm gấp đôi, Q2 chậm gấp bốn, hàng số đếm 1, 2, 3, 4, 5, 6, 7, 0
Bộ đếm nhị phân 3 bit từ ba flip-flop (hình tự vẽ).
  • Nối Q̄ (ngõ ra đảo) của flip-flop D về chính đầu D: mỗi cạnh lên, Q chép giá trị ngược với chính nó, tức là đảo trạng thái. Ngõ ra Q có tần số bằng một nửa xung nhịp: đây là mạch chia đôi tần số.
  • Nối nhiều tầng như vậy, tầng sau lấy xung nhịp từ tầng trước: ba ngõ ra Q0, Q1, Q2 đọc thành số nhị phân tăng dần 0, 1, 2 … 7 rồi quay về 0. Đó là bộ đếm.
  • Đồng hồ điện tử dùng chính nguyên lý này: thạch anh 32 768 Hz qua 15 tầng chia đôi còn đúng 1 Hz, mỗi giây một xung. Bộ định thời (timer) trong ESP32 cũng là các bộ đếm như vậy, chỉ dài hơn (64 bit).

4. Thanh ghi dịch và IC 74HC595

Sơ đồ khối bên trong 74HC595: tám flip-flop FF0 đến FF7 nối thành hàng ngang, dữ liệu DS vào FF0, ngõ ra FF7 là Q7 phẩy nối sang IC sau, xung SH_CP điều khiển việc dịch; bên dưới tám ô chốt 0 đến 7 nhận dữ liệu từ hàng trên khi có xung ST_CP, qua thanh OE ra tám ngõ Q0 đến Q7; ghi chú chức năng từng chân
Bên trong 74HC595: thanh ghi dịch và thanh ghi chốt (hình tự vẽ, đơn giản hóa).

Nối 8 flip-flop D thành hàng, ngõ ra của ô này vào đầu D của ô kế tiếp, chung một xung nhịp: mỗi cạnh lên, mọi bit dịch sang phải một ô, ô đầu tiên nhận bit mới từ chân dữ liệu. Sau 8 xung nhịp, 8 bit đưa vào nối tiếp trên một dây đã nằm song song trên 8 ngõ ra. Đó là thanh ghi dịch (shift register) kiểu nối tiếp vào, song song ra.

74HC595 có thêm một hàng 8 mạch chốt phía sau thanh ghi dịch:

  • DS (chân 14): dữ liệu vào. SH_CP (chân 11): xung dịch. ST_CP (chân 12): xung chốt, chép 8 bit từ thanh ghi dịch sang hàng chốt.
  • Nhờ hàng chốt, trong lúc đang dịch, ngõ ra Q0–Q7 vẫn giữ giá trị cũ; chỉ khi có xung ST_CP, 8 ngõ ra mới đổi cùng lúc, đèn không bị nhấp nháy theo từng bit.
  • OE (chân 13, mức thấp là bật) bật tắt cả 8 ngõ ra; MR (chân 10, mức thấp là xóa) xóa thanh ghi dịch. Dùng bình thường thì OE nối GND, MR nối VCC.
  • Q7' (chân 9) là bit bị đẩy ra khỏi ô cuối: nối vào DS của IC 74HC595 thứ hai, dùng chung SH_CP và ST_CP, được 16 ngõ ra mà vẫn chỉ tốn ba chân vi điều khiển. Ghép bao nhiêu IC cũng được, chỉ là dịch lâu hơn.
Dạng sóng ba đường DS, SH_CP, ST_CP khi dịch byte 178 bằng 10110010 nhị phân: tám ô ghi bit 7 bằng 1, bit 6 bằng 0, bit 5 bằng 1, bit 4 bằng 1, bit 3 bằng 0, bit 2 bằng 0, bit 1 bằng 1, bit 0 bằng 0; DS đổi đầu mỗi ô, SH_CP có tám xung, mỗi xung lên ở nửa sau ô; ST_CP lên mức cao ở cuối; ghi chú sau tám xung bit 7 nằm ở Q7, bit 0 ở Q0, xung ST_CP làm tám LED đổi cùng lúc
Dạng sóng khi dịch một byte ra 74HC595 (hình tự vẽ, theo thứ tự lệnh của chương trình).

Một chiều ngược lại cũng có: 74HC165 là thanh ghi song song vào, nối tiếp ra, dùng để đọc 8 nút nhấn qua ba chân. Còn khi tải lớn hơn vài mA mỗi kênh (relay, dải LED), ngõ ra 74HC595 đi qua transistor (bài 19) hoặc IC đệm ULN2803.

5. Thí nghiệm: ESP32 điều khiển 8 LED qua 74HC595

Chuẩn bị

Sơ đồ nối

Sơ đồ: 3V3 của ESP32 nối chân 16 VCC và chân 10 MR của 74HC595; GPIO23 nối chân 14 DS, GPIO18 nối chân 11 SH_CP, GPIO5 nối chân 12 ST_CP; GND nối chân 8 và chân 13 OE; tám ngõ ra Q0 chân 15 và Q1 đến Q7 chân 1 đến 7, mỗi ngõ qua điện trở 330 ôm tới anode một LED, cathode các LED nối chung xuống đất
Sơ đồ thí nghiệm 74HC595 với 8 LED (hình tự vẽ).
  • IC nuôi 3,3 V để mức logic khớp với ESP32. Với LED đỏ, mỗi kênh khoảng (3,3 − 1,8) / 330 ≈ 4,5 mA, cả 8 kênh khoảng 36 mA, dưới giới hạn tổng 70 mA của IC.
  • Q0 ở chân 15 (phía bên kia vỏ), Q1–Q7 ở chân 1–7: dễ cắm nhầm thứ tự LED, nên kiểm tra bằng chế độ đèn chạy.
  • Tụ 100 nF sát chân 16 và chân 8.

Chương trình

/*
  PYWORLD.VN - Thanh ghi dịch 74HC595 với ESP32: tự dịch từng bit ra 8 LED, đếm nhị phân, đèn chạy và hiển thị số gõ từ Serial
  74HC595 nuôi 3,3 V: DS (chân 14) nối GPIO23, SH_CP (chân 11) nối GPIO18, ST_CP (chân 12) nối GPIO5; OE (13) xuống GND, MR (10) lên 3,3 V
  Q0 (chân 15) và Q1–Q7 (chân 1–7) mỗi chân qua 330 Ω tới anode một LED, cathode xuống GND
*/

#define CHAN_DS 23      // dữ liệu nối tiếp
#define CHAN_SH 18      // xung nhịp dịch (shift clock)
#define CHAN_ST 5       // xung chốt (storage/latch clock)

const uint32_t CHU_KY_MS = 250;
int cheDo = 0;          // 0: đếm nhị phân, 1: đèn chạy, 2: giữ giá trị gõ vào
uint8_t giaTri = 0;
uint32_t lanTruoc = 0;

// Dịch 8 bit ra 74HC595, bit cao trước: sau 8 xung, bit 7 nằm ở Q7, bit 0 nằm ở Q0
void ghi595(uint8_t b) {
  digitalWrite(CHAN_ST, LOW);
  for (int i = 7; i >= 0; i--) {
    digitalWrite(CHAN_DS, (b >> i) & 1);   // Đặt bit lên chân DS trước
    digitalWrite(CHAN_SH, HIGH);           // Cạnh lên: mọi flip-flop nhận bit của ô bên cạnh
    delayMicroseconds(1);
    digitalWrite(CHAN_SH, LOW);
  }
  digitalWrite(CHAN_ST, HIGH);             // Cạnh lên: chép 8 bit sang thanh ghi chốt, LED đổi cùng lúc
}

void inGiaTri(uint8_t b) {
  char nhiPhan[9];
  for (int i = 0; i < 8; i++) nhiPhan[i] = ((b >> (7 - i)) & 1) ? '1' : '0';
  nhiPhan[8] = '\0';
  const char *ten[] = {"dem", "chay", "nhap"};
  Serial.printf("[%s] Q7..Q0 = %s = %3u = 0x%02X\n", ten[cheDo], nhiPhan, (unsigned)b, (unsigned)b);
}

void docLenh() {
  if (!Serial.available()) return;
  String s = Serial.readStringUntil('\n');
  s.trim();
  if (s.length() == 0) return;
  if (s == "d") {
    cheDo = 0;
    giaTri = 0;
  } else if (s == "c") {
    cheDo = 1;
    giaTri = 1;
  } else {
    long v = s.toInt();
    if (v < 0 || v > 255 || (v == 0 && s != "0")) {
      Serial.println("Go so 0-255, 'd' de dem, 'c' de chay");
      return;
    }
    cheDo = 2;
    giaTri = (uint8_t)v;
  }
  ghi595(giaTri);
  inGiaTri(giaTri);
  lanTruoc = millis();
}

void setup() {
  Serial.begin(115200);
  pinMode(CHAN_DS, OUTPUT);
  pinMode(CHAN_SH, OUTPUT);
  pinMode(CHAN_ST, OUTPUT);
  digitalWrite(CHAN_SH, LOW);
  ghi595(0);
  delay(300);
  Serial.println("74HC595: go so 0-255 de hien thi, 'd' de dem nhi phan, 'c' de den chay");
}

void loop() {
  docLenh();
  if (cheDo == 2 || millis() - lanTruoc < CHU_KY_MS) return;
  lanTruoc = millis();
  if (cheDo == 0) {
    giaTri++;                                    // Bộ đếm 8 bit: 255 + 1 quay về 0
  } else {
    giaTri = (giaTri << 1) | (giaTri >> 7);      // Xoay vòng trái một bit
  }
  ghi595(giaTri);
  inGiaTri(giaTri);
}
  • ghi595() là phần chính: kéo ST_CP xuống, lần lượt đặt từng bit (bit cao trước) lên DS rồi tạo một xung SH_CP, cuối cùng kéo ST_CP lên để chốt. Hàm này làm đúng những gì hình 6 vẽ. Gói esp32 có sẵn hàm shiftOut() làm việc tương tự; tự viết một lần giúp hiểu rõ thanh ghi dịch.
  • Chế độ đếm: giaTri++ mỗi 250 ms, biến 8 bit tự quay về 0 sau 255; 8 LED hiện số đếm nhị phân, LED Q0 nháy nhanh nhất, mỗi LED sau chậm gấp đôi, giống hệt dạng sóng bộ đếm ở hình 4.
  • Chế độ đèn chạy: xoay vòng các bit sang trái. Gõ một số 0–255 vào Serial Monitor (chọn kiểu kết thúc dòng "Newline") để hiện số đó; gõ d quay về đếm, c sang đèn chạy.

Kết quả mong đợi

Hình minh họa Serial Monitor: dòng hướng dẫn, sáu dòng chế độ đếm từ 00000001 bằng 1 đến 00000110 bằng 6, một dòng chế độ nhập 10110010 bằng 178 bằng 0xB2, năm dòng chế độ đèn chạy 00000001, 00000010, 00000100, 00001000, 00010000
Kết quả mong đợi trên Serial Monitor (hình minh họa theo phép toán của chương trình).

LED sáng đúng theo dãy bit in ra: bit 1 là LED sáng. Gõ 178 thì LED Q7, Q5, Q4, Q1 sáng. Thử bỏ dòng digitalWrite(CHAN_ST, HIGH) ở cuối ghi595() rồi nạp lại: LED không đổi nữa, vì dữ liệu đã vào thanh ghi dịch nhưng chưa được chốt ra ngõ ra.

6. Xử lý lỗi thường gặp

Hiện tượngNguyên nhân thường gặpCách xử lý
Không LED nào sángOE để hở hoặc nối 3,3 V; MR nối GND; thiếu nguồn chân 16OE xuống GND, MR lên 3,3 V; đo nguồn giữa chân 16 và 8
LED sáng lộn xộn, không theo sốNhầm SH_CP với ST_CP, hoặc DS cắm nhầm chânĐối chiếu chân 11, 12, 14 với sơ đồ
Thứ tự LED bị ngược hoặc lệch một vị tríQuên Q0 ở chân 15; LED cắm theo thứ tự chân 1–8Dời LED Q0 sang chân 15; chân 8 là GND
LED nháy nhẹ khi đang dịchNối ST_CP chung với SH_CPTách riêng ST_CP, chỉ chốt sau khi đủ 8 bit
Gõ số không đổi gìSerial Monitor không gửi ký tự xuống dòngChọn "Newline" ở góc Serial Monitor
IC nóng, LED mờ khi sáng nhiềuDòng tổng quá lớn (điện trở nhỏ, LED trắng nuôi 5 V)Giữ điện trở 330 Ω trở lên; tải lớn dùng ULN2803

7. Xem thêm

  • Các bài liên quan trong loạt điện tử căn bản: LED và điện trở hạn dòng (bài 16), transistor làm công tắc (bài 19), cổng logic (bài 27).
  • Bài tiếp theo của loạt: tìm lỗi mạch điện tử từng bước.

Tin tức liên quan

Jack Type-C cái và điện trở 5,1 kΩ ở CC1, CC2: vì sao cắm sạc Type-C không lên nguồn
Jack Type-C cái và điện trở 5,1 kΩ ở CC1, CC2: vì sao cắm sạc Type-C không lên nguồn

Jack Type-C cái để hở CC1, CC2 thì sạc có cổng ra Type-C không cấp điện. Bài giải thích sơ đồ chân đầu cái, cách nguồn nhận ra thiết bị, cách gắn hai điện trở 5,1 kΩ và bảng tra lỗi thường gặp.

Sai số Abbe, sai số cosin và giãn nở nhiệt khi đo chuyển vị, kích thước: cách tính và cách giảm
Sai số Abbe, sai số cosin và giãn nở nhiệt khi đo chuyển vị, kích thước: cách tính và cách giảm

Ba nguồn sai số có ở mọi phép đo kích thước: sai số Abbe khi đường đo lệch thang đo, sai số cosin khi trục đo lệch chuyển động, giãn nở nhiệt; cách tính, ví dụ ngân sách và quy tắc bố trí.

Điều khiển hồng ngoại hoạt động thế nào: sóng mang 38 kHz, giao thức NEC và ESP32
Điều khiển hồng ngoại hoạt động thế nào: sóng mang 38 kHz, giao thức NEC và ESP32

Giải thích điều khiển hồng ngoại: sóng mang 38 kHz, mắt thu và giao thức NEC với khung 32 bit, mã lặp. Hướng dẫn tự giải mã phím điều khiển và tự phát lệnh bằng ESP32, không dùng thư viện ngoài.

Vali nhựa hay vali nhôm: chọn loại nào để đựng thiết bị, dụng cụ
Vali nhựa hay vali nhôm: chọn loại nào để đựng thiết bị, dụng cụ

So sánh vali nhựa và vali nhôm đựng thiết bị theo chống nước, chống bụi, chịu va đập, nhiệt độ, vẻ ngoài, khóa và bảo dưỡng; khi nào nên chọn mỗi loại và sơ đồ chọn nhanh.

IC 555: chế độ dao động và đơn ổn, cách tính tần số và thời gian
IC 555: chế độ dao động và đơn ổn, cách tính tần số và thời gian

IC 555 là gì, sơ đồ chân và cấu tạo bên trong, mạch đơn ổn tạo trễ và mạch dao động nháy LED, nguồn gốc công thức t = 1,1RC và f = 1,44/((R1 + 2R2)C), bảng giá trị và mạch tạo trễ relay.

Tự thiết kế khung tin trên UART: byte bắt đầu, độ dài, CRC và thời gian chờ
Tự thiết kế khung tin trên UART: byte bắt đầu, độ dài, CRC và thời gian chờ

Hướng dẫn thiết kế một khung tin trên UART gồm byte bắt đầu, độ dài, loại, dữ liệu và CRC-16, cùng bộ nhận dạng máy trạng thái trên ESP32 biết bỏ khung hỏng và tự hồi phục khi mất đồng bộ.

Hiệu chuẩn load cell tại hiện trường: tải thật, mô phỏng mV/V, thế chỗ, ISO 376 và ASTM E74
Hiệu chuẩn load cell tại hiện trường: tải thật, mô phỏng mV/V, thế chỗ, ISO 376 và ASTM E74

Hiệu chuẩn hệ load cell tại hiện trường: chuỗi đo và nguồn sai số, tải thật so với mô phỏng mV/V, thế chỗ cho cân bồn, lưu ý lắp đặt, so sánh ISO 376 và ASTM E74.

Quy định bay flycam tại Việt Nam 2026: đăng ký, giấy phép điều khiển, flycam dưới 250 g, phép bay
Quy định bay flycam tại Việt Nam 2026: đăng ký, giấy phép điều khiển, flycam dưới 250 g, phép bay

Tóm tắt quy định bay flycam theo Luật Phòng không nhân dân 2024 và Nghị định 288/2025: 5 loại theo trọng lượng, đăng ký, giấy phép điều khiển, khi nào flycam dưới 250 g được miễn phép bay.


Bình luận
Đã thêm vào giỏ hàng