Dark
  • thứ hai, 23 tháng 9 2024
Esp8266 Và Nút Nhấn Phần 1: Đọc Trạng Thái - Chống Dội

Esp8266 Và Nút Nhấn Phần 1: Đọc Trạng Thái - Chống Dội

Nút nhấn chắc ai trong chúng ta, những người đam mê điện tử iot, cũng thường xuyên sử dụng trong các dự án của mình. Trong dự án iot 1 cũng có mặt nó, một linh kiện thiết yếu trong mạch điện. Nhìn có vẻ đơn giản, nhưng khi code thì chắc không ít lần gặp rắc rối khi không dễ dàng kiểm soát được nó.  

Trong bài hôm nay mình sẽ chia sẻ cho các bạn mới làm quen với lập trình nhúng, cũng như các bạn đang tìm cách kiểm soát nút nhấn của mình, những cách để có thể khống chế nó bằng module Esp8266 và Arduino IDE.

 

Chân esp8266

 

1. Kết nối và đọc trạng thái nút nhấn

Kết nối

Để đọc được trạng thái nút nhấn thì đầu tiên ta phải khai báo chân dùng để đọc, ở đây chân mình dùng chân GPIO5. Ta khai báo như sau

void setup() {
 pinMode(5,INPUT);// chân 5 là input
}

void loop() {
  // chưa làm gì trong đây cả
}

Với cách khai báo INPUT ta cần kéo trở cố định trạng thái trước khi nhấn nút cho chân đọc. 

Dưới đây mình dùng trở 10k ohm để kéo chân 5 lên cao HIGH (1), có nghĩa là bình thường ta chưa tác động gì đến nút nhấn, thì chân 5 luôn đọc được trạng thái cao HIGH. Nhưng khi ta nhấn nút thì chân 5 sẽ có trạng thái thấp LOW (0), vì chân còn lại của nút nhấn mình đã nối với GND (0V) (dây màu xanh).

image

Còn đây là cách kéo trở xuống thấp, và dĩ nhiên sẽ ngược lại với cách trên. Bình thường chân 5 sẽ có trạng thái LOW, khi nhấn nút thì nó có trạng thái HIGH.

image

Vậy vì sao ta phải kéo trở cho chân đọc, vì với cách khai báo pinMode(5,INPUT) thì chân nó sẽ không có trạng thái cố định. Hay nói cách khác là trạng thái lơ lửng có lúc HIGH có lúc LOW, nên mình không thể nào biết được chính xác lúc nào là nút được nhấn, lúc nào là nó nhiễu. Khiến cho chương trình của mình chạy từa lưa hết lên. 

Có cách nào không kéo trở mà trạng thái chân 5 vẫn cố định không? 
Tất nhiên là có rồi, nhà sản xuất người ta tính hết cả rồi. Để cho mạch được đơn giản thì trong con esp8266 người ta đã gắn sẵn trở cho nó (tất cả các chân GPIO đều có trở kéo lên nguồn, ngoại trừ GPIO16 có trở kéo xuống GND).

Lúc này ta khai báo khác tí: 

void setup() {
 pinMode(5,INPUT_PULLUP);// chân 5 là chân input
}

void loop() {
  // chưa làm gì trong đây cả
}

image

Nói nãy giờ mình vẫn chưa chỉ các bạn hàm đọc nút nhấn là gì, đây đây nó ở dưới đây.

Đọc nút nhấn

void setup() {
 pinMode(5,INPUT_PULLUP);// khai báo chân 5 là input với trở kéo lên
}

void loop() {
  digitalRead(5);// đọc trạng thái chân 5
}

Vậy làm sao để biết chân 5 mình đọc được cái gì. Phải có cái gì để biết chứ, đó chính là nhiệm vụ của Serial (tra google nếu chưa biết Serial là gì nha). Còn ở đây mình chỉ các bạn cách dùng nó để xem esp đang đọc được gì. 

void setup() {
 Serial.begin(115200);// khai báo để sử dụng Serial
 pinMode(5,INPUT_PULLUP);// khai báo chân 5 là chân đọc với trở kéo lên
}

void loop() {
  byte status= digitalRead(5);// đọc trạng thái chân 5
  Serial.println("Button: "+String(status));// in ra man hình serial
 }

Cách bật nó như thế này: kết nối esp với máy tính, chọn cổng com vào Tools -> Port -> chọn COM của esp đang kết nối. Sau đó nhấn vào nút như hình.

image

Chọn tốc độ baud bằng với tốc độ trong Serial.begin(115200) là : 115200

image

Và đây là kết quả khi ta nhấn nút.

image

Và đây là lúc vấn đề bắt đầu có những lúc bạn nhấn nút nhưng trạng thái nó vẫn nhảy 0 1 1 1 0 . Đây là do đặc tính cơ học vật lý của nút nhấn, khi bạn nhấn nút thì hai tiếp điểm của nút nhấn nó tiếp xúc rồi nhả ra nhiều lần trước khi đóng lại hẳn quá trình đó gọi là: chattering. Xem mô tả dưới hình cho dễ hiểu.

