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.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Encoder.cpp Source File

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