define(`TITLE', `Debouncing a rotary encoder is really hard')
define(`DATE', `2014-01-08')
define(`CONTENT', `
... but finally it worked:

<pre>
const unsigned long DEBOUNCING_DEAD_TIME = 100;
const int DEBOUNCING_REPEAT = 1000;


volatile int rotaryCount = 0;
volatile bool switchState = false;
volatile unsigned long lastEvent = 0;

int myDigitalRead(int a) {
  int r = 0;
  for (int i = 0; i &lt; DEBOUNCING_REPEAT; i++) {
    if (digitalRead(a) == HIGH) {
      r++;
    } else {
      r--;
    }
  }
  int res = -1;
  if (r &gt;= (DEBOUNCING_REPEAT / 2)) {
    res = 1;
  } else if (r &lt;= -1 * (DEBOUNCING_REPEAT / 2)) {
    res = 0;
  }
  return res;
}

void rotary_a_interrupt() {
  unsigned long currentEvent = millis();

  if ((lastEvent == 0) || (lastEvent + DEBOUNCING_DEAD_TIME &lt; currentEvent)) {
    lastEvent = currentEvent;

    int a = myDigitalRead(ROTARY_A);
    int b = myDigitalRead(ROTARY_B);

    if (((a != -1) &amp;&amp; (b != -1))) {
      if (a == b) {
        rotaryCount++;
      } else {
        rotaryCount--;
      }
    }
  }
}

void rotary_b_interrupt() {
  unsigned long currentEvent = millis();

  if ((lastEvent == 0) || (lastEvent + DEBOUNCING_DEAD_TIME &lt; currentEvent)) {
    lastEvent = currentEvent;

    int a = myDigitalRead(ROTARY_A);
    int b = myDigitalRead(ROTARY_B);

    if (((a != -1) &amp;&amp; (b != -1))) {
      if (a == b) {
        rotaryCount--;
      } else {
        rotaryCount++;
      }
    }
  }
}

void switch_interrupt() {
  unsigned long currentEvent = millis();

  if ((lastEvent == 0) || (lastEvent + DEBOUNCING_DEAD_TIME &lt; currentEvent)) {
    lastEvent = currentEvent;

    switchState = true;
  }
}

void hardwareInit() {
  pinMode(SWITCH, INPUT_PULLUP);
  pinMode(ROTARY_A, INPUT_PULLUP);
  pinMode(ROTARY_B, INPUT_PULLUP);
  attachInterrupt(SWITCH_IRQ, switch_interrupt, FALLING);
  attachInterrupt(ROTARY_A_IRQ, rotary_a_interrupt, CHANGE);
  attachInterrupt(ROTARY_B_IRQ, rotary_b_interrupt, CHANGE);
}
</pre>

The primary problem was not to get any rotary event of the wrong direction, the secondary problem was not to miss too much events, best of course none.

Only the combination of a dead time after one interrupt and validating a read pin state by rereading it MANY times solved the primary problem. To solve the secondary problem too, the validation has be softened by not requiring all reread states to have the same value but accepting a limited number of wrong values.
')