/* MD_REncoder - Library for Rotary Encoders See header file for comments This version copyright (C) 2014 Marco Colli. All rights reserved. Original library copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3. Contact: bb@cactii.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** * \file * \brief Implements core MD_REncoder class methods */ #include /* * The below state table has, for each state (row), the new state * to set based on the next encoder output. From left to right in, * the table, the encoder outputs are 00, 01, 10, 11, and the value * in that position is the new state to set. */ #define R_START 0x0 #if ENABLE_HALF_STEP // Use the half-step state table (emits a code at 00 and 11) #define R_CCW_BEGIN 0x1 #define R_CW_BEGIN 0x2 #define R_START_M 0x3 #define R_CW_BEGIN_M 0x4 #define R_CCW_BEGIN_M 0x5 const unsigned char ttable[][4] = { // 00 01 10 11 {R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START}, // R_START (00) {R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START}, // R_CCW_BEGIN {R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START}, // R_CW_BEGIN {R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START}, // R_START_M (11) {R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW}, // R_CW_BEGIN_M {R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW} // R_CCW_BEGIN_M }; #else // Use the full-step state table (emits a code at 00 only) #define R_CW_FINAL 0x1 #define R_CW_BEGIN 0x2 #define R_CW_NEXT 0x3 #define R_CCW_BEGIN 0x4 #define R_CCW_FINAL 0x5 #define R_CCW_NEXT 0x6 const unsigned char ttable[][4] = { // 00 01 10 11 {R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START}, // R_START {R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW}, // R_CW_FINAL {R_CW_NEXT, R_CW_BEGIN, R_START, R_START}, // R_CW_BEGIN {R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START}, // R_CW_NEXT {R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START}, // R_CCW_BEGIN {R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW}, // R_CCW_FINAL {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START} // R_CCW_NEXT }; #endif MD_REncoder::MD_REncoder(uint8_t pinA, uint8_t pinB): _pinA (pinA), _pinB (pinB), _state(R_START) #if ENABLE_SPEED , _period(DEFAULT_PERIOD), _count(0), _spd(0), _timeLast(0) #endif { } void MD_REncoder::begin(void) { pinMode(_pinA, (ENABLE_PULLUPS ? INPUT_PULLUP : INPUT)); pinMode(_pinB, (ENABLE_PULLUPS ? INPUT_PULLUP : INPUT)); value=0; last_dir=DIR_NONE; } void MD_REncoder::update(void) // Grab state of input pins, determine new state from the pins // and state table, and return the emit bits (ie the generated event). { uint8_t pinstate = (digitalRead(_pinB) << 1) | digitalRead(_pinA); _state = ttable[_state & 0xf][pinstate]; #if ENABLE_SPEED // handle the encoder velocity calc if (_state & 0x30) _count++; if (millis() - _timeLast >= _period) { _spd = _count * (1000/_period); _timeLast = millis(); _count = 0; } #endif switch(_state & 0x30) { case DIR_CW: value++; last_dir=DIR_CW; break; case DIR_CCW: last_dir=DIR_CCW; value--; break; } } int32_t MD_REncoder::read_value(void) { return (value); } int8_t MD_REncoder::read(void) { switch(last_dir) { case DIR_CW: last_dir=DIR_NONE; return(4); case DIR_CCW: last_dir=DIR_NONE; return(-4); } return(0); } void MD_REncoder::write(int32_t v) { value=v; }