Arduino Nút Nhấn giữ và Nhấn ngắn

Chúng ta sẽ học:

Trong ba phần đầu tiên, chúng ta học cách phát hiện về nguyên lý.

Trong phần cuối, chúng ta học cách nhận diện trong thực tế bằng cách áp dụng kỹ thuật debounce. Xem Arduino - Nút nhấn - Khử rung. Nếu không có kỹ thuật debounce, chúng ta có thể nhận diện sai nhấn nút ngắn.

Phần cứng cần chuẩn bị

1×Arduino Uno R3
1×USB 2.0 cable type A/B (for USB-A PC)
1×USB 2.0 cable type C/B (for USB-C PC)
1×breadboard-mount Button with Cap
1×breadboard-mount Button Kit
1×Panel-mount Push Button
1×mô-đun nút nhấn
1×breadboard
1×dây jumper
1×(Khuyến nghị) Screw Terminal Block Shield for Arduino Uno
1×(Khuyến nghị) Breadboard Shield for Arduino Uno
1×(Khuyến nghị) Enclosure for Arduino Uno
1×(Khuyến nghị) Prototyping Base Plate & Breadboard Kit for Arduino UNO

Or you can buy the following kits:

1×DIYables STEM V3 Starter Kit (Arduino included)
1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)

Về Nút

Nếu bạn chưa biết về nút (bố trí chân, cách nó hoạt động, cách lập trình ...), hãy tìm hiểu về chúng trong các bài hướng dẫn sau:

Sơ đồ đấu dây

sơ đồ đấu dây nút Arduino

This image is created using Fritzing. Click to enlarge image

Trong bài hướng dẫn này, chúng ta sẽ sử dụng điện trở kéo lên nội bộ. Do đó, trạng thái của nút là HIGH khi ở mức bình thường và LOW khi được nhấn.

Cách Phát Hiện Nhấn Ngắn

Chúng tôi đo thời gian giữa sự nhấn và sự thả. Nếu thời lượng này ngắn hơn một khoảng thời gian được định trước, sự nhấn ngắn được phát hiện.

Hãy xem xét từng bước một:

  • Xác định thời gian tối đa mà một lần nhấn ngắn kéo dài.
const int SHORT_PRESS_TIME = 500; // 500 milliseconds
  • Phát hiện khi nút được nhấn và lưu thời điểm nhấn nút
if(lastState == HIGH && currentState == LOW) pressedTime = millis();
  • Phát hiện nút được thả và lưu thời điểm thả.
if(lastState == LOW && currentState == HIGH) releasedTime = millis();
  • Tính thời gian giữ nút và
long pressDuration = releasedTime - pressedTime;
  • Xác định nhấn ngắn bằng cách so sánh thời gian nhấn với thời gian nhấn ngắn được định nghĩa.
if( pressDuration < SHORT_PRESS_TIME ) Serial.println("A short press is detected");

Mã Arduino để phát hiện nhấn ngắn

/* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/arduino/arduino-button-long-press-short-press */ // constants won't change. They're used here to set pin numbers: const int BUTTON_PIN = 7; // the number of the pushbutton pin const int SHORT_PRESS_TIME = 500; // 500 milliseconds // Variables will change: int lastState = LOW; // the previous state from the input pin int currentState; // the current reading from the input pin unsigned long pressedTime = 0; unsigned long releasedTime = 0; void setup() { Serial.begin(9600); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { // read the state of the switch/button: currentState = digitalRead(BUTTON_PIN); if(lastState == HIGH && currentState == LOW) // button is pressed pressedTime = millis(); else if(lastState == LOW && currentState == HIGH) { // button is released releasedTime = millis(); long pressDuration = releasedTime - pressedTime; if( pressDuration < SHORT_PRESS_TIME ) Serial.println("A short press is detected"); } // save the the last state lastState = currentState; }

Hướng dẫn từng bước

  • Tải mã ở trên lên Arduino bằng Arduino IDE
  • Nhấn nút nhanh vài lần.
  • Xem kết quả trên Serial Monitor
COM6
Send
A short press is detected
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

※ Lưu ý:

