Bài 9: Nhấn giữ button để hoán vị trạng thái của LED - Debounce

Nội dung chính, cần nắm

Bạn hãy thử cách giải quyết vấn đề này thử xem:

Tôi muốn sử dụng 2 button để điều khiển trạng thái 3 đèn LED.

  1. Khi nhấn button 1 thì hoán vị trạng thái bật - tắt của đèn LED 1
  2. Khi nhấn button 2 thì hoán vị trạng thái bật - tắt của đèn LED 2
  3. Khi nhấn cả 2 button thì hoán vị tráng thái bật - tắt của đèn LED 3

Bây giờ, nếu đơn thuần bạn chỉ dùng hàm if để so sánh điều kiện thì tôi chắc chắn một điều rằng bạn sẽ làm các đèn LED sáng liên tục devil!

Hôm nay, chúng ta tìm cách để làm được điều đó. Đầu tiên là với 1 button và sau đó là nhiều button (bằng vòng lặp for).

Bài này mang tính chất tham khảo nhiều hơn là thực hành, khi thực hành cho các sản phẩm của bạn, bạn nên sử dụng các thư viện về button có sẵn để code đẹp hơn và dễ hiểu hơn! Nếu bạn muốn debounce một cách dễ dàng hơn, đồng thời xem rõ nghĩa về debounce, xin hãy đọc bài này, Debounce cho nút nhấn bằng tụ điện

Phần cứng

PHẦN 1: Điều khiển việc hoán vị trạng thái bật-tắt của 1 đèn LED bởi 1 button

Lắp mạch

Lập trình và hướng dẫn

Trước tiên, bạn cần biết rằng, chúng ta sẽ định nghĩa việc nhấn button là như thế nào!  Đó là việc chúng ta nhấn button, sau đó trong một khoảng thời gian (khoảng vài trăm mili giây hoặc hơn - tùy ý của bạn) bạn vẫn nhấn, sau đó bạn kiểm tra lại lần nữa, nếu button vẫn được nhấn và giữa quá trình 2 lần nhấn ấy bạn không thả ra thì đó là sự kiện nhấn giữ. Bây giờ chúng ta cùng xem code để hiểu rõ hơn nhé. Đôi khi lời nói còn khó hiểu hơn cả những dòng code xinh đẹp devil.

int led = 11; // Biến khai báo chân đèn LED được nối vào Arduino
int button = 8; // Biến khai báo chân của button

unsigned long waitTime = 500; // Bạn cần nhấn giữ 500 mili giây để hệ thống xem đó là một sự kiến nhấn giữ.

boolean ledStatus = 0; // tương tự với LOW - mặc định đèn sẽ tắt

boolean lastButtonStatus = 0; //Biến dùng để lưu trạng thái của phím bấm. Mặc định là 0 <=> LOW <=> chưa nhấn
boolean buttonLongPress = 0; // Mặc định là không có sự kiện nhấn giữ.

unsigned long lastChangedTime;

void setup() {
  pinMode(led,OUTPUT);   // Đặt chân LED là OUTPUT - hiển nhiên rồi
  pinMode(button,INPUT); // Đặt chân button là INPUT - hiển nhiên rồi
  
  digitalWrite(led,ledStatus); //Xuất trạng thái mặc định
  
  Serial.begin(9600); //Bật Serial để debug
  Serial.println("Bat dau");
}

void loop() {
  boolean reading = digitalRead(button); // đọc giá trị của button
  if (reading != lastButtonStatus) { // Nếu bạn đang nhấn button rồi thả ra giữa chừng hoặc đang thả button rồi nhấn lại 
                                     // thì ta cần phải cập nhập lại thời gian thay đổi cuối cùng
        
    lastButtonStatus = reading; //Cập nhập trạng thái cuối cùng.
    lastChangedTime = millis(); //Cập nhập thời gian
    
    
    
    Serial.print("Thay doi trang thai cua Button luc : ");
    Serial.print(lastChangedTime);
    Serial.print(". Bay gio trang thai la : ");
    Serial.println(lastButtonStatus);
  } // Còn nếu bạn đang nhấn giữ button hoặc thả nó thời gian dài chỉ sẽ không ảnh hưởng đến việc này
  
  if (millis() - lastChangedTime > waitTime) { // Nếu sự chênh lệch giữa thời điểm đang xét và thời điểm cuối cùng thay đổi trạng thái của button lớn hơn thời gian đợi để tạo sự kiện nhấn giữ THÌ nó là một sự kiến nhấn giữ
    buttonLongPress = reading; // Cập nhập trạng thái của button = với trạng thái của button
    lastChangedTime = millis();
    Serial.print("Xay ra su kien nhan giu: ");
    Serial.println(buttonLongPress);
    
  }
  
  if (buttonLongPress == true) { // Nếu có sự kiện nhấn giữ, ta thay đổi trạng thái của đèn LED
    ledStatus = !ledStatus; //Dấu ! là dấu phủ định, 0 thành 1, 1 thành 0, tắt thành sáng, sáng thành tắt
    buttonLongPress = false; // Kết thúc sự kiện nhấn giữ
  }
  digitalWrite(led,ledStatus); // Xuất giá trị của đèn LED ra đèn LED
}

