我正在尝试为Arduino项目中的一个按钮实现三个不同的功能。单击,双击并按住。 我必须使用中断并让系统尽可能地休眠,因为最终产品必须在硬币电池上运行几个月。
#include <Ports.h>
#include <RF12.h>
#include <avr/sleep.h>
#include <PinChangeInt.h>
#include <VirtualWire.h>
ISR(WDT_vect) { Sleepy::watchdogEvent(); }
char *controller;
const int buttonPin = 3;
bool stateSingle = false;
bool stateDouble = false;
bool stateLong = false;
void setup() {
pinMode(13, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(5, OUTPUT);
// vw_set_ptt_inverted(true);
// vw_set_tx_pin(12);
// vw_setup(4000);
//
Serial.begin(9600);
PCintPort::attachInterrupt(buttonPin, wakeUp, HIGH);
}
void wakeUp() {
}
void loop() {
cli();
int i = 0;
while (digitalRead(buttonPin) == HIGH) { // Wait until button is LOW, or has been high for more than 600ms
Sleepy::loseSomeTime(50);
if (i > 12)
break;
i++;
}
if (digitalRead(buttonPin) == HIGH)
longTapAction();
else {
i = 0;
while (digitalRead(buttonPin) == LOW) { // Wait for possible double press
Sleepy::loseSomeTime(50);
if (i > 8)
break;
i++;
}
if (digitalRead(buttonPin) == HIGH) {
doubleTapAction();
while (digitalRead(buttonPin) == HIGH)
Sleepy::loseSomeTime(50);
} else
singleTapAction();
}
}
void singleTapAction() {
stateSingle = !stateSingle;
digitalWrite(5, stateSingle ? HIGH : LOW);
sei();
Sleepy::powerDown();
}
void doubleTapAction() {
stateDouble = !stateDouble;
digitalWrite(6, stateDouble ? HIGH : LOW);
sei();
Sleepy::powerDown();
}
void longTapAction() {
stateLong = !stateLong;
digitalWrite(7, stateLong ? HIGH : LOW);
sei();
Sleepy::powerDown();
}
问题是这并不总是正常工作。
由于我使用了中断,millis()
内的void loop()
由于某种原因不可靠。
对于任何双击,对于任何保留操作,也会调用单击功能。我怀疑这是由于多次中断触发,但我没办法测试这个。此外,有时,双击似乎只需要一次点击。我的想法是错的,我忘记了吗?
答案 0 :(得分:1)
如果您经常看到char hostname[50];
⋮
rc = gethostname(hostname,sizeof(hostname));
和singleTapAction
触发,问题可能是您的方法没有真正去除按钮输入,这意味着您可能会在任何点击上读取虚假噪音按或双按。如果有嘈杂的输入,你的第一个while循环几乎会立即退出,这使得以下行为难以预测。
https://www.arduino.cc/en/Tutorial/Debounce
如果您查看arduino网站上的链接示例 - 可能的解决方案是记录输入存在的时间段并忽略少于一定时间段的任何输入。修改代码来执行此操作可以阻止虚假调用。