Serial Monitor có thể hiển thị nhiều lần phát hiện nhấn ngắn cho một lần nhấn. Đây là hành vi bình thường của nút. Hành vi này được gọi là “hiện tượng giật”. Vấn đề sẽ được giải quyết ở phần cuối của bài hướng dẫn này.

Cách nhận diện nhấn giữ

Có hai trường hợp sử dụng để phát hiện nhấn giữ.

  • Sự kiện nhấn và giữ lâu được phát hiện ngay sau khi nút được nhả ra
  • Sự kiện nhấn và giữ lâu được phát hiện trong suốt thời gian nút đang được nhấn, ngay cả khi nút chưa được thả

Trong trường hợp sử dụng đầu tiên, chúng tôi đo thời lượng giữa sự kiện nhấn và thả. Nếu thời lượng dài hơn một khoảng thời gian được xác định, sự kiện nhấn giữ (long-press) được phát hiện.

Trong trường hợp sử dụng thứ hai, sau khi nhấn nút, chúng tôi liên tục đo thời gian nhấn và kiểm tra sự kiện nhấn giữ cho đến khi nút được thả. Trong suốt thời gian nút được nhấn, nếu thời lượng vượt quá một khoảng thời gian đã xác định trước, sự kiện nhấn giữ sẽ được phát hiện.

Mã Arduino để phát hiện nhấn giữ lâu khi được thả

/* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/arduino/arduino-button-long-press-short-press */ // constants won't change. They're used here to set pin numbers: const int BUTTON_PIN = 7; // the number of the pushbutton pin const int LONG_PRESS_TIME = 1000; // 1000 milliseconds // Variables will change: int lastState = LOW; // the previous state from the input pin int currentState; // the current reading from the input pin unsigned long pressedTime = 0; unsigned long releasedTime = 0; void setup() { Serial.begin(9600); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { // read the state of the switch/button: currentState = digitalRead(BUTTON_PIN); if(lastState == HIGH && currentState == LOW) // button is pressed pressedTime = millis(); else if(lastState == LOW && currentState == HIGH) { // button is released releasedTime = millis(); long pressDuration = releasedTime - pressedTime; if( pressDuration > LONG_PRESS_TIME ) Serial.println("A long press is detected"); } // save the the last state lastState = currentState; }

Hướng dẫn từng bước

  • Tải mã ở trên lên Arduino thông qua Arduino IDE
  • Nhấn và thả nút sau một giây.
  • Xem kết quả trên Serial Monitor
COM6
Send
A long press is detected
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

Sự kiện nhấn giữ chỉ được phát hiện ngay sau khi nút được thả.

Mã Arduino để phát hiện nhấn giữ lâu trong quá trình nhấn

/* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/arduino/arduino-button-long-press-short-press */ // constants won't change. They're used here to set pin numbers: const int BUTTON_PIN = 7; // the number of the pushbutton pin const int LONG_PRESS_TIME = 1000; // 1000 milliseconds // Variables will change: int lastState = LOW; // the previous state from the input pin int currentState; // the current reading from the input pin unsigned long pressedTime = 0; bool isPressing = false; bool isLongDetected = false; void setup() { Serial.begin(9600); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { // read the state of the switch/button: currentState = digitalRead(BUTTON_PIN); if(lastState == HIGH && currentState == LOW) { // button is pressed pressedTime = millis(); isPressing = true; isLongDetected = false; } else if(lastState == LOW && currentState == HIGH) { // button is released isPressing = false; } if(isPressing == true && isLongDetected == false) { long pressDuration = millis() - pressedTime; if( pressDuration > LONG_PRESS_TIME ) { Serial.println("A long press is detected"); isLongDetected = true; } } // save the the last state lastState = currentState; }

Hướng dẫn từng bước

  • Tải mã ở trên lên Arduino bằng Arduino IDE
  • Nhấn và thả nút sau vài giây.
  • Xem kết quả trên Serial Monitor
COM6
Send
A long press is detected
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

Sự kiện nhấn giữ chỉ được phát hiện khi nút chưa được thả.

Cách Nhận Diện Cả Nhấn Giữ và Nhấn Nhanh

