Viet Dev

Cover image for Arduino - Nút nhấn
Tuan for Unicloud Group

Posted on

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:

Hình ảnh về các loại nút nhấn trong thực<br>
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:

Mạch nguyên lí của nút nhấn không giữ trạng<br>
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:

Hình ảnh sơ đồ kết nối thực<br>
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");
  }
}
Enter fullscreen mode Exit fullscreen mode

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 ???

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.

Hình ảnh trên Serial terminal của Arduino<br>
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ế:

Một kết quả đo trên máy Oscilloscope mô tả hiện hiện Switch<br>
boucing(Nguồn<br>
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;
  }
Enter fullscreen mode Exit fullscreen mode

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ì
}
Enter fullscreen mode Exit fullscreen mode

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
???

Top comments (0)