Nhiễu do nút bấm, hay còn gọi là dao động tiếp điểm (contact bounce), xảy ra khi tiếp điểm cơ học bên trong nút không đóng/mở ngay lập tức mà dao động trong vài mili giây. Điều này tạo ra các tín hiệu không ổn định, ảnh hưởng đến độ chính xác khi vi điều khiển nhận tín hiệu.

Một ví dụ khá phổ biến là khi sử dụng thuật toán đếm số lần bấm nút của nút bấm. Số đếm được nhiều hơn số lần chúng ta thực sự bấm nút mặc cho thuật toán không có vấn đề gì. Nguyên nhân của vấn đề trên chính là Nhiễu.

1.Giải Pháp Chống Nhiễu Bằng Phần Cứng

Phần cứng có thể được thiết kế để loại bỏ hoặc giảm thiểu các tín hiệu nhiễu trước khi chúng được xử lý bởi vi điều khiển. Dưới đây là các thành phần chính trong sơ đồ:

  • Điện trở Kéo Xuống (Pull-down Resistor):
    • Điện trở 10kΩ kết nối từ chân nút bấm đến chân GND. Khi nút không được nhấn, điện trở này giữ cho tín hiệu ở mức logic LOW, giúp tránh nhiễu tín hiệu “floating”.
  • Tụ lọc (Debounce Capacitor):
    • Tụ điện 0.1µF (C104) được đặt song song với nút bấm. Tụ này có tác dụng lọc các dao động nhanh trong tín hiệu nút bấm khi tiếp điểm bị dao động, nhờ vào tính chất tích và xả điện của tụ điện.
    • Khi tiếp điểm dao động, tụ điện sẽ làm phẳng các dao động, tạo ra một tín hiệu ổn định hơn.
  • Kết nối với GPIO của Vi Điều Khiển:
    • Sau khi tín hiệu đã được làm sạch bởi điện trở và tụ điện, nó được đưa vào chân GPIO của vi điều khiển để xử lý cho các bước tiếp theo.

Lưu Ý: Khi sử dụng đồng thời Điện Trở Kéo và tụ lọc, sẽ xuất hiện độ trể từ khi bấm nút đến khi chân GPIO nhận được tín hiệu. Để tính toán độ trễ tín hiệu của nút bấm theo sơ đồ mạch, ta cần xem xét mạch RC (bao gồm tụ điện 0.1 µF và điện trở 10 kΩ). Đây là mạch khử nhiễu (debouncing) hoặc lọc tín hiệu (filtering) để loại bỏ tín hiệu không mong muốn.

Độ trễ của mạch RC phụ thuộc vào hằng số thời gian τ, được tính bằng công thức:

equation

  • R=10 kΩ=10,000 ΩR
  • C=0.1 μF=0.1×10−6 F

Tính τ:

equation

Hằng số thời gian này cho biết rằng tín hiệu sẽ đạt khoảng 63% giá trị cuối cùng sau 1 ms. Thông thường, để tín hiệu ổn định, ta cần khoảng 3τ đến đến 5τ (3 ms đeˆˊn 5 ms)

Tùy thuộc vào mức độ lọc nhiễu, chúng ta có thể giảm độ trễ bằng cách:

Giảm giá trị của điện trở R:

  • R càng nhỏ, hằng số thời gian τcàng giảm, và do đó tín hiệu sẽ ổn định nhanh hơn.
  • Tuy nhiên, nếu R quá nhỏ, dòng điện qua mạch khi nút bấm được nhấn sẽ tăng, điều này có thể ảnh hưởng đến mức tiêu thụ điện năng và hiệu năng của mạch.

Giảm giá trị của tụ điện C:

  • C càng nhỏ, hằng số thời gian τ càng giảm.
  • Tuy nhiên, nếu C quá nhỏ, khả năng khử nhiễu (debouncing) của mạch sẽ giảm, dẫn đến việc tín hiệu có thể không ổn định hoặc có hiện tượng “nhấp nháy” (chattering).

