Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Encoder.cpp@8:3086ea6466d1, 2015-05-20 (annotated)
- 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?
| User | Revision | Line number | New 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 |