Arduino – Nút nhấn

Arduino – Nút nhấn

Kiến thức

Nút nhấn sẽ giúp khởi động 1 hành động nào đó khi cần thiết. Những ứng dụng thực tế hầu như đều cần những kích hoạt từ bên ngoài thông qua các loại nút nhấn như nút nhấn cảm ứng, nút nhấn nhấn lưu trạng thái on/off, nút nhấn nhiều trạng thái…​ Trong phần này, chúng ta sẽ tìm hiểu những vấn đề về sử dụng nút nhấn thông qua các ví dụ mẫu. Các loại nút nhấn trong thực tế như hình bên dưới:

buttons image
Hình 1. Hình ảnh về các loại nút nhấn trong thực tế

Với nút nhấn không giữ trạng thái, khi nhấn nút và giữ thì sẽ cho dòng điện chạy qua. Ngược lại, khi nhả hoặc không nhấn sẽ không cho dòng điện chạy qua. Nguyên lí hoạt động của nút nhấn không giữ trạng thái như hình dưới:

button circuit 1
Hình 2. Mạch nguyên lí của nút nhấn không giữ trạng thái

Chớp, tắt LED sử dụng nút nhấn

Yêu cầu

Nhấn nút thì đèn LED sáng, không nhấn nút đèn LED sẽ tắt.

Linh kiện cần dùng

  • Board Arduino Uno

  • Breadboard

  • Nút nhấn

  • Led

  • Điện trở 330Ω

  • Điện trở 10KΩ

  • Dây kết nối

Đấu nối

Kết nối nút nhấn và LED với board Arduino Uno theo sơ đồ sau:

buttonPin
Hình 3. Hình ảnh sơ đồ kết nối thực tế

Điện trở kéo

Trong sơ đồ kết nối, nút nhấn đang được điện trở 10KΩ kéo xuống ground (mass). Đây được gọi là điện trở kéo xuống. Điện trở kéo lên nguồn, hoặc kéo xuống ground (mass) được sử dụng rất thường xuyên trong vi điều khiển hoặc trong các mạch số (digital circuit).

Với vi điều khiển, 1 chân được cấu hình là INPUT (ngõ vào), nếu không có thiết bị hay mạch điện nào kết nối với nó. Khi vi điều khiển đọc trạng thái của chân đó thì chúng ta không xác định mức điện áp của nó được bởi nó có thể ở mức HIGH hoặc mức LOW, thuật ngữ thường được sử dụng để diễn tả trạng thái này là floating (trôi nổi).

Để khắc phục hiện tượng này, chúng ta sẽ kết nối chân này với 1 điện trở kéo lên nguồn (pull-up) hoặc 1 điện trở kéo xuống ground hay mass (pull-down) để đảm bảo chân đó chỉ ở 1 trong 2 trạng thái, hoặc HIGH, hoặc LOW.

Như vậy, khi không nhấn button, trạng thái của pin sẽ ở mức LOW và khi button được nhấn thì trạng thái sẽ ở mức HIGH.

Nếu mắc mạch điện như trên mà không dùng điện trở kéo thì sẽ xảy ra hiện tượng ngắn mạch.

Thông thường, giá trị điện trở kéo nằm trong khoảng 4.7KΩ đến 10KΩ là phù hợp.

Source code

const int buttonPin = 2;  //  Chân kết nối với nút nhấn
const int ledPin =  13;    //  Chân kết nối với LED
int buttonState = 0;      //  Biến đọc trạng thái của nút nhấn.

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(115200);
  Serial.println("init serial");
}

void loop()
{
  buttonState = digitalRead(buttonPin); //  Đọc trạng thái của nút nhấn.

  if (buttonState == HIGH) {             //  Kiểm tra, nếu button đã được nhấn
    digitalWrite(ledPin, HIGH);         //  Bật LED
    Serial.println("PRESSED, LED ON");  //  In ra màn hình Serial chữ PRESSED, LED ON
  } else {
    digitalWrite(ledPin, LOW);
    Serial.println("NOTHING, LED OFF");
  }
}