Nhấn ngắn và nhấn giữ sau khi thả

/* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/arduino/arduino-button-long-press-short-press */ // constants won't change. They're used here to set pin numbers: const int BUTTON_PIN = 7; // the number of the pushbutton pin const int SHORT_PRESS_TIME = 1000; // 1000 milliseconds const int LONG_PRESS_TIME = 1000; // 1000 milliseconds // Variables will change: int lastState = LOW; // the previous state from the input pin int currentState; // the current reading from the input pin unsigned long pressedTime = 0; unsigned long releasedTime = 0; void setup() { Serial.begin(9600); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { // read the state of the switch/button: currentState = digitalRead(BUTTON_PIN); if(lastState == HIGH && currentState == LOW) // button is pressed pressedTime = millis(); else if(lastState == LOW && currentState == HIGH) { // button is released releasedTime = millis(); long pressDuration = releasedTime - pressedTime; if( pressDuration < SHORT_PRESS_TIME ) Serial.println("A short press is detected"); if( pressDuration > LONG_PRESS_TIME ) Serial.println("A long press is detected"); } // save the the last state lastState = currentState; }

Hướng dẫn từng bước

  • Tải mã ở trên lên Arduino bằng Arduino IDE
  • Nhấn nút lâu và ngắn.
  • Xem kết quả trên Trình theo dõi Serial

※ Lưu ý:

Serial Monitor có thể hiển thị nhiều lần phát hiện nhấn ngắn khi nhấn giữ lâu. Đây là hành vi bình thường của nút nhấn. Hành vi này được gọi là “hiện tượng chattering”. Vấn đề sẽ được giải quyết ở phần cuối của bài hướng dẫn này.

Nhấn ngắn và nhấn giữ trong quá trình nhấn

/* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/arduino/arduino-button-long-press-short-press */ // constants won't change. They're used here to set pin numbers: const int BUTTON_PIN = 7; // the number of the pushbutton pin const int SHORT_PRESS_TIME = 1000; // 1000 milliseconds const int LONG_PRESS_TIME = 1000; // 1000 milliseconds // Variables will change: int lastState = LOW; // the previous state from the input pin int currentState; // the current reading from the input pin unsigned long pressedTime = 0; unsigned long releasedTime = 0; bool isPressing = false; bool isLongDetected = false; void setup() { Serial.begin(9600); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { // read the state of the switch/button: currentState = digitalRead(BUTTON_PIN); if(lastState == HIGH && currentState == LOW) { // button is pressed pressedTime = millis(); isPressing = true; isLongDetected = false; } else if(lastState == LOW && currentState == HIGH) { // button is released isPressing = false; releasedTime = millis(); long pressDuration = releasedTime - pressedTime; if( pressDuration < SHORT_PRESS_TIME ) Serial.println("A short press is detected"); } if(isPressing == true && isLongDetected == false) { long pressDuration = millis() - pressedTime; if( pressDuration > LONG_PRESS_TIME ) { Serial.println("A long press is detected"); isLongDetected = true; } } // save the the last state lastState = currentState; }

Hướng dẫn từng bước

  • Tải mã ở trên lên Arduino bằng Arduino IDE
  • Nhấn nút lâu và nhấn nút ngắn.
  • Xem kết quả trên Serial Monitor

※ Lưu ý:

Màn hình Serial Monitor có thể hiển thị một vài lần phát hiện nhấn ngắn khi nhấn giữ lâu. Đây là hành vi bình thường của nút. Hành vi này được gọi là “hiện tượng bật nảy”. Vấn đề sẽ được giải quyết ở phần cuối của bài hướng dẫn này.

Nhấn giữ lâu và nhấn ngắn với khử nhiễu

Việc khử nhiễu cho nút (debounce) là rất quan trọng trong nhiều ứng dụng.

Việc lọc nhiễu tiếp xúc (debouncing) khá phức tạp, đặc biệt khi sử dụng nhiều nút. Để giúp người mới bắt đầu dễ dàng hơn rất nhiều, chúng tôi đã tạo ra một thư viện có tên ezButton.

