Nội Dung Bài Viết
Trong chuỗi bài viết về các phương pháp chống dội nút nhấn, hôm nay chúng ta sẽ tìm hiểu Phương pháp 2: Chống dội nút nhấn bằng dịch bit (Bit-shift Debounce Filter) trong STM32f103 – một kỹ thuật phần mềm hiệu quả, không cần dùng timer, phù hợp cho hệ thống quét nút định kỳ.
Trong quá trình lập trình vi điều khiển STM32F103 bằng thanh ghi, xử lý hiện tượng dội nút nhấn (button bounce) là một bước quan trọng để đảm bảo hệ thống hoạt động chính xác. Khi người dùng nhấn hoặc thả nút, các tiếp điểm cơ học thường dao động trong vài mili giây, tạo ra tín hiệu không ổn định. Nếu không được lọc, hệ thống có thể hiểu sai thành nhiều lần nhấn, gây lỗi trong xử lý.
Phương pháp 2: Dịch bit (Bit-shift Debounce Filter)
Khi bạn nhấn nút, các tiếp điểm bên trong có thể dao động trong vài mili giây (thường 5-20ms), tạo ra tín hiệu ngắt quãng. Nếu hệ thống đọc tín hiệu này ngay lập tức mà không lọc, nó sẽ ghi nhận nhiều lần nhấn giả, gây lỗi (ví dụ: đếm sai số lần nhấn).
Nguyên lý hoạt động phương pháp chống dội nút nhấn bằng dịch bit (Bit-shift Debounce Fliter)
Nguyên lý
- Phương pháp này sử dụng một “bộ đệm dịch bit” (shift register) để ghi lại trạng thái của nút qua nhiều lần đọc.
- Mỗi chu kỳ vòng lặp, đọc giá trị nút (0 hoặc 1).
- Dịch giá trị này vào một thanh ghi (biến 8-bit hoặc 32-bit).
- Nếu 8 lần liên tiếp là 1 → nút được nhấn thật.
- Nếu 8 lần liên tiếp là 0 → nút được thả thật.
Sơ đồ (flow chart) phương pháp chống dội nút nhấn bằng dịch bit

