title: Arduino click, double click and hold button
body: <p>I am trying to implement three different functions for one button in an Arduino project. Click, double click and hold.
  I have to use interrupts and let the system sleep as much as possible, because the final product will have to run on a coin cell for a few months.</p>
  
  <pre><code>#include &lt;Ports.h&gt;
  #include &lt;RF12.h&gt;
  #include &lt;avr/sleep.h&gt;
  #include &lt;PinChangeInt.h&gt;
  #include &lt;VirtualWire.h&gt;
  
  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 &gt; 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 &gt; 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();
  }
  </code></pre>
  
  <p>The problem is that this is not always correctly working.
  Because I'm using interrupts, <code>millis()</code> inside <code>void loop()</code> is not reliable, for some reason.</p>
  
  <p>For any double click, and for any hold action, the single click function also gets called. I suspect this is due to multiple interrupts firing, but I have no way to test this. Also, sometimes, the double click seems to need only one click. Is my thinking wrong, did I forget something?</p>