2015-09-27 300 views
1

我想为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()是不可靠的,出于某种原因。

对于任何双击和任何保持操作,单击功能也会被调用。我怀疑这是由于多个中断触发,但我无法测试这个。另外,有时候,双击似乎只需要一次点击。我的思想错了吗,我忘记了什么吗?

回答

1

如果您看到singleTapActiondoubleTapAction触发过于频繁,这个问题可能是你的方法,并没有真正的去抖按钮输入,这意味着你可以在任何点击作为单一按下键或双击按阅读杂散噪声。 E.G第一个while循环会在出现噪声输入时几乎立即退出,这会使以下行为难以预测。

https://www.arduino.cc/en/Tutorial/Debounce

如果你看一下在Arduino的网站链接的例子 - 一个可能的解决方案是记录时间的输入就一直存在的时期,而忽略小于一定时期的任何输入。修改你的代码来做到这一点可以阻止虚假的呼叫。

+0

这是有道理的,特别是对于额外的单击功能调用,当你这样说的时候。当设备进入睡眠状态时,这个例子会不会更复杂一些,因为睡眠时millis()不会增加?什么是最好的方法仍然包括反弹? –

+0

添加类似'static unsigned long last_interrupt_time = 0; unsigned long interrupt_time = millis(); if(interrupt_time - last_interrupt_time> 200)',行为仍然相同。 –