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:
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:
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:
Đ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.
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óaconst
để 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.
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ế:
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
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
???
Top comments (0)