Cách hoạt động phương pháp chống dội nút nhấn bằng dịch bit (Bit-shift Debounce Filter)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | void UpdateButton(GPIO_TypeDef* port, uint32_t pin, Button* btn, uint32_t active) { uint32_t keyInput = (((port->IDR.reg >> pin) & 1U) == active) ? 1U: 0U; btn->keyDebounceValue = (btn->keyDebounceValue << 1) | keyInput; if (btn->keyDebounceValue >= 0xFF) { if (btn->keyState == BTN_IDLE) { btn->keyState = BTN_PRESSED; btn->keyEvent = BTN_PRESSED; } else { btn->keyEvent = BTN_IDLE; } } else { if (btn->keyState == BTN_PRESSED) { btn->keyState = BTN_IDLE; btn->keyEvent = BTN_RELEASE; } else { btn->keyEvent = BTN_IDLE; } } } |
Chương trình main chống dội nút nhấn bằng dịch bit (Bit-shift Debounce Filter)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int main(void) { SystemClock_Config(); // Initialize system clock GPIO_LED_Config(); GPIO_Button_Config(); while (1) { // Process button with bit shift debounce UpdateButton(GPIOC,1, &keyInput, 0); if (keyInput.keyEvent == BTN_PRESSED) { LED_Toggle(); } } } |
Chương trình chống dội nút nhấn bằng dịch bit hoạt động như sau:
- Bước 1: Đọc trạng thái GPIO (keyInput) và gán 0 hoặc 1 dựa trên active.
- Bước 2: Dịch trái keyDebounceValue (một byte, 8 bit) và thêm keyInput vào bit thấp nhất. Điều này giống như một hàng chờ 8 lần đọc.
- Bước 3: Nếu keyDebounceValue đạt 0xFF (8 lần đọc liên tiếp là 1), xác nhận nút được nhấn (BTN_PRESSED). Nếu giảm xuống dưới 0xFF và trước đó là BTN_PRESSED, xác nhận nút được thả (BTN_RELEASE).
- Ví dụ: Nếu bạn nhấn nút, keyDebounceValue sẽ tăng từ 0x00, 0x01, 0x03, …, đến 0xFF sau 8 lần đọc ổn định, sau đó hệ thống mới phản hồi.
Link Github: Download chương trình chống dội nút nhấn bằng phường pháp dịch bit (bit-shift Debounce Filter)
Ưu điểm chống dội nút nhấn bằng dịch bit (Bit-shift Debounce Filter)
- Không cần timer → giảm độ phức tạp trong lập trình, phù hợp khi tài nguyên hạn chế.
- Nhẹ, hiệu quả cho hệ thống quét nút định kỳ → chỉ cần một biến lưu trạng thái dịch bit, không chiếm nhiều RAM/Flash.
- Không gây blocking CPU → khác với phương pháp delay thủ công, hệ thống vẫn có thể xử lý các tác vụ khác trong khi quét nút.
- Dễ mở rộng cho nhiều nút → chỉ cần thêm cấu trúc dữ liệu cho từng nút, không ảnh hưởng đến hiệu suất tổng thể.
- Độ tin cậy cao khi tần suất quét ổn định → đảm bảo loại bỏ nhiễu cơ học mà không cần phần cứng bổ sung.
Nhược điểm chống dội nút nhấn bằng dịch bit (Bit-shift Debounce Filter)
- Thời gian chống dội phụ thuộc tần suất quét → nếu vòng lặp chậm, thời gian debounce sẽ dài; nếu vòng lặp quá nhanh, dễ lọt nhiễu.
- Khó điều chỉnh chính xác thời gian debounce → phải cân bằng giữa số bit dịch và tốc độ quét để đạt hiệu quả mong muốn.
- Cần vòng lặp quét đều đặn → nếu hệ thống không duy trì chu kỳ quét ổn định, kết quả chống dội có thể sai lệch.
- Phức tạp hơn delay thủ công → đòi hỏi hiểu về dịch bit và cấu trúc dữ liệu, không trực quan bằng cách chèn
delay(). - Không phù hợp cho hệ thống real-time khắt khe nếu tần suất quét không được đảm bảo chính xác.
So sánh với phương pháp Delay thủ công
| Tiêu chí | Delay thủ công (Simple Delay) | Dịch bit (Bit-shift Filter) |
|---|---|---|
| Nguyên lý | Chèn delay() sau khi nhấn | Dịch bit trạng thái nút qua nhiều lần đọc |
| Blocking CPU | Có | Không |
| Cần timer | Không | Không |
| Độ chính xác | Phụ thuộc độ dài delay | Phụ thuộc tần suất quét |
| Khả năng mở rộng | Kém | Tốt |
| Phù hợp hệ thống real-time | Không | Có thể |
| Ứng dụng phù hợp | Demo, hệ thống đơn giản | Hệ thống quét nút định kỳ |
Kết luận
Phương pháp chống dội nút nhấn bằng dịch bit (Bit-shift Debounce Filter) trong lập trình STM32F103 thanh ghi là một giải pháp phần mềm gọn nhẹ, dễ triển khai và không gây blocking CPU. Bằng cách sử dụng một bộ đệm dịch bit để theo dõi trạng thái nút qua nhiều chu kỳ đọc, hệ thống có thể xác định chính xác khi nút thực sự được nhấn hoặc thả.
Tuy nhiên, thời gian chống dội của phương pháp này phụ thuộc vào tần suất quét nút, nên việc điều chỉnh độ nhạy có thể không linh hoạt bằng các phương pháp dùng timer. Dù vậy, đây vẫn là lựa chọn lý tưởng cho các hệ thống nhúng nhỏ, có vòng lặp quét đều đặn và không yêu cầu thời gian thực nghiêm ngặt.