PHẦN 2: Điều khiển việc hoán vị trạng thái bật-tắt của 3 đèn LED bởi 2 button

Đây sẽ là gợi ý cho bạn để sau này bạn sẽ làm được nhiều phím nhấn giữ hơn!

Lắp mạch

Lập trình

int led[3] = {11,12,13}; // Biến khai báo chân đèn LED được nối vào Arduino
int button[2] = {9,2}; // Biến khai báo chân của button

unsigned long waitTime = 500; // Bạn cần nhấn giữ 500 mili giây để hệ thống xem đó là một sự kiến nhấn giữ.

boolean ledStatus[3] = {0,0,0}; // tương tự với LOW - mặc định đèn sẽ tắt
boolean reading[2] = {} ;//Biến dùng để lưu trạng thái thời gian thực của các button 
boolean lastButtonStatus[2] = {0,0}; //Biến dùng để lưu trạng thái của phím bấm. Mặc định là 0 <=> LOW <=> chưa nhấn
boolean buttonLongPress[2] = {0,0}; // Mặc định là không có sự kiện nhấn giữ.

int buttonLongPressTimes[2] = {0,0}; //Biến dùng để lưu số lượng sự kiện nhấn giữ button của bạn.

unsigned long lastChangedTime[2];

void setup() {
  for (int i = 0;i < sizeof(led) / sizeof(int); i++) {//Xem hàm sizeof tại http://arduino.vn/reference/sizeof
    pinMode(led[i],OUTPUT);   // Đặt chân LED là OUTPUT - hiển nhiên rồi
    digitalWrite(led[i],ledStatus[i]); //Xuất trạng thái mặc định
  }
  for (int i = 0;i < sizeof(button) / sizeof(int); i++)
    pinMode(button[i],INPUT); // Đặt chân button là INPUT - hiển nhiên rồi
  
}

void loop() {
  /**
    
  **/
  for (int i = 0;i < sizeof(button) / sizeof(int); i++) {
    reading[i] = digitalRead(button[i]); // đọc giá trị của button
    if (reading[i] != lastButtonStatus[i]) { // Nếu bạn đang nhấn button rồi thả ra giữa chừng hoặc đang thả button rồi nhấn lại 
                                       // thì ta cần phải cập nhập lại thời gian thay đổi cuối cùng
      if (reading[i] == LOW) buttonLongPress[i] = false;
      lastButtonStatus[i] = reading[i]; //Cập nhập trạng thái cuối cùng.
      lastChangedTime[i] = millis(); //Cập nhập thời gian
    } // Còn nếu bạn đang nhấn giữ button hoặc thả nó thời gian dài chỉ sẽ không ảnh hưởng đến việc này
  
    if (millis() - lastChangedTime[i] > waitTime) { // Nếu sự chênh lệch giữa thời điểm đang xét và thời điểm cuối cùng thay đổi trạng thái của button lớn hơn thời gian đợi để tạo sự kiện nhấn giữ THÌ nó là một sự kiến nhấn giữ
      if (buttonLongPress[i] != reading[i]) {
        buttonLongPressTimes[i] = 1;
      } else {
        buttonLongPressTimes[i]++;
      }
      buttonLongPress[i] = reading[i]; // Cập nhập trạng thái của button = với trạng thái của button
      lastChangedTime[i] = millis();
    }
  }

  for (int i = 0;i < sizeof(button) / sizeof(int); i++) {
    if (buttonLongPress[i] == true && buttonLongPressTimes[i] == 1) { // Nếu có sự kiện nhấn giữ và đó là lần đầu tiên, ta thay đổi trạng thái của đèn LED. Lúc này ta không cần phải loại bỏ sự kiện này nữa. Tạo điều kiện cho việc nhấn giữ tổ hợp phím
      ledStatus[i] = !ledStatus[i]; //Dấu ! là dấu phủ định, 0 thành 1, 1 thành 0, tắt thành sáng, sáng thành tắt
      buttonLongPressTimes[i]++; // Tránh trường hợp thay đổi 2 lần
    }
    digitalWrite(led[i],ledStatus[i]); // Xuất giá trị của đèn LED ra đèn LED
  }
  
  //LED thứ 3 (digital 13)
  if (buttonLongPress[0] == true && buttonLongPress[1] == true && buttonLongPressTimes[1] == 2) { //Tại sao lại bằng 2? Bởi vì ở trên chúng ta đã cho nó ==1 và khi thực thiện lệnh thì times được tăng lên 2 nên bây giờ ta phải ==2
    ledStatus[2] = !ledStatus[2];
    buttonLongPressTimes[1]++;
  }
  digitalWrite(led[2],ledStatus[2]);
}

 

