Quadrature encoder interface by Aaron Berk

Dependents:   TEST_ENCODER

Fork of QEI by Aaron Berk

QEI.cpp

Committer:
aminomar
Date:
2016-05-04
Revision:
1:5f28ceec8280
Parent:
0:5c2ad81551aa

File content as of revision 1:5f28ceec8280:


#include "QEI.h"

QEI::QEI(PinName channelA, PinName channelB, PinName index, int pulsesPerRev, Encoding encoding) : 
         channelA_(channelA), channelB_(channelB), index_(index) 
         {

    pulses_       = 0;
    revolutions_  = 0;
    pulsesPerRev_ = pulsesPerRev;
    encoding_     = encoding;

    //Workout what the current state is.
    int chanA = channelA_.read();
    int chanB = channelB_.read();

    //2-bit state.
    currState_ = (chanA << 1) | (chanB);
    prevState_ = currState_;

    //X2 encoding uses interrupts on only channel A.
    //X4 encoding uses interrupts on      channel A,
    //and on channel B.
    channelA_.rise(this, &QEI::encode);
    channelA_.fall(this, &QEI::encode);

    //If we're using X4 encoding, then attach interrupts to channel B too.
    if (encoding == X4_ENCODING) {
        channelB_.rise(this, &QEI::encode);
        channelB_.fall(this, &QEI::encode);
    }
    //Index is optional.
    if (index !=  NC) {
        index_.rise(this, &QEI::index);
    }

}

void QEI::reset(void) {

    pulses_      = 0;
    revolutions_ = 0;

}

int QEI::getCurrentState(void) {

    return currState_;

}

int QEI::getPulses(void) {

    return pulses_;

}

int QEI::getRevolutions(void) {

    return revolutions_;

}

// +-------------+
// | X2 Encoding |
// +-------------+
//
// When observing states two patterns will appear:
//
// Counter clockwise rotation:
//
// 10 -> 01 -> 10 -> 01 -> ...
//
// Clockwise rotation:
//
// 11 -> 00 -> 11 -> 00 -> ...
//
// We consider counter clockwise rotation to be "forward" and
// counter clockwise to be "backward". Therefore pulse count will increase
// during counter clockwise rotation and decrease during clockwise rotation.
//
// +-------------+
// | X4 Encoding |
// +-------------+
//
// There are four possible states for a quadrature encoder which correspond to
// 2-bit gray code.
//
// A state change is only valid if of only one bit has changed.
// A state change is invalid if both bits have changed.
//
// Clockwise Rotation ->
//
//    00 01 11 10 00
//
// <- Counter Clockwise Rotation
//
// If we observe any valid state changes going from left to right, we have
// moved one pulse clockwise [we will consider this "backward" or "negative"].
//
// If we observe any valid state changes going from right to left we have
// moved one pulse counter clockwise [we will consider this "forward" or
// "positive"].
//
// We might enter an invalid state for a number of reasons which are hard to
// predict - if this is the case, it is generally safe to ignore it, update
// the state and carry on, with the error correcting itself shortly after.
void QEI::encode(void) {

    int change = 0;
    int chanA  = channelA_.read();
    int chanB  = channelB_.read();

    //2-bit state.
    currState_ = (chanA << 1) | (chanB);

    if (encoding_ == X2_ENCODING) {

        //11->00->11->00 is counter clockwise rotation or "forward". If it follows the sequence, then pulses ++
        if ((prevState_ == 0x3 && currState_ == 0x0) ||
            (prevState_ == 0x0 && currState_ == 0x3)) {

            pulses_++;

        }
        //10->01->10->01 is clockwise rotation or "backward".
        else if ((prevState_ == 0x2 && currState_ == 0x1) ||
                 (prevState_ == 0x1 && currState_ == 0x2)) {

            pulses_--;

        }

    } else if (encoding_ == X4_ENCODING) {

        //Entered a new valid state.
        if (((currState_ ^ prevState_) != INVALID) && (currState_ != prevState_)) {
            //2 bit state. Right hand bit of prev XOR left hand bit of current
            //gives 0 if clockwise rotation and 1 if counter clockwise rotation.
            change = (prevState_ & PREV_MASK) ^ ((currState_ & CURR_MASK) >> 1);

            if (change == 0) {
                change = -1;
            }

            pulses_ -= change;
        }

    }

    prevState_ = currState_;

}

void QEI::index(void) {

    revolutions_++;

}