我想为Arduino项目中的一个按钮实现三种不同的功能。点击,双击并按住。 我必须使用中断,并尽可能让系统进入睡眠状态,因为最终产品必须在硬币电池上运行几个月。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()
是不可靠的,出于某种原因。
对于任何双击和任何保持操作,单击功能也会被调用。我怀疑这是由于多个中断触发,但我无法测试这个。另外,有时候,双击似乎只需要一次点击。我的思想错了吗,我忘记了什么吗?
这是有道理的,特别是对于额外的单击功能调用,当你这样说的时候。当设备进入睡眠状态时,这个例子会不会更复杂一些,因为睡眠时millis()不会增加?什么是最好的方法仍然包括反弹? –
添加类似'static unsigned long last_interrupt_time = 0; unsigned long interrupt_time = millis(); if(interrupt_time - last_interrupt_time> 200)',行为仍然相同。 –