Giải thích source code

  • Lệnh const int buttonPin = 2 khai báo chân số 2 được kết nối với nút nhấn, từ khóa const để chỉ rằng đây là 1 biến không thể thay đổi, thường thì nó được dùng để định nghĩa các chân kết nối hoặc các biến mà người dùng không muốn thay đổi giá trị của biến đó trong chương trình.

  • Lệnh Serial.begin(115200) nhằm khởi tạo giao tiếp Serial của vi điều khiển, giá trị 115200 là tốc độ truyền nhận dữ liệu.

  • Lệnh Serial.println("init serial") Nhằm in ra chữ init serial trên Serial monitor của Arduino IDE. Chúng ta sẽ tìm hiểu kĩ hơn về giao tiếp Serial ở chương tiếp theo [USB_Serial_communication]

Kết quả

  • Khi nhấn nút thì LED sẽ sáng. Khi không nhấn nút ra thì LED sẽ tắt.

  • Trên Serial monitor hiện ra dòng chữ HIGH khi nhấn nút và LOW khi không nhấn nút.

press button result
Hình 4. Hình ảnh trên Serial terminal của Arduino IDE

Chớp, tắt LED và chống dội phím khi nhấn (switch debouncing)

Một số board mạch khác, khi dùng nút nhấn, chúng ta nhận thấy có vài lần chương trình in ra dòng chữ “PRESSED, LED ON” và “NOTHING, LED OFF” xen kẽ nhau như khung màu vàng ở hình bên trên, nguyên nhân của hiện tượng này được giải thích như sau:

  • Nút nhấn là 1 linh kiện cơ khí, tại thời điểm bắt đầu nhấn nút, các tiếp điểm cơ khí tiếp xúc với nhau tạo ra sự nhiễu điện áp. Mặc dù chúng ta đã nhấn nút, tuy nhiên khi tiến hành đọc trạng thái của chân kết nối với nút nhấn, giá trị điện áp có lúc HIGH, có lúc LOW. Hiện tượng này được gọi là SWITCH BOUNCING.

  • Hiện tượng này diễn ra rất nhanh và mắt thường không nhìn thấy được, tuy nhiên vi điều khiển có tốc độ xử lí lệnh rất nhanh, nếu sử dụng serial terminal ta có thể thấy kết quả của hiện tượng này. Ngoài ra, chúng ta có thế sử dụng máy Oscilloscope để thấy rõ kết quả thực tế:

switch boucing
Hình 5. Một kết quả đo trên máy Oscilloscope mô tả hiện hiện Switch boucing(Nguồn www.pololu.com)
Nếu không khắc phục hiện tượng này, nó có thể làm hỏng chương trình của bạn.

Có 2 phương pháp để khắc phục tình trạng này đó là:

  • Sử dụng bằng phần cứng: Mắc thêm tụ điện song song với nút nhấn. Bình thường, tụ điện được nối với VCC và GND nên ở trạng thái tích lũy năng lượng (charge). Khi nhấn nút, tụ điện sẽ chuyển sang chế độ giải phóng năng lượng (discharge), giá trị điện áp tại chân kết nối với nút nhấn sẽ giảm 1 cách từ từ xuống 0V, việc làm chậm quá trình giảm điện áp này sẽ ngăn ngừa hiện tượng switch bouncing.

  • Sử dụng bằng phần mềm: Cũng dựa trên cách tạo 1 thời gian trễ nhất định (delay) đồng thời kiểm tra trạng thái trước đó của nút nhấn để có kết quả chính xác. Source code khi sử dụng phần mềm mô tả như bên dưới:

