我用两个按钮写一个简单的草图。为了处理按钮状态,我编写了一个名为changeButtonStatus
的函数(作为参数,我传递一个按钮引脚),它返回一个事件编号:
在主循环中,我为每个按钮调用此功能,并使用Serial.println()
打印出一条消息。
问题是我的草图只能在一个按钮上正常工作,并且它不能与两个或多个按钮一起使用。
这是我的代码:
#include <elapsedMillis.h>
int but1 = 3;
int but2 = 4;
int eventBut1, eventBut2;
int currentButtonStatus = 0; // 0 - button is not pressed
// 1 - button is pressed for the first time
// 2 - button is released after being pressed
// 3 - button is pressed for the second time
unsigned long currentButtonStatusStart1; // number of milliseconds when the status has changed to 1
unsigned long currentButtonStatusStart2; // number of milliseconds when the status has changed to 2
unsigned long currentButtonStatusStart3; // number of milliseconds when the status has changed to 3
const int delayFalse = 30; // if the value is less than 30 milliseconds, one press is not registered
const int delayLongSingleClick = 400; // if the value is greater than 400 milliseconds, long press is reegistered
const int delayDeltaDoubleClick = 300; // delay to registere double clck
void setup() {
pinMode (but1, INPUT);
pinMode (but2, INPUT);
Serial.begin(9600);
}
void loop() {
eventBut1 = changeButtonStatus(but1); // variable to keep the state of but1 (not pressed, single press, double press, long press)
eventBut2 = changeButtonStatus(but2); // variable to keep the state of but2 (not pressed, single press, double press, long press)
if (eventBut1 > 0) {
if (eventBut1 == 1) {Serial.println("But1 Single click");}
if (eventBut1 == 4) {Serial.println("But1 is released after long press");}
}
if (eventBut2 > 0) {
if (eventBut2 == 1) {Serial.println("But2 Single click");}
if (eventBut2 == 2) {Serial.println("But2 Double press");}
}
}
/**
* Change current button status
* @return = 0 - not pressed
* 1 - single click
* 2 - double click
* 3 - long press
* 4 - released after long press
*/
int changeButtonStatus(int butPin) {
// Event
int event = 0;
// Current button status
int currentButtonClick = digitalRead(butPin);
// Current time
unsigned long timeButton = millis();
switch(currentButtonStatus) {
case 0:
// button has not been pressed
if(currentButtonClick) {
// fix button click
currentButtonStatus = 1;
currentButtonStatusStart1 = millis();
} else {
// button is not pressed
}
break;
case 1:
// button is pressed for the first time
if(currentButtonClick) {
// button is still pressed
if(timeButton - currentButtonStatusStart1 >= delayLongSingleClick) {
// button long press state
event = 3;
}
} else {
// button has been released
if(timeButton - currentButtonStatusStart1 < delayFalse) {
currentButtonStatus = 0;
event = 0;
} else if(timeButton - currentButtonStatusStart1 < delayLongSingleClick) {
currentButtonStatus = 2;
currentButtonStatusStart2 = millis();
} else {
// button has been released after long press
currentButtonStatus = 0;
event = 4;
}
}
break;
case 2:
if(currentButtonClick) {
// if the button has been pressed for the second time
// check how long the button has been released
if(timeButton - currentButtonStatusStart2 < delayFalse) {
currentButtonStatus = 1;
} else {
// fix second press
currentButtonStatus = 3;
currentButtonStatusStart3 = millis();
}
} else {
// if the button is still released
// check for the single click
if(timeButton - currentButtonStatusStart2 > delayDeltaDoubleClick) {
// button has been released for too long, fix single click
currentButtonStatus = 0;
event = 1;
}
}
break;
case 3:
// confirm double click
if(currentButtonClick) {
// button is still pressed
// wait for the button to be released
} else {
// button has been released
// check for the debounce
if(timeButton - currentButtonStatusStart3 < delayFalse) {
// button has been released too early, probably it's a debounce
} else {
// fix double click
event = 2;
currentButtonStatus = 0;
}
}
break;
}
return event;
}
如果你能帮助我找出可能存在的问题,我将感激不尽。
答案 0 :(得分:0)
我们可以看到一个问题,你用两个按钮分享一些全局变量:currentButtonStatus, currentButtonStatusStartX ...
。
你不应该在修正中定义另一组这些变量,你应该为按钮创建一个类,并在你的类中包含这些以前的全局变量。
我写过这样的代码,几乎没有变化。 从这一点开始,您可以改进并创建一个枚举,它将替换事件按钮的常量0,1,2,3。
请注意,我已经检查过我的修改编译,但我还没有使用真实按钮进行测试。
//#include <elapsedMillis.h>
int butPin1 = 3;
int butPin2 = 4;
int eventBut1, eventBut2;
class ButtonStat {
static const int delayFalse = 30; // if the value is less than 30 milliseconds, one press is not registered
static const int delayLongSingleClick = 400; // if the value is greater than 400 milliseconds, long press is reegistered
static const int delayDeltaDoubleClick = 300; // delay to registere double clck
public:
explicit ButtonStat(int pinBut): pin(pinBut),currentButtonStatus(0), currentButtonStatusStart1(0),
currentButtonStatusStart2(0), currentButtonStatusStart3(0) {}
int changeButtonStatus();
int getPin() {return pin;}
private:
int pin;
int currentButtonStatus; // 0 - button is not pressed
// 1 - button is pressed for the first time
// 2 - button is released after being pressed
// 3 - button is pressed for the second time
unsigned long currentButtonStatusStart1; // number of milliseconds when the status has changed to 1
unsigned long currentButtonStatusStart2; // number of milliseconds when the status has changed to 2
unsigned long currentButtonStatusStart3; // number of milliseconds when the status has changed to 3
} ;
ButtonStat butt1 = ButtonStat(butPin1);
ButtonStat butt2 = ButtonStat(butPin2);
void setup() {
pinMode (butt1.getPin(), INPUT);
pinMode (butt2.getPin(), INPUT);
Serial.begin(9600);
}
void loop() {
eventBut1 = butt1.changeButtonStatus(); // variable to keep the state of but1 (not pressed, single press, double press, long press)
eventBut2 = butt2.changeButtonStatus(); // variable to keep the state of but2 (not pressed, single press, double press, long press)
if (eventBut1 > 0) {
if (eventBut1 == 1) {Serial.println("But1 Single click");}
if (eventBut1 == 4) {Serial.println("But1 is released after long press");}
}
if (eventBut2 > 0) {
if (eventBut2 == 1) {Serial.println("But2 Single click");}
if (eventBut2 == 2) {Serial.println("But2 Double press");}
}
}
/**
* Change current button status
* @return = 0 - not pressed
* 1 - single click
* 2 - double click
* 3 - long press
* 4 - released after long press
*/
int ButtonStat::changeButtonStatus() {
// Event
int event = 0;
// Current button status
int currentButtonClick = digitalRead(pin);
// Current time
unsigned long timeButton = millis();
switch(currentButtonStatus) {
case 0:
// button has not been pressed
if(currentButtonClick) {
// fix button click
currentButtonStatus = 1;
currentButtonStatusStart1 = millis();
} else {
// button is not pressed
}
break;
case 1:
// button is pressed for the first time
if(currentButtonClick) {
// button is still pressed
if(timeButton - currentButtonStatusStart1 >= delayLongSingleClick) {
// button long press state
event = 3;
}
} else {
// button has been released
if(timeButton - currentButtonStatusStart1 < delayFalse) {
currentButtonStatus = 0;
event = 0;
} else if(timeButton - currentButtonStatusStart1 < delayLongSingleClick) {
currentButtonStatus = 2;
currentButtonStatusStart2 = millis();
} else {
// button has been released after long press
currentButtonStatus = 0;
event = 4;
}
}
break;
case 2:
if(currentButtonClick) {
// if the button has been pressed for the second time
// check how long the button has been released
if(timeButton - currentButtonStatusStart2 < delayFalse) {
currentButtonStatus = 1;
} else {
// fix second press
currentButtonStatus = 3;
currentButtonStatusStart3 = millis();
}
} else {
// if the button is still released
// check for the single click
if(timeButton - currentButtonStatusStart2 > delayDeltaDoubleClick) {
// button has been released for too long, fix single click
currentButtonStatus = 0;
event = 1;
}
}
break;
case 3:
// confirm double click
if(currentButtonClick) {
// button is still pressed
// wait for the button to be released
} else {
// button has been released
// check for the debounce
if(timeButton - currentButtonStatusStart3 < delayFalse) {
// button has been released too early, probably it's a debounce
} else {
// fix double click
event = 2;
currentButtonStatus = 0;
}
}
break;
}
return event;
}
另一个评论:每个按钮可能需要上拉电阻。如果你没有外部的,你可以修改pinMode声明:pinMode (butt1.getPin(), INPUT_PULLUP);
。