Eduardo de Mier / UIEncoder
Committer:
eduardoG26
Date:
Wed May 20 18:16:22 2015 +0000
Revision:
8:3086ea6466d1
Parent:
7:c7daa056b152
Changes for easy ebugging

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eduardoG26 2:603b47d3755e 1 // Encoder lib for user interfaces
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 2:603b47d3755e 6 /*
eduardoG26 2:603b47d3755e 7 The MIT License (MIT)
eduardoG26 2:603b47d3755e 8
eduardoG26 2:603b47d3755e 9 Copyright (c) 2014 calima engineering
eduardoG26 2:603b47d3755e 10
eduardoG26 2:603b47d3755e 11 Permission is hereby granted, free of charge, to any person obtaining a copy
eduardoG26 2:603b47d3755e 12 of this software and associated documentation files (the "Software"), to deal
eduardoG26 2:603b47d3755e 13 in the Software without restriction, including without limitation the rights
eduardoG26 2:603b47d3755e 14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
eduardoG26 2:603b47d3755e 15 copies of the Software, and to permit persons to whom the Software is
eduardoG26 2:603b47d3755e 16 furnished to do so, subject to the following conditions:
eduardoG26 2:603b47d3755e 17
eduardoG26 2:603b47d3755e 18 The above copyright notice and this permission notice shall be included in
eduardoG26 2:603b47d3755e 19 all copies or substantial portions of the Software.
eduardoG26 2:603b47d3755e 20
eduardoG26 2:603b47d3755e 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
eduardoG26 2:603b47d3755e 22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
eduardoG26 2:603b47d3755e 23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
eduardoG26 2:603b47d3755e 24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
eduardoG26 2:603b47d3755e 25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
eduardoG26 2:603b47d3755e 26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
eduardoG26 2:603b47d3755e 27 THE SOFTWARE.
eduardoG26 2:603b47d3755e 28 */
eduardoG26 1:158a3886aced 29
eduardoG26 0:fc87dcec05fd 30 #include "mbed.h"
eduardoG26 1:158a3886aced 31 #include "Encoder.h"
eduardoG26 2:603b47d3755e 32 #include "EncoderConfig.h"
eduardoG26 1:158a3886aced 33
eduardoG26 1:158a3886aced 34 // Chose encoder pins, default, nucleo-XXX
eduardoG26 1:158a3886aced 35 #ifndef ENCODER_PIN_A
eduardoG26 1:158a3886aced 36 #define ENCODER_PIN_A D6
eduardoG26 1:158a3886aced 37 #endif
eduardoG26 5:70534b19d8bf 38
eduardoG26 1:158a3886aced 39 #ifndef ENCODER_PIN_B
eduardoG26 1:158a3886aced 40 #define ENCODER_PIN_B D7
eduardoG26 1:158a3886aced 41 #endif
eduardoG26 1:158a3886aced 42
eduardoG26 5:70534b19d8bf 43 #ifndef ENCODER_PIN_PB
eduardoG26 5:70534b19d8bf 44 #define ENCODER_PIN_PB D5
eduardoG26 5:70534b19d8bf 45 #endif
eduardoG26 5:70534b19d8bf 46
eduardoG26 1:158a3886aced 47 // Sample every ... microseconds, default
eduardoG26 1:158a3886aced 48 // 250µs is a good value for cheap 24 ppr encoders (ALPS EC12E24...) with strong bouncing.
eduardoG26 1:158a3886aced 49 // 1000µs is a good value for quality 24 ppr encoders (ALPS EC12E24...) with low bouncing.
eduardoG26 1:158a3886aced 50 // 250µs is a good value for fast 24+ ppr encoders (Sparkfun, Qubig Panel1 type...).
eduardoG26 1:158a3886aced 51 #ifndef ENCODER_SAMPLE_PERIOD_US
eduardoG26 1:158a3886aced 52 #define ENCODER_SAMPLE_PERIOD_US (250)
eduardoG26 1:158a3886aced 53 #endif
eduardoG26 0:fc87dcec05fd 54
eduardoG26 7:c7daa056b152 55 // Calc debounce counter reload
eduardoG26 5:70534b19d8bf 56 #define PB_DEBOUNCE_RELOAD (((uint32_t)ENCODER_PB_DEBOUNCE_MS * 1000uL) / ENCODER_SAMPLE_PERIOD_US)
eduardoG26 5:70534b19d8bf 57
eduardoG26 4:ee384561bfa4 58 // Counts steps := pulses
eduardoG26 6:c2af98aa7d2b 59 static volatile uint16_t Pulses_u16;
eduardoG26 4:ee384561bfa4 60
eduardoG26 4:ee384561bfa4 61 // State variables
eduardoG26 6:c2af98aa7d2b 62 static volatile bool Up, Down, Ready, PB_RawState_b, PB_State_b;
eduardoG26 0:fc87dcec05fd 63
eduardoG26 6:c2af98aa7d2b 64 // Counter for debouncing
eduardoG26 5:70534b19d8bf 65 static volatile uint16_t PB_DebounceCounter_u16;
eduardoG26 5:70534b19d8bf 66
eduardoG26 5:70534b19d8bf 67 DigitalIn PinA(ENCODER_PIN_A), PinB(ENCODER_PIN_B), PinPB(ENCODER_PIN_PB);
eduardoG26 0:fc87dcec05fd 68
eduardoG26 0:fc87dcec05fd 69 static Ticker EncoderTick;
eduardoG26 1:158a3886aced 70 static void EncoderTickIRQ();
eduardoG26 0:fc87dcec05fd 71
eduardoG26 6:c2af98aa7d2b 72 #if DEBUG_ENC
eduardoG26 6:c2af98aa7d2b 73 static DigitalOut DebugPin(D4);
eduardoG26 6:c2af98aa7d2b 74 #endif
eduardoG26 6:c2af98aa7d2b 75
eduardoG26 1:158a3886aced 76 // Call once in main.
eduardoG26 1:158a3886aced 77 void EncoderStart ()
eduardoG26 1:158a3886aced 78 {
eduardoG26 5:70534b19d8bf 79 PinA.mode(PullUp); // Encoder pin A
eduardoG26 5:70534b19d8bf 80 PinB.mode(PullUp); // Encoder pin B
eduardoG26 1:158a3886aced 81 EncoderTick.attach_us (&EncoderTickIRQ, ENCODER_SAMPLE_PERIOD_US);
eduardoG26 5:70534b19d8bf 82 PinPB.mode(PullUp); // Pushbutton pin
eduardoG26 5:70534b19d8bf 83 PB_DebounceCounter_u16 = PB_DEBOUNCE_RELOAD; // Start
eduardoG26 1:158a3886aced 84 }
eduardoG26 1:158a3886aced 85
eduardoG26 4:ee384561bfa4 86 // Switch off IRQ and change Pullups to PullDowns to save power
eduardoG26 1:158a3886aced 87 void EncoderStop ()
eduardoG26 1:158a3886aced 88 {
eduardoG26 3:e8e1481ac042 89 PinA.mode(PullDown);
eduardoG26 3:e8e1481ac042 90 PinB.mode(PullDown);
eduardoG26 5:70534b19d8bf 91 PinPB.mode(PullDown);
eduardoG26 1:158a3886aced 92 EncoderTick.detach();
eduardoG26 1:158a3886aced 93 }
eduardoG26 5:70534b19d8bf 94
eduardoG26 1:158a3886aced 95 // Get counting variable.
eduardoG26 5:70534b19d8bf 96 uint16_t EncoderGetPulses ()
eduardoG26 1:158a3886aced 97 {
eduardoG26 6:c2af98aa7d2b 98 return Pulses_u16;
eduardoG26 1:158a3886aced 99 }
eduardoG26 1:158a3886aced 100
eduardoG26 5:70534b19d8bf 101 // Get pushbutton state.
eduardoG26 5:70534b19d8bf 102 bool EncoderGetPB ()
eduardoG26 5:70534b19d8bf 103 {
eduardoG26 5:70534b19d8bf 104 return not PB_State_b; // invert, pressed == true
eduardoG26 5:70534b19d8bf 105 }
eduardoG26 5:70534b19d8bf 106
eduardoG26 1:158a3886aced 107 // State machine. Runs in IRQ. Static.
eduardoG26 0:fc87dcec05fd 108 static void EncoderTickIRQ()
eduardoG26 0:fc87dcec05fd 109 {
eduardoG26 8:3086ea6466d1 110 #if DEBUG_ENC
eduardoG26 8:3086ea6466d1 111 DebugPin = 0;
eduardoG26 8:3086ea6466d1 112 DebugPin = 1;
eduardoG26 8:3086ea6466d1 113 DebugPin = 0;
eduardoG26 8:3086ea6466d1 114 #endif
eduardoG26 6:c2af98aa7d2b 115 // Encoder section
eduardoG26 1:158a3886aced 116 // If-then-else structure is good because every pin is read max. once.
eduardoG26 0:fc87dcec05fd 117 if(PinB) {
eduardoG26 7:c7daa056b152 118 if(PinA) { // booth open?
eduardoG26 6:c2af98aa7d2b 119 //no! Skips pulses at low speed! Ready = (!Up && !Down); (one extra cicle in idle mode)
eduardoG26 6:c2af98aa7d2b 120 Ready = true; // Reset all
eduardoG26 6:c2af98aa7d2b 121 Up = false;
eduardoG26 6:c2af98aa7d2b 122 Down = false;
eduardoG26 0:fc87dcec05fd 123 } else {
eduardoG26 6:c2af98aa7d2b 124 Up = Ready; // clockwise.
eduardoG26 0:fc87dcec05fd 125 }
eduardoG26 7:c7daa056b152 126 } else {
eduardoG26 0:fc87dcec05fd 127 if(PinA) { // counterclockwise?
eduardoG26 7:c7daa056b152 128 Down = Ready;
eduardoG26 7:c7daa056b152 129 } else { // booth closed?
eduardoG26 0:fc87dcec05fd 130 if(Ready) {
eduardoG26 6:c2af98aa7d2b 131 if (Up) {
eduardoG26 6:c2af98aa7d2b 132 Pulses_u16++; //moving forward
eduardoG26 7:c7daa056b152 133 #if DEBUG_ENC
eduardoG26 7:c7daa056b152 134 DebugPin = 1;
eduardoG26 7:c7daa056b152 135 #endif
eduardoG26 0:fc87dcec05fd 136 }
eduardoG26 6:c2af98aa7d2b 137 // Do not change to ...else... construct!
eduardoG26 6:c2af98aa7d2b 138 if (Down) {
eduardoG26 6:c2af98aa7d2b 139 Pulses_u16--; //moving reverse
eduardoG26 7:c7daa056b152 140 #if DEBUG_ENC
eduardoG26 7:c7daa056b152 141 DebugPin = 0;
eduardoG26 7:c7daa056b152 142 #endif
eduardoG26 6:c2af98aa7d2b 143 }
eduardoG26 0:fc87dcec05fd 144 }
eduardoG26 6:c2af98aa7d2b 145 Ready = false;
eduardoG26 0:fc87dcec05fd 146 }
eduardoG26 0:fc87dcec05fd 147 }
eduardoG26 6:c2af98aa7d2b 148
eduardoG26 6:c2af98aa7d2b 149
eduardoG26 6:c2af98aa7d2b 150 // Pushbutton section
eduardoG26 5:70534b19d8bf 151 if(PinPB == PB_RawState_b) {
eduardoG26 5:70534b19d8bf 152 if(--PB_DebounceCounter_u16 == 0) {
eduardoG26 5:70534b19d8bf 153 PB_State_b = PB_RawState_b;
eduardoG26 5:70534b19d8bf 154 PB_DebounceCounter_u16 = PB_DEBOUNCE_RELOAD; // Restart
eduardoG26 5:70534b19d8bf 155 }
eduardoG26 5:70534b19d8bf 156 } else {
eduardoG26 5:70534b19d8bf 157 PB_RawState_b = PinPB;
eduardoG26 5:70534b19d8bf 158 PB_DebounceCounter_u16 = PB_DEBOUNCE_RELOAD; // Restart
eduardoG26 5:70534b19d8bf 159 }
eduardoG26 0:fc87dcec05fd 160 }
eduardoG26 0:fc87dcec05fd 161
eduardoG26 0:fc87dcec05fd 162 // End of file