const int buttonPin = 2;  //  Chân kết nối với nút nhấn
const int ledPin =  13;    //  Chân kết nối với LED
int ledState = LOW;          //  Biến lưu trạng thái hiện tại của chân kết nối đến LED
int buttonState;              //  Biến lưu trạng thái hiện của nút nhấn
int lastButtonState = LOW;   //  Biến lưu trạng thái trước đó của nút nhấn.

unsigned long lastDebounceTime = 0; //  Biến lưu thời gian delay chống dội phím ở lần cuối cùng.
unsigned long debounceDelay = 50;   //  Thời gian delay để chống dội phím nhấn

void setup()
{
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  digitalWrite(ledPin, ledState);
}

void loop()
{
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  digitalWrite(ledPin, ledState);

  lastButtonState = reading;
  }

Work flow của chương trình

Biến reading đọc trạng thái của button ở thời điểm hiện tại và kiểm tra, nếu giá trị này khác trạng thái cuối của button (Giá trị thiết lập ban đầu là LOW – không nhấn), có nghĩa là chúng ta đã nhấn nút thì chương trình bắt đầu đếm thời gian chống dội phím . Nếu thời gian lớn hơn giá trị đã cài đặt, chương trình sẽ kiểm tra lại 1 lần nữa trạng thái của nút nhấn, nếu nó vẫn giữ nguyên và không thay đổi (button vẫn đang được nhấn) thì sẽ :

  • Gán biến trạng thái của nút nhấn bằng biến reading.

  • Đảo trạng thái LED nếu button được nhấn (mức HIGH).

Sau đó, điều khiển LED sáng bằng lệnh digitalWrite(), gán giá trị trạng thái nút nhấn bằng với biến reading để kiểm tra cho những vòng lặp sau. Như vậy, cứ mỗi lần nhấn nút và LED sẽ thay đổi trạng thái.

Sử dụng ngắt (interrupt) để điểu khiển LED,

Trong 2 ví dụ trước, chúng ta sử dụng nút nhấn để điều khiển LED trên board với cách thức hỏi vòng (polling), nghĩa là vi điều khiển sẽ kiểm tra liên tục trạng thái của nút nhấn trong vòng lặp loop, cách này thường chiếm dụng nhiều tài nguyên của CPU đồng thời độ đáp ứng của chương trình cũng không nhanh bằng cách sử dụng ngắt (interrupt).

Chip Atmage328P có 2 ngắt trên các chân D2 và D3. Nếu bạn muốn sử dụng chức năng ngắt cho các chân khác thì phải cài đặt thêm 1 số lệnh nữa, vấn đề này tương đối phức tạp và chúng ta không đề cập ở đây.

Yêu cầu

Nhấn button thì đèn LED sẽ đảo trạng thái (nếu LED đang sáng thì sẽ tắt và ngược lại).

Đấu nối

Sơ đồ đấu nối tương tự như ví dụ trên

buttonPin

Source code

int ledPin = 13;     //  Chân kết nối với LED
int btnPin = 2;     //  Chấn có chức năng interrupt trên board
int ledState = LOW; //  Gán trạng thái LED ban đầu là LOW

void blink()
{
  if (ledState == LOW) {
    ledState = HIGH;
  } else {
    ledState = LOW;
  }

  digitalWrite(ledPin, ledState);
}

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(btnPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(btnPin), blink, RISING);
}

void loop()
{
  // Không phải làm gì
}

Giải thích chương trình

Lệnh attachInterrupt() bao gồm 3 đối số:

  • Lệnh digitalPinToInterrupt(btnPin): Chuyển chân digital hiện tại sang chức năng ngắt.

  • Blink(): Làm sẽ được gọi khi có sự kiện ngắt xảy ra.

  • FALLING: Phát hiện ngắt xảy ra nếu có 1 xung cạnh xuống ở chân ngắt. Đây là 1 trong các chế độ (mode) phát hiện có ngắt xảy ra, các mode là : LOW, RISING, FALLING, HIGH.

Chúng ta sẽ tìm hiểu sâu hơn về interrupt tại phần [timer-interrupt]

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *