Quadrature encoder interface by Aaron Berk

Dependents:   TEST_ENCODER

Fork of QEI by Aaron Berk

Committer:
aminomar
Date:
Wed May 04 18:47:39 2016 +0000
Revision:
1:5f28ceec8280
Parent:
0:5c2ad81551aa
test encoder;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
aberk 0:5c2ad81551aa 1
aberk 0:5c2ad81551aa 2 #include "QEI.h"
aberk 0:5c2ad81551aa 3
aminomar 1:5f28ceec8280 4 QEI::QEI(PinName channelA, PinName channelB, PinName index, int pulsesPerRev, Encoding encoding) :
aminomar 1:5f28ceec8280 5 channelA_(channelA), channelB_(channelB), index_(index)
aminomar 1:5f28ceec8280 6 {
aberk 0:5c2ad81551aa 7
aberk 0:5c2ad81551aa 8 pulses_ = 0;
aberk 0:5c2ad81551aa 9 revolutions_ = 0;
aberk 0:5c2ad81551aa 10 pulsesPerRev_ = pulsesPerRev;
aberk 0:5c2ad81551aa 11 encoding_ = encoding;
aberk 0:5c2ad81551aa 12
aberk 0:5c2ad81551aa 13 //Workout what the current state is.
aberk 0:5c2ad81551aa 14 int chanA = channelA_.read();
aberk 0:5c2ad81551aa 15 int chanB = channelB_.read();
aberk 0:5c2ad81551aa 16
aberk 0:5c2ad81551aa 17 //2-bit state.
aberk 0:5c2ad81551aa 18 currState_ = (chanA << 1) | (chanB);
aberk 0:5c2ad81551aa 19 prevState_ = currState_;
aberk 0:5c2ad81551aa 20
aberk 0:5c2ad81551aa 21 //X2 encoding uses interrupts on only channel A.
aberk 0:5c2ad81551aa 22 //X4 encoding uses interrupts on channel A,
aberk 0:5c2ad81551aa 23 //and on channel B.
aberk 0:5c2ad81551aa 24 channelA_.rise(this, &QEI::encode);
aberk 0:5c2ad81551aa 25 channelA_.fall(this, &QEI::encode);
aberk 0:5c2ad81551aa 26
aberk 0:5c2ad81551aa 27 //If we're using X4 encoding, then attach interrupts to channel B too.
aberk 0:5c2ad81551aa 28 if (encoding == X4_ENCODING) {
aberk 0:5c2ad81551aa 29 channelB_.rise(this, &QEI::encode);
aberk 0:5c2ad81551aa 30 channelB_.fall(this, &QEI::encode);
aberk 0:5c2ad81551aa 31 }
aberk 0:5c2ad81551aa 32 //Index is optional.
aberk 0:5c2ad81551aa 33 if (index != NC) {
aberk 0:5c2ad81551aa 34 index_.rise(this, &QEI::index);
aberk 0:5c2ad81551aa 35 }
aberk 0:5c2ad81551aa 36
aberk 0:5c2ad81551aa 37 }
aberk 0:5c2ad81551aa 38
aberk 0:5c2ad81551aa 39 void QEI::reset(void) {
aberk 0:5c2ad81551aa 40
aberk 0:5c2ad81551aa 41 pulses_ = 0;
aberk 0:5c2ad81551aa 42 revolutions_ = 0;
aberk 0:5c2ad81551aa 43
aberk 0:5c2ad81551aa 44 }
aberk 0:5c2ad81551aa 45
aberk 0:5c2ad81551aa 46 int QEI::getCurrentState(void) {
aberk 0:5c2ad81551aa 47
aberk 0:5c2ad81551aa 48 return currState_;
aberk 0:5c2ad81551aa 49
aberk 0:5c2ad81551aa 50 }
aberk 0:5c2ad81551aa 51
aberk 0:5c2ad81551aa 52 int QEI::getPulses(void) {
aberk 0:5c2ad81551aa 53
aberk 0:5c2ad81551aa 54 return pulses_;
aberk 0:5c2ad81551aa 55
aberk 0:5c2ad81551aa 56 }
aberk 0:5c2ad81551aa 57
aberk 0:5c2ad81551aa 58 int QEI::getRevolutions(void) {
aberk 0:5c2ad81551aa 59
aberk 0:5c2ad81551aa 60 return revolutions_;
aberk 0:5c2ad81551aa 61
aberk 0:5c2ad81551aa 62 }
aberk 0:5c2ad81551aa 63
aberk 0:5c2ad81551aa 64 // +-------------+
aberk 0:5c2ad81551aa 65 // | X2 Encoding |
aberk 0:5c2ad81551aa 66 // +-------------+
aberk 0:5c2ad81551aa 67 //
aberk 0:5c2ad81551aa 68 // When observing states two patterns will appear:
aberk 0:5c2ad81551aa 69 //
aberk 0:5c2ad81551aa 70 // Counter clockwise rotation:
aberk 0:5c2ad81551aa 71 //
aberk 0:5c2ad81551aa 72 // 10 -> 01 -> 10 -> 01 -> ...
aberk 0:5c2ad81551aa 73 //
aberk 0:5c2ad81551aa 74 // Clockwise rotation:
aberk 0:5c2ad81551aa 75 //
aberk 0:5c2ad81551aa 76 // 11 -> 00 -> 11 -> 00 -> ...
aberk 0:5c2ad81551aa 77 //
aberk 0:5c2ad81551aa 78 // We consider counter clockwise rotation to be "forward" and
aberk 0:5c2ad81551aa 79 // counter clockwise to be "backward". Therefore pulse count will increase
aberk 0:5c2ad81551aa 80 // during counter clockwise rotation and decrease during clockwise rotation.
aberk 0:5c2ad81551aa 81 //
aberk 0:5c2ad81551aa 82 // +-------------+
aberk 0:5c2ad81551aa 83 // | X4 Encoding |
aberk 0:5c2ad81551aa 84 // +-------------+
aberk 0:5c2ad81551aa 85 //
aberk 0:5c2ad81551aa 86 // There are four possible states for a quadrature encoder which correspond to
aberk 0:5c2ad81551aa 87 // 2-bit gray code.
aberk 0:5c2ad81551aa 88 //
aberk 0:5c2ad81551aa 89 // A state change is only valid if of only one bit has changed.
aberk 0:5c2ad81551aa 90 // A state change is invalid if both bits have changed.
aberk 0:5c2ad81551aa 91 //
aberk 0:5c2ad81551aa 92 // Clockwise Rotation ->
aberk 0:5c2ad81551aa 93 //
aberk 0:5c2ad81551aa 94 // 00 01 11 10 00
aberk 0:5c2ad81551aa 95 //
aberk 0:5c2ad81551aa 96 // <- Counter Clockwise Rotation
aberk 0:5c2ad81551aa 97 //
aberk 0:5c2ad81551aa 98 // If we observe any valid state changes going from left to right, we have
aberk 0:5c2ad81551aa 99 // moved one pulse clockwise [we will consider this "backward" or "negative"].
aberk 0:5c2ad81551aa 100 //
aberk 0:5c2ad81551aa 101 // If we observe any valid state changes going from right to left we have
aberk 0:5c2ad81551aa 102 // moved one pulse counter clockwise [we will consider this "forward" or
aberk 0:5c2ad81551aa 103 // "positive"].
aberk 0:5c2ad81551aa 104 //
aberk 0:5c2ad81551aa 105 // We might enter an invalid state for a number of reasons which are hard to
aberk 0:5c2ad81551aa 106 // predict - if this is the case, it is generally safe to ignore it, update
aberk 0:5c2ad81551aa 107 // the state and carry on, with the error correcting itself shortly after.
aberk 0:5c2ad81551aa 108 void QEI::encode(void) {
aberk 0:5c2ad81551aa 109
aberk 0:5c2ad81551aa 110 int change = 0;
aberk 0:5c2ad81551aa 111 int chanA = channelA_.read();
aberk 0:5c2ad81551aa 112 int chanB = channelB_.read();
aberk 0:5c2ad81551aa 113
aberk 0:5c2ad81551aa 114 //2-bit state.
aberk 0:5c2ad81551aa 115 currState_ = (chanA << 1) | (chanB);
aberk 0:5c2ad81551aa 116
aberk 0:5c2ad81551aa 117 if (encoding_ == X2_ENCODING) {
aberk 0:5c2ad81551aa 118
aminomar 1:5f28ceec8280 119 //11->00->11->00 is counter clockwise rotation or "forward". If it follows the sequence, then pulses ++
aberk 0:5c2ad81551aa 120 if ((prevState_ == 0x3 && currState_ == 0x0) ||
aminomar 1:5f28ceec8280 121 (prevState_ == 0x0 && currState_ == 0x3)) {
aberk 0:5c2ad81551aa 122
aberk 0:5c2ad81551aa 123 pulses_++;
aberk 0:5c2ad81551aa 124
aberk 0:5c2ad81551aa 125 }
aberk 0:5c2ad81551aa 126 //10->01->10->01 is clockwise rotation or "backward".
aberk 0:5c2ad81551aa 127 else if ((prevState_ == 0x2 && currState_ == 0x1) ||
aberk 0:5c2ad81551aa 128 (prevState_ == 0x1 && currState_ == 0x2)) {
aberk 0:5c2ad81551aa 129
aberk 0:5c2ad81551aa 130 pulses_--;
aberk 0:5c2ad81551aa 131
aberk 0:5c2ad81551aa 132 }
aberk 0:5c2ad81551aa 133
aberk 0:5c2ad81551aa 134 } else if (encoding_ == X4_ENCODING) {
aberk 0:5c2ad81551aa 135
aberk 0:5c2ad81551aa 136 //Entered a new valid state.
aberk 0:5c2ad81551aa 137 if (((currState_ ^ prevState_) != INVALID) && (currState_ != prevState_)) {
aberk 0:5c2ad81551aa 138 //2 bit state. Right hand bit of prev XOR left hand bit of current
aberk 0:5c2ad81551aa 139 //gives 0 if clockwise rotation and 1 if counter clockwise rotation.
aberk 0:5c2ad81551aa 140 change = (prevState_ & PREV_MASK) ^ ((currState_ & CURR_MASK) >> 1);
aberk 0:5c2ad81551aa 141
aberk 0:5c2ad81551aa 142 if (change == 0) {
aberk 0:5c2ad81551aa 143 change = -1;
aberk 0:5c2ad81551aa 144 }
aberk 0:5c2ad81551aa 145
aberk 0:5c2ad81551aa 146 pulses_ -= change;
aberk 0:5c2ad81551aa 147 }
aberk 0:5c2ad81551aa 148
aberk 0:5c2ad81551aa 149 }
aberk 0:5c2ad81551aa 150
aberk 0:5c2ad81551aa 151 prevState_ = currState_;
aberk 0:5c2ad81551aa 152
aberk 0:5c2ad81551aa 153 }
aberk 0:5c2ad81551aa 154
aberk 0:5c2ad81551aa 155 void QEI::index(void) {
aberk 0:5c2ad81551aa 156
aberk 0:5c2ad81551aa 157 revolutions_++;
aberk 0:5c2ad81551aa 158
aberk 0:5c2ad81551aa 159 }