image

 

Debounce

Vậy làm sao để đọc được đúng trạng thái nút nhấn? Đây là Debounce phần trọng tâm của ngày hôm nay, đầu tiên các bạn nạp thử code bên dưới và nhấn thử nút xem thế nào. 

// Code chưa debounce
void setup() {
  Serial.begin(115200);// khai báo để sử dụng Serial
  pinMode(5, INPUT_PULLUP); // khai báo chân 5 là chân đọc với trở kéo lên
  Serial.println("Start Up");// In ra khi khởi động
}

void loop() {
  if (digitalRead(5) == LOW) // khi nhấn nút
  {
    Serial.println("Button pressed"); // cái này được in khi nhấn nút
  }
  else
  {
      Serial.println("The button is released"); // cái này được in khi thả ra
  }
}

Kết quả ở đây 

image

Có các cách debounce mà mình hay dùng xin giới thiệu với các bạn để tham khảo.

Debounce bằng delay - while

delay có nhiệm vụ dừng chương trình trong thời gian mili giây. Và cứ mỗi 1000 mili giây = 1 giây.

// Code Debounce nút nhấn dùng while
byte flagButton = 0; // cờ này giúp hiển thị màng hình 1 lần rồi thoi

void setup() {
  Serial.begin(115200);// khai báo để sử dụng Serial
  pinMode(5, INPUT_PULLUP); // khai báo chân 5 là chân đọc với trở kéo lên
  Serial.println("Start Up");
}

void loop() {
  if (digitalRead(5) == LOW) // khi nhấn nút
  {
    delay(50);//dừng chương trình trong 50 mili giây bỏ qua lúc nhiễu
    Serial.println("Button pressed"); // cái này được in khi nhấn nút
    while (digitalRead(5) == LOW); // while chưa thoát khi điều kiện còn đúng
    flagButton = 0;
  }
  else
  {
    if (flagButton == 0) {
      Serial.println("The button is released"); // cái này được in khi thả ra
      flagButton = 1;
    }
  }
}

Các bạn nạp lại thử code bên trên vào và nhấn lại nút xem thế nào.

Kết quả ở đây:

image

Ta thấy khi nhấn nút đã bớt nhiễu hẳn, những khung màu xanh vẫn còn nhiễu một ít. 

Debounce bằng millis() so sánh trạng thái

Trước tiên millis() có nhiệm vụ trả về một số kiểu unsigned long - là thời gian (tính theo mili giây) kể từ lúc mạch esp bắt đầu chương trình của bạn. Nó sẽ tràn số và quay số 0 (sau đó tiếp tục tăng) sau 50 ngày.

// Code Debounce nút nhấn dùng millis()
byte lastState = LOW;  // trạng thái cuối
byte currentState;     // trạng thái hiện tại
byte flagStateChange = HIGH; // cờ thay đổi trạng thái

unsigned long lastDebounceTime = 0;  // biến lưu thời điểm thay dổi trang thái nút

void setup() {
  Serial.begin(115200);// khai báo để sử dụng Serial
  pinMode(4, INPUT_PULLUP); // khai báo chân 4 là chân đọc với trở kéo lên
  Serial.println("Start Up");
}

void loop() {
  // lấy trang thái hiện tại của chân 4, không nhấn là HIGH
  currentState = digitalRead(4);

  // kiểm tra nút có nhấn không
  if (currentState != flagStateChange) {// nếu nút nhấn (currentState=LOW)

    lastDebounceTime = millis();// lấy thời điểm nhấn nút

    flagStateChange = currentState;// đặc lại giá trị cho cờ
  }

  //sau 50ms từ lúc nhấn nút thì chạy vào đây
  if ((millis() - lastDebounceTime) > 50) { // cái này để bỏ qua khoảng nhiễu nhấn nút
    {
      if (lastState == HIGH && currentState == LOW) {// cái này chạy khi nhấn xuống
        Serial.println("The button is pressed");
      }
      else if (lastState == LOW && currentState == HIGH) {// cái này chạy khi buông nút nhấn ra
        Serial.println("The button is released");
      }
      lastState = currentState;//đặt lại trạng thái cuối
    }
  }
}

Kết quả ở đây

image

Ta thấy chương trình đã chạy rất mượt đọc đúng trạng thái của nút nhấn.

Trên đây là 2 cách mình biết về cách xử lý nhiễu nút nhấn. Các bạn còn cách nào khác có thể chia sẻ bên dưới phần bình luận nhá. Tham gia nhóm FB để góp ý, cũng như post các vấn đề của các bạn, bọn mình sẽ cố gắng hổ trợ.

Link: Facebook-hackanidea.net

Bình luận / Trả lời