OmEspHelpers
OmRotaryEncoder.h
1 /*
2  * Some technical notes about why I did it this way.
3  * Each rotary encoder gets its own plain-old-C zero-arguments interrupt
4  * service routine (isr). This happens because each unique template
5  * signature of the class gets its own set of class-global (static)
6  * variables and functions, including the isr. A c++ static method
7  * is a plain old c function.
8  *
9  * So, each set of unique pins... gets it own isr.
10  *
11  * There's no reason to declare two RotaryEncoder instances with
12  * the same pins. But it'd probably work, returning same value for both.
13  */
14 template <int pinD0, int pinD1, int pinB>
16 {
17 public:
18  static int oldD0;
19  static int oldD1;
20  static int oldB;
21  static int irqs;
22  static int value4;
23  static int value;
24 
26  {
27  pinMode(pinD0, INPUT_PULLUP);
28  pinMode(pinD1, INPUT_PULLUP);
29  pinMode(pinB, INPUT_PULLUP);
30 
31  attachInterrupt(pinD0, OmRotaryEncoder::isrRe, CHANGE);
32  attachInterrupt(pinD1, OmRotaryEncoder::isrRe, CHANGE);
33  attachInterrupt(pinB, OmRotaryEncoder::isrRe, CHANGE);
34 
35  OmRotaryEncoder::oldD0 = 1;
36  OmRotaryEncoder::oldD1 = 1;
37  OmRotaryEncoder::oldB = 1;
38  OmRotaryEncoder::irqs = 0;
39  OmRotaryEncoder::value4 = 0;
40  OmRotaryEncoder::value = 0;
41  }
42 
43  int getValue()
44  {
45  return OmRotaryEncoder::value;
46  }
47 
48  static void IRAM_ATTR isrRe() // i read on the internet that IRAM_ATTR is needed, on dual core esp32... ok
49  {
50 
51  OmRotaryEncoder::irqs++;
52 
53  int d0 = digitalRead(pinD0);
54  int d1 = digitalRead(pinD1);
55 
56  if(OmRotaryEncoder::oldD0 == d0 && OmRotaryEncoder::oldD1 == d1) return; // not for us.
57 
58  int dir = 0;
59 
60  if(d0 != OmRotaryEncoder::oldD0)
61  dir = d0 == d1 ? +1 : -1;
62  else if(d1 != OmRotaryEncoder::oldD1)
63  dir = d0 != d1 ? +1 : -1;
64 
65  OmRotaryEncoder::value4 += dir;
66 
67  /*
68  * The rotary encoder I'm using has 4 steps per click.
69  * So for debouncing and hysteresis, we lock in the new
70  * value when it achieves a multiple of 4, giving room
71  * for three steps of slip and bounce without fluttering
72  * the value. Really we could do multiples of 2 safely as well.
73  * Or 3, but it wouldn't line up to the clicks.
74  * Perhaps this precision should be a variable to the instantiation.
75  * dvb2019
76  */
77  if(OmRotaryEncoder::value4 % 4 == 0)
78  OmRotaryEncoder::value = OmRotaryEncoder::value4 / 4;
79 
80  OmRotaryEncoder::oldD0 = d0;
81  OmRotaryEncoder::oldD1 = d1;
82  }
83 
84 };
85 
86 // TODO this belongs in .cpp file. It can only be stated once, so not belong in .h. dvb2019.
87 template <int pinD0, int pinD1, int pinB> int OmRotaryEncoder<pinD0, pinD1, pinB>::oldD0;
88 template <int pinD0, int pinD1, int pinB> int OmRotaryEncoder<pinD0, pinD1, pinB>::oldD1;
89 template <int pinD0, int pinD1, int pinB> int OmRotaryEncoder<pinD0, pinD1, pinB>::oldB;
90 template <int pinD0, int pinD1, int pinB> int OmRotaryEncoder<pinD0, pinD1, pinB>::irqs;
91 template <int pinD0, int pinD1, int pinB> int OmRotaryEncoder<pinD0, pinD1, pinB>::value4;
92 template <int pinD0, int pinD1, int pinB> int OmRotaryEncoder<pinD0, pinD1, pinB>::value;
93 
OmRotaryEncoder
Definition: OmRotaryEncoder.h:16