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.
Encoder.cpp
00001 // Encoder lib for user interfaces 00002 // Extremely simple time driven state machin with inherent debouncing. 00003 // No irq-jamming because of switch bouncing 00004 // No counting on first edges when encoder leaves idle state (both switches open). 00005 // Rock solid 00006 /* 00007 The MIT License (MIT) 00008 00009 Copyright (c) 2014 calima engineering 00010 00011 Permission is hereby granted, free of charge, to any person obtaining a copy 00012 of this software and associated documentation files (the "Software"), to deal 00013 in the Software without restriction, including without limitation the rights 00014 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00015 copies of the Software, and to permit persons to whom the Software is 00016 furnished to do so, subject to the following conditions: 00017 00018 The above copyright notice and this permission notice shall be included in 00019 all copies or substantial portions of the Software. 00020 00021 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00022 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00023 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00024 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00025 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00026 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00027 THE SOFTWARE. 00028 */ 00029 00030 #include "mbed.h" 00031 #include "Encoder.h" 00032 #include "EncoderConfig.h" 00033 00034 // Chose encoder pins, default, nucleo-XXX 00035 #ifndef ENCODER_PIN_A 00036 #define ENCODER_PIN_A D6 00037 #endif 00038 00039 #ifndef ENCODER_PIN_B 00040 #define ENCODER_PIN_B D7 00041 #endif 00042 00043 #ifndef ENCODER_PIN_PB 00044 #define ENCODER_PIN_PB D5 00045 #endif 00046 00047 // Sample every ... microseconds, default 00048 // 250µs is a good value for cheap 24 ppr encoders (ALPS EC12E24...) with strong bouncing. 00049 // 1000µs is a good value for quality 24 ppr encoders (ALPS EC12E24...) with low bouncing. 00050 // 250µs is a good value for fast 24+ ppr encoders (Sparkfun, Qubig Panel1 type...). 00051 #ifndef ENCODER_SAMPLE_PERIOD_US 00052 #define ENCODER_SAMPLE_PERIOD_US (250) 00053 #endif 00054 00055 // Calc debounce counter reload 00056 #define PB_DEBOUNCE_RELOAD (((uint32_t)ENCODER_PB_DEBOUNCE_MS * 1000uL) / ENCODER_SAMPLE_PERIOD_US) 00057 00058 // Counts steps := pulses 00059 static volatile uint16_t Pulses_u16; 00060 00061 // State variables 00062 static volatile bool Up, Down, Ready, PB_RawState_b, PB_State_b; 00063 00064 // Counter for debouncing 00065 static volatile uint16_t PB_DebounceCounter_u16; 00066 00067 DigitalIn PinA(ENCODER_PIN_A), PinB(ENCODER_PIN_B), PinPB(ENCODER_PIN_PB); 00068 00069 static Ticker EncoderTick; 00070 static void EncoderTickIRQ(); 00071 00072 #if DEBUG_ENC 00073 static DigitalOut DebugPin(D4); 00074 #endif 00075 00076 // Call once in main. 00077 void EncoderStart () 00078 { 00079 PinA.mode(PullUp); // Encoder pin A 00080 PinB.mode(PullUp); // Encoder pin B 00081 EncoderTick.attach_us (&EncoderTickIRQ, ENCODER_SAMPLE_PERIOD_US); 00082 PinPB.mode(PullUp); // Pushbutton pin 00083 PB_DebounceCounter_u16 = PB_DEBOUNCE_RELOAD; // Start 00084 } 00085 00086 // Switch off IRQ and change Pullups to PullDowns to save power 00087 void EncoderStop () 00088 { 00089 PinA.mode(PullDown); 00090 PinB.mode(PullDown); 00091 PinPB.mode(PullDown); 00092 EncoderTick.detach(); 00093 } 00094 00095 // Get counting variable. 00096 uint16_t EncoderGetPulses () 00097 { 00098 return Pulses_u16; 00099 } 00100 00101 // Get pushbutton state. 00102 bool EncoderGetPB () 00103 { 00104 return not PB_State_b; // invert, pressed == true 00105 } 00106 00107 // State machine. Runs in IRQ. Static. 00108 static void EncoderTickIRQ() 00109 { 00110 #if DEBUG_ENC 00111 DebugPin = 0; 00112 DebugPin = 1; 00113 DebugPin = 0; 00114 #endif 00115 // Encoder section 00116 // If-then-else structure is good because every pin is read max. once. 00117 if(PinB) { 00118 if(PinA) { // booth open? 00119 //no! Skips pulses at low speed! Ready = (!Up && !Down); (one extra cicle in idle mode) 00120 Ready = true; // Reset all 00121 Up = false; 00122 Down = false; 00123 } else { 00124 Up = Ready; // clockwise. 00125 } 00126 } else { 00127 if(PinA) { // counterclockwise? 00128 Down = Ready; 00129 } else { // booth closed? 00130 if(Ready) { 00131 if (Up) { 00132 Pulses_u16++; //moving forward 00133 #if DEBUG_ENC 00134 DebugPin = 1; 00135 #endif 00136 } 00137 // Do not change to ...else... construct! 00138 if (Down) { 00139 Pulses_u16--; //moving reverse 00140 #if DEBUG_ENC 00141 DebugPin = 0; 00142 #endif 00143 } 00144 } 00145 Ready = false; 00146 } 00147 } 00148 00149 00150 // Pushbutton section 00151 if(PinPB == PB_RawState_b) { 00152 if(--PB_DebounceCounter_u16 == 0) { 00153 PB_State_b = PB_RawState_b; 00154 PB_DebounceCounter_u16 = PB_DEBOUNCE_RELOAD; // Restart 00155 } 00156 } else { 00157 PB_RawState_b = PinPB; 00158 PB_DebounceCounter_u16 = PB_DEBOUNCE_RELOAD; // Restart 00159 } 00160 } 00161 00162 // End of file
Generated on Sun Jul 24 2022 11:04:44 by 1.7.2