Chúng tôi sẽ sử dụng thư viện này trong các mã dưới đây.

Nhấn ngắn và nhấn dài với lọc nhiễu sau khi nhả nút

/* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/arduino/arduino-button-long-press-short-press */ #include <ezButton.h> const int SHORT_PRESS_TIME = 1000; // 1000 milliseconds const int LONG_PRESS_TIME = 1000; // 1000 milliseconds ezButton button(7); // create ezButton object that attach to pin 7; unsigned long pressedTime = 0; unsigned long releasedTime = 0; void setup() { Serial.begin(9600); button.setDebounceTime(50); // set debounce time to 50 milliseconds } void loop() { button.loop(); // MUST call the loop() function first if(button.isPressed()) pressedTime = millis(); if(button.isReleased()) { releasedTime = millis(); long pressDuration = releasedTime - pressedTime; if( pressDuration < SHORT_PRESS_TIME ) Serial.println("A short press is detected"); if( pressDuration > LONG_PRESS_TIME ) Serial.println("A long press is detected"); } }

Hướng dẫn từng bước

  • Cài đặt thư viện ezButton. Xem Cách làm
  • Tải mã ở trên lên Arduino thông qua Arduino IDE
  • Nhấn nút lâu và nhấn nút ngắn
  • Xem kết quả trên Serial Monitor

Nhấn ngắn và nhấn dài với khử nhiễu trong quá trình nhấn

/* * Mã Arduino này được phát triển bởi newbiely.vn * Mã Arduino này được cung cấp để sử dụng công khai, không có ràng buộc. * Để xem hướng dẫn chi tiết và sơ đồ kết nối, vui lòng truy cập: * https://newbiely.vn/tutorials/arduino/arduino-button-long-press-short-press */ #include <ezButton.h> const int SHORT_PRESS_TIME = 1000; // 1000 milliseconds const int LONG_PRESS_TIME = 1000; // 1000 milliseconds ezButton button(7); // create ezButton object that attach to pin 7; unsigned long pressedTime = 0; unsigned long releasedTime = 0; bool isPressing = false; bool isLongDetected = false; void setup() { Serial.begin(9600); button.setDebounceTime(50); // set debounce time to 50 milliseconds } void loop() { button.loop(); // MUST call the loop() function first if(button.isPressed()){ pressedTime = millis(); isPressing = true; isLongDetected = false; } if(button.isReleased()) { isPressing = false; releasedTime = millis(); long pressDuration = releasedTime - pressedTime; if( pressDuration < SHORT_PRESS_TIME ) Serial.println("A short press is detected"); } if(isPressing == true && isLongDetected == false) { long pressDuration = millis() - pressedTime; if( pressDuration > LONG_PRESS_TIME ) { Serial.println("A long press is detected"); isLongDetected = true; } } }

Hướng dẫn từng bước

  • Cài đặt thư viện ezButton. Xem Hướng dẫn
  • Tải mã ở trên lên Arduino bằng IDE Arduino
  • Nhấn nút lâu và nhấn nút ngắn.
  • Xem kết quả trên Serial Monitor

Video Tutorial

Việc sản xuất video tốn rất nhiều thời gian. Nếu video hướng dẫn hữu ích cho việc học của bạn, hãy đăng ký kênh YouTube để ủng hộ. Nếu nhu cầu đủ cao, chúng tôi sẽ cố gắng làm thêm nhiều video.

Tại sao cần nhấn giữ và nhấn ngắn

  • Để giảm số lượng nút. Một nút có thể đảm nhận hai hoặc nhiều chức năng. Ví dụ, nhấn ngắn để đổi chế độ hoạt động, nhấn giữ để tắt thiết bị.
  • Việc nhấn giữ được dùng để giảm việc nhấn ngắn vô tình. Ví dụ, một số loại thiết bị sử dụng nút để khôi phục cài đặt gốc. Nếu nút bị nhấn vô tình, điều này là nguy hiểm. Để tránh điều này, thiết bị được thiết kế để khôi phục cài đặt gốc chỉ khi nút được nhấn giữ (ví dụ trên 5 giây).