按鈕與Debounce問題
一、我們都一樣
剛開始接觸物聯網時,都會遇到按照老師的操作,做得一模一樣,但是....怎麼動作與預期中的不一樣
尤其是按鈕:明明按下要亮,卻按了一兩次才做動一次正常...
其實是這樣的,這就是按鈕的bounce,當我們按鈕按下的時候,其實是數位訊號讀取了幾十次,會建議在序列埠當中加一個counter,然後把它列印出來....
您會發現counter列印出來的數字,每次您按下按鍵時候,不是每次都加一,可能是加了十或加了幾百...
您看照片,當按鈕按下的時候其實一直在跑...
資料來源:https://iscixin.github.io/freakhq/push-button/
const byte swPin = 2;
const byte ledPin = 13;
boolean ledState = LOW;
int counter = 0;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(swPin, INPUT_PULLUP);
digitalWrite(ledPin, ledState);
}
void loop() {
boolean swState = digitalRead(swPin);
if (swState == LOW) {
ledState = !ledState;
digitalWrite(ledPin, ledState);
Serial.print("LOW count:");
Serial.println(counter);
counter++;
}
}
二、以polling方式來解決bounce
所以先講解決之道吧
設定一個狀態的flag加delay秒數約50毫秒或100毫秒...
曾希哲老師的大作上是這樣建議的
延遲100毫秒
按鈕接的時候,會建議於按鈕迴路加上10K歐姆的電阻,不然有很多雜訊讓電路訊號不穩定
Arduino電路中,電阻通常接在正訊號端
這是Arduino的程式,在7697上的應用也是一樣的
資料來源:https://i0.wp.com/www.lazytomatolab.com/wp-content/uploads/Arduino-SpeedUp-Class-8.138.jpeg?resize=1024%2C576&ssl=1
三、主動式外部中斷方式
山姆老師教得蠻清楚的...
完整程式碼:
#include "Arduino.h"
int ledPin = 13; // assign LED pin to number 13
int digitalPin = 2; // assign digital pin to number 2
bool bLedState = LOW; // initial LED state to LOW level
bool bBottonUP = true; // initial bottonUP flag
bool bHasINT0 = false; // initial INT0 flag
void setup()
{
pinMode(ledPin, OUTPUT); // initial LED pin to OUTPUT mode
pinMode(digitalPin, INPUT); // initial digital pin to INPUT mode
digitalWrite(ledPin, bLedState); // setup LED state according to ledState
Serial.begin(9600);
while (!Serial){
; // wait for serial port to connect
}
Serial.println("Hello INT0");
// config INT0 falling edge trigger (10) to generate interrupt by set EICRA
EICRA |= _BV(ISC01);
EICRA &= ~_BV(ISC00);
// Enable INT0 interrupt by set EIMSK
EIMSK |= _BV(INT0);
}
void loop()
{
// read digital pin2 state and check bBottonUP
// if ( digitalRead(digitalPin) == LOW && bBottonUP == true )
if ( bHasINT0 && bBottonUP == true )
{
bLedState = ! bLedState; // reverse LED state
digitalWrite(ledPin, bLedState); // setup LED state according to ledState
bBottonUP = false;
delay(50);
}
// else if (digitalRead(digitalPin)== HIGH && bBottonUP == false)
else if (bHasINT0 && bBottonUP == false)
{
// Serial.println("re-enable INT0");
bBottonUP = true;
bHasINT0 = false;
// Re-enable INT0 interrupt by set EIMSK
EIMSK |= _BV(INT0);
}
}
ISR(INT0_vect)
{
EIMSK &= ~_BV(INT0); // disable INT0
bHasINT0 = true; // Set flag
}