2. Giải Pháp Chống Nhiễu Code

Kích hoạt điện trở Kéo bằng câu lệnh trong phần Setup()

pinMode(buttonPin, INPUT_PULLUP); // Kích hoạt điện trở kéo nội bộ

Arduino có tích hợp điện trở kéo (pull-up resistor) bên trong các chân GPIO. Việc sử dụng điện trở kéo nội bộ giúp đơn giản hóa thiết kế phần cứng, đặc biệt khi bạn kết nối nút bấm trực tiếp với Arduino.

Khi sử dụng điện trở kéo nội bộ, bạn chỉ cần cấu hình chân GPIO làm INPUT_PULLUP. Khi đó, trạng thái mặc định của chân sẽ là HIGH khi nút không nhấn (mạch hở), và LOW khi nút được nhấn (mạch kín).

Code Arduino mẫu:

Dưới đây là đoạn code mẫu sử dụng điện trở kéo nội bộ Arduino

const int buttonPin = 3;     // Pin nút bấm
const int ledPin = 13;       // Pin kết nối đèn LED để hiển thị trạng
 
void setup() {
  pinMode(buttonPin, INPUT_PULLUP); // Kích hoạt điện trở kéo nội bộ
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.begin(9600);
}

void loop() {
  int buttonState = digitalRead(buttonPin); // Đọc trạng thái nút
  if (buttonState == LOW) { // Nút được nhấn (mức logic LOW)
    
    digitalWrite(ledPin, HIGH);
    Serial.println("Button Pressed!");
  } else { // Nút không nhấn (mức logic HIGH)
    
    digitalWrite(ledPin, LOW);
    Serial.println("Button Released!");
  }
  delay(100);
}

Code Arduino mẫu:

Dưới đây là đoạn code mẫu để lọc nhiễu kết hợp sử dụng điện trở kéo và lọc nhiễu Debounce.

const int buttonPin = 2;    // Chân kết nối nút bấm
const int ledPin = 13;      // Chân kết nối đèn LED
int buttonState = HIGH;     // Trạng thái hiện tại của nút bấm
int lastButtonState = HIGH; // Trạng thái nút bấm trước đó

unsigned long lastDebounceTime = 0; // Thời gian lần cuối cùng trạng thái thay đổi
unsigned long debounceDelay = 50;   // Độ trễ để lọc nhiễu (đơn vị: ms)

void setup() {
  pinMode(buttonPin, INPUT_PULLUP); // Kích hoạt điện trở kéo nội bộ
  pinMode(ledPin, OUTPUT);          // Cài đặt chân LED là đầu ra
  digitalWrite(ledPin, LOW);        // Ban đầu tắt đèn LED
}

void loop() {
  // Đọc trạng thái hiện tại của nút bấm
  int reading = digitalRead(buttonPin);

  // Kiểm tra nếu trạng thái nút thay đổi so với lần trước
  if (reading != lastButtonState) {
    // Cập nhật thời gian khi thay đổi trạng thái
    lastDebounceTime = millis();
  }

  // Nếu trạng thái ổn định vượt quá thời gian debounce
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // Cập nhật trạng thái nút bấm nếu có thay đổi
    if (reading != buttonState) {
      buttonState = reading;

      // Nếu nút đang được nhấn (mức logic LOW)
      if (buttonState == LOW) {
        digitalWrite(ledPin, HIGH); // Bật đèn LED
      } else {
        digitalWrite(ledPin, LOW);  // Tắt đèn LED
      }
    }
  }

  // Lưu trạng thái nút bấm để kiểm tra lần sau
  lastButtonState = reading;
}


Lưu ý:

  • Nếu nhiễu quá lớn (tần số cao), có thể cần kết hợp cả phần cứng (mạch RC) và phần mềm để đảm bảo tín hiệu ổn định hơn.