lên
19 thành viên đã đánh giá bài viết này hữu ích.
Các dự án được truyền cảm hứng

Select any filter and click on Apply to see results

Các bài viết cùng tác giả

Kết nối điều khiển từ xa sử dụng ESP8266 và Arduino với hệ thống firmware iNut Cảm biến CloudMQTT - 1000 firmware miễn phí

Chuyện kể rằng, có 02 sinh viên Việt Nam, trong lúc làm đồ án đại học kết nối điều khiển từ xa qua Internet. Một người thì chọn phương án truyền thống sử dụng máy tính làm máy chủ và demo các tính năng theo yêu cầu đồ án. Người còn lại biết đến iNut Sensor và tìm cách tối ưu hóa phần mềm và phần cứng nhằm chau chuốt cho đồ án của mình trở nên "xịn" và "nhiều tính năng bá đạo". Đến lúc bảo vệ đồ án, cậu sinh viên 01 cảm thấy choáng ván với muôn vàn vấn đề từ việc nơi trình bày đồ án không có wifi, mạng chập chờn, máy tính mở không lên, đứt cáp biển,... Cuối cùng cũng bảo vệ được với điểm số không ưng ý lắm dù tốn rất nhiều thời gian và công sức. Cậu còn lại nhờ vào việc chau chuốt phần mềm, tối ưu hóa và comment kĩ từng lệnh trong dòng code, viết báo cáo bài bản chuẩn bị slide như ý, dùng điện thoại cài wifi, quét mã QRcode để chia sẻ quyền truy cập đến phần mềm rất chuyên nghiệp, mọi thứ cậu chủ động hoàn toàn mà không bị các vấn đề "học tài thi phận" bủa vây mà kết quả hết sức mĩ mãn, điểm số mĩ miều, kiến thức IoT được chuẩn hóa. Thực vậy, các dự án, đồ án sử dụng nền tảng iNut Platform bên dưới cho phép các bạn sinh viên làm các dự án hết sức hoàn hảo: từ xe điều khiển, bãi giữ xe thông minh, hệ thống máy lạnh, máy bơm, điều hòa thông minh,... do chinh các bạn tự làm nên đã đạt được những điểm số tốt và tuyệt đối. Cũng chính vì thế, iNut JSC (công ty chủ quản của iNut Platform) đã kết hợp với Khu Công nghệ phần mềm - ĐHQGHCM để tổ chức những khóa đào tạo ngắn hạn cho sinh viên Việt Nam sử dụng nền tảng IoT do iNut JSC phát triển. Và để mở con đường tri thức tiếp cận IoT trong nháy mắt, iNut JSC đã tạo ra một phiên bản firmware trị giá 50.000 đồng sử dụng clouding của CloudMQTT và tài trợ 1000 firmware cho tất cả các bạn học sinh, sinh viên Việt Nam có thể tiếp cận IoT một cách dễ dàng và nhanh chóng nhất!

lên
14 thành viên đã đánh giá bài viết này hữu ích.

true

true là một hằng logic. Bạn cũng có thể HIỂU true là một hằng số nguyên mang giá trị là 1. Trong các biểu thức logic, một hằng số hay giá trị của một biểu thức khác 0 được xem như là mang giá trị true

lên
4 thành viên đã đánh giá bài viết này hữu ích.