Library for manual Encoders as used in user interfaces. Very simple, reduced and rock solid encoder library. Counts full pulses only. Inherent debouncing through state machine. Running on a regular timer IRQ. No IRQ jamming through bouncing. Immune to false edges giving unwanted counts when moving partial steps. Not depending on PinDetect or anything else. May be enhanced by adding acceleration and push button debouncing in the future.

Library for manual Encoders as used in user interfaces. Very simple, reduced and rock solid. Counts full pulses/steps only. Inherent debouncing through state machine. No time dependency for debouncing. Very tight code running in a regular timer IRQ. No IRQ jamming through bouncing edges. Immune to false edges giving unwanted counts when moving partial steps back and forth. Not depending on PinDetect or any other debouncing library. May be enhanced in the near future by adding acceleration and push button debouncing.

Committer:
eduardoG26
Date:
Tue Nov 25 08:55:27 2014 +0000
Revision:
1:158a3886aced
Parent:
UI_Encoder.cpp@0:fc87dcec05fd
Child:
2:603b47d3755e
First Revision

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eduardoG26 1:158a3886aced 1 // Encoder lib
eduardoG26 1:158a3886aced 2 // Extremely simple time driven state machin with inherent debouncing.
eduardoG26 1:158a3886aced 3 // No irq-jamming because of switch bouncing
eduardoG26 1:158a3886aced 4 // No counting on first edges when encoder leaves idle state (both switches open).
eduardoG26 1:158a3886aced 5 // Rock solid
eduardoG26 1:158a3886aced 6
eduardoG26 0:fc87dcec05fd 7 #include "mbed.h"
eduardoG26 1:158a3886aced 8 #include "Encoder.h"
eduardoG26 1:158a3886aced 9
eduardoG26 1:158a3886aced 10
eduardoG26 1:158a3886aced 11 // Chose encoder pins, default, nucleo-XXX
eduardoG26 1:158a3886aced 12 #ifndef ENCODER_PIN_A
eduardoG26 1:158a3886aced 13 #define ENCODER_PIN_A D6
eduardoG26 1:158a3886aced 14 #endif
eduardoG26 1:158a3886aced 15 #ifndef ENCODER_PIN_B
eduardoG26 1:158a3886aced 16 #define ENCODER_PIN_B D7
eduardoG26 1:158a3886aced 17 #endif
eduardoG26 1:158a3886aced 18
eduardoG26 1:158a3886aced 19 // Sample every ... microseconds, default
eduardoG26 1:158a3886aced 20 // 250µs is a good value for cheap 24 ppr encoders (ALPS EC12E24...) with strong bouncing.
eduardoG26 1:158a3886aced 21 // 1000µs is a good value for quality 24 ppr encoders (ALPS EC12E24...) with low bouncing.
eduardoG26 1:158a3886aced 22 // 250µs is a good value for fast 24+ ppr encoders (Sparkfun, Qubig Panel1 type...).
eduardoG26 1:158a3886aced 23 #ifndef ENCODER_SAMPLE_PERIOD_US
eduardoG26 1:158a3886aced 24 #define ENCODER_SAMPLE_PERIOD_US (250)
eduardoG26 1:158a3886aced 25 #endif
eduardoG26 0:fc87dcec05fd 26
eduardoG26 0:fc87dcec05fd 27 static volatile uint16_t Pulses;
eduardoG26 0:fc87dcec05fd 28 static bool UpDown, Ready;
eduardoG26 0:fc87dcec05fd 29
eduardoG26 0:fc87dcec05fd 30 DigitalIn PinA(ENCODER_PIN_A), PinB(ENCODER_PIN_B);
eduardoG26 0:fc87dcec05fd 31
eduardoG26 0:fc87dcec05fd 32 static Ticker EncoderTick;
eduardoG26 1:158a3886aced 33 static void EncoderTickIRQ();
eduardoG26 0:fc87dcec05fd 34
eduardoG26 1:158a3886aced 35 // Call once in main.
eduardoG26 1:158a3886aced 36 void EncoderStart ()
eduardoG26 1:158a3886aced 37 {
eduardoG26 1:158a3886aced 38 PinA.mode(PullUp);
eduardoG26 1:158a3886aced 39 PinB.mode(PullUp);
eduardoG26 1:158a3886aced 40 EncoderTick.attach_us (&EncoderTickIRQ, ENCODER_SAMPLE_PERIOD_US);
eduardoG26 1:158a3886aced 41 }
eduardoG26 1:158a3886aced 42
eduardoG26 1:158a3886aced 43 // Switch off Pullups and IRQ to save power f. e.
eduardoG26 1:158a3886aced 44 void EncoderStop ()
eduardoG26 1:158a3886aced 45 {
eduardoG26 1:158a3886aced 46 PinA.mode(PullNone);
eduardoG26 1:158a3886aced 47 PinB.mode(PullNone);
eduardoG26 1:158a3886aced 48 EncoderTick.detach();
eduardoG26 1:158a3886aced 49 }
eduardoG26 1:158a3886aced 50 // Get counting variable.
eduardoG26 1:158a3886aced 51 uint16_t EncoderGet ()
eduardoG26 1:158a3886aced 52 {
eduardoG26 1:158a3886aced 53 return Pulses;
eduardoG26 1:158a3886aced 54 }
eduardoG26 1:158a3886aced 55
eduardoG26 1:158a3886aced 56 // State machine. Runs in IRQ. Static.
eduardoG26 0:fc87dcec05fd 57 static void EncoderTickIRQ()
eduardoG26 0:fc87dcec05fd 58 {
eduardoG26 1:158a3886aced 59 // If-then-else structure is good because every pin is read max. once.
eduardoG26 0:fc87dcec05fd 60 if(PinB) {
eduardoG26 0:fc87dcec05fd 61 if(PinA) { // clockwise?
eduardoG26 0:fc87dcec05fd 62 Ready = true;
eduardoG26 0:fc87dcec05fd 63 } else {
eduardoG26 0:fc87dcec05fd 64 UpDown = true;
eduardoG26 0:fc87dcec05fd 65 }
eduardoG26 0:fc87dcec05fd 66 } else {
eduardoG26 0:fc87dcec05fd 67 if(PinA) { // counterclockwise?
eduardoG26 0:fc87dcec05fd 68 UpDown = false;
eduardoG26 0:fc87dcec05fd 69 } else {
eduardoG26 0:fc87dcec05fd 70 if(Ready) {
eduardoG26 0:fc87dcec05fd 71 if (UpDown) {
eduardoG26 0:fc87dcec05fd 72 Pulses++; //moving forward
eduardoG26 0:fc87dcec05fd 73 } else {
eduardoG26 0:fc87dcec05fd 74 Pulses--; //moving reverse
eduardoG26 0:fc87dcec05fd 75 }
eduardoG26 0:fc87dcec05fd 76 Ready = false;
eduardoG26 0:fc87dcec05fd 77 }
eduardoG26 0:fc87dcec05fd 78 }
eduardoG26 0:fc87dcec05fd 79 }
eduardoG26 0:fc87dcec05fd 80 }
eduardoG26 0:fc87dcec05fd 81
eduardoG26 0:fc87dcec05fd 82 // End of file