Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of QEI by
QEI.cpp
00001 /** 00002 * @author Aaron Berk 00003 * 00004 * @section LICENSE 00005 * 00006 * Copyright (c) 2010 ARM Limited 00007 * 00008 * Permission is hereby granted, free of charge, to any person obtaining a copy 00009 * of this software and associated documentation files (the "Software"), to deal 00010 * in the Software without restriction, including without limitation the rights 00011 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00012 * copies of the Software, and to permit persons to whom the Software is 00013 * furnished to do so, subject to the following conditions: 00014 * 00015 * The above copyright notice and this permission notice shall be included in 00016 * all copies or substantial portions of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00019 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00020 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00021 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00022 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00023 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00024 * THE SOFTWARE. 00025 * 00026 * @section DESCRIPTION 00027 * 00028 * Quadrature Encoder Interface. 00029 * 00030 * A quadrature encoder consists of two code tracks on a disc which are 90 00031 * degrees out of phase. It can be used to determine how far a wheel has 00032 * rotated, relative to a known starting position. 00033 * 00034 * Only one code track changes at a time leading to a more robust system than 00035 * a single track, because any jitter around any edge won't cause a state 00036 * change as the other track will remain constant. 00037 * 00038 * Encoders can be a homebrew affair, consisting of infrared emitters/receivers 00039 * and paper code tracks consisting of alternating black and white sections; 00040 * alternatively, complete disk and PCB emitter/receiver encoder systems can 00041 * be bought, but the interface, regardless of implementation is the same. 00042 * 00043 * +-----+ +-----+ +-----+ 00044 * Channel A | ^ | | | | | 00045 * ---+ ^ +-----+ +-----+ +----- 00046 * ^ ^ 00047 * ^ +-----+ +-----+ +-----+ 00048 * Channel B ^ | | | | | | 00049 * ------+ +-----+ +-----+ +----- 00050 * ^ ^ 00051 * ^ ^ 00052 * 90deg 00053 * 00054 * The interface uses X2 encoding by default which calculates the pulse count 00055 * based on reading the current state after each rising and falling edge of 00056 * channel A. 00057 * 00058 * +-----+ +-----+ +-----+ 00059 * Channel A | | | | | | 00060 * ---+ +-----+ +-----+ +----- 00061 * ^ ^ ^ ^ ^ 00062 * ^ +-----+ ^ +-----+ ^ +-----+ 00063 * Channel B ^ | ^ | ^ | ^ | ^ | | 00064 * ------+ ^ +-----+ ^ +-----+ +-- 00065 * ^ ^ ^ ^ ^ 00066 * ^ ^ ^ ^ ^ 00067 * Pulse count 0 1 2 3 4 5 ... 00068 * 00069 * This interface can also use X4 encoding which calculates the pulse count 00070 * based on reading the current state after each rising and falling edge of 00071 * either channel. 00072 * 00073 * +-----+ +-----+ +-----+ 00074 * Channel A | | | | | | 00075 * ---+ +-----+ +-----+ +----- 00076 * ^ ^ ^ ^ ^ 00077 * ^ +-----+ ^ +-----+ ^ +-----+ 00078 * Channel B ^ | ^ | ^ | ^ | ^ | | 00079 * ------+ ^ +-----+ ^ +-----+ +-- 00080 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 00081 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 00082 * Pulse count 0 1 2 3 4 5 6 7 8 9 ... 00083 * 00084 * It defaults 00085 * 00086 * An optional index channel can be used which determines when a full 00087 * revolution has occured. 00088 * 00089 * If a 4 pules per revolution encoder was used, with X4 encoding, 00090 * the following would be observed. 00091 * 00092 * +-----+ +-----+ +-----+ 00093 * Channel A | | | | | | 00094 * ---+ +-----+ +-----+ +----- 00095 * ^ ^ ^ ^ ^ 00096 * ^ +-----+ ^ +-----+ ^ +-----+ 00097 * Channel B ^ | ^ | ^ | ^ | ^ | | 00098 * ------+ ^ +-----+ ^ +-----+ +-- 00099 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 00100 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 00101 * ^ ^ ^ +--+ ^ ^ +--+ ^ 00102 * ^ ^ ^ | | ^ ^ | | ^ 00103 * Index ------------+ +--------+ +----------- 00104 * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 00105 * Pulse count 0 1 2 3 4 5 6 7 8 9 ... 00106 * Rev. count 0 1 2 00107 * 00108 * Rotational position in degrees can be calculated by: 00109 * 00110 * (pulse count / X * N) * 360 00111 * 00112 * Where X is the encoding type [e.g. X4 encoding => X=4], and N is the number 00113 * of pulses per revolution. 00114 * 00115 * Linear position can be calculated by: 00116 * 00117 * (pulse count / X * N) * (1 / PPI) 00118 * 00119 * Where X is encoding type [e.g. X4 encoding => X=44], N is the number of 00120 * pulses per revolution, and PPI is pulses per inch, or the equivalent for 00121 * any other unit of displacement. PPI can be calculated by taking the 00122 * circumference of the wheel or encoder disk and dividing it by the number 00123 * of pulses per revolution. 00124 */ 00125 00126 /** 00127 * Includes 00128 */ 00129 #include "QEI.h" 00130 00131 QEI::QEI(PinName channelA, 00132 PinName channelB, 00133 PinName index, 00134 int pulsesPerRev, 00135 Encoding encoding) : channelA_(channelA), channelB_(channelB), 00136 index_(index) 00137 { 00138 00139 pulses_ = 0; 00140 revolutions_ = 0; 00141 pulsesPerRev_ = pulsesPerRev; 00142 encoding_ = encoding; 00143 firstZ = true; 00144 00145 //Workout what the current state is. 00146 int chanA = channelA_.read(); 00147 int chanB = channelB_.read(); 00148 00149 //2-bit state. 00150 currState_ = (chanA << 1) | (chanB); 00151 prevState_ = currState_; 00152 00153 //X2 encoding uses interrupts on only channel A. 00154 //X4 encoding uses interrupts on channel A, 00155 //and on channel B. 00156 channelA_.rise(this, &QEI::encode); 00157 channelA_.fall(this, &QEI::encode); 00158 00159 //If we're using X4 encoding, then attach interrupts to channel B too. 00160 if (encoding == X4_ENCODING) { 00161 channelB_.rise(this, &QEI::encode); 00162 channelB_.fall(this, &QEI::encode); 00163 pulsesPerRev_ *= 2; 00164 } 00165 //Index is optional. 00166 if (index != NC) { 00167 index_.rise(this, &QEI::index); 00168 } 00169 } 00170 00171 void QEI::reset(void) 00172 { 00173 00174 pulses_ = 0; 00175 revolutions_ = 0; 00176 firstZ = true; 00177 00178 } 00179 00180 int QEI::getCurrentState(void) 00181 { 00182 00183 return currState_; 00184 00185 } 00186 00187 int QEI::getPulses(void) 00188 { 00189 00190 return pulses_; 00191 00192 } 00193 00194 int QEI::getRevolutions(void) 00195 { 00196 00197 return revolutions_; 00198 00199 } 00200 00201 // +-------------+ 00202 // | X2 Encoding | 00203 // +-------------+ 00204 // 00205 // When observing states two patterns will appear: 00206 // 00207 // Counter clockwise rotation: 00208 // 00209 // 10 -> 01 -> 10 -> 01 -> ... 00210 // 00211 // Clockwise rotation: 00212 // 00213 // 11 -> 00 -> 11 -> 00 -> ... 00214 // 00215 // We consider counter clockwise rotation to be "forward" and 00216 // counter clockwise to be "backward". Therefore pulse count will increase 00217 // during counter clockwise rotation and decrease during clockwise rotation. 00218 // 00219 // +-------------+ 00220 // | X4 Encoding | 00221 // +-------------+ 00222 // 00223 // There are four possible states for a quadrature encoder which correspond to 00224 // 2-bit gray code. 00225 // 00226 // A state change is only valid if of only one bit has changed. 00227 // A state change is invalid if both bits have changed. 00228 // 00229 // Clockwise Rotation -> 00230 // 00231 // 00 01 11 10 00 00232 // 00233 // <- Counter Clockwise Rotation 00234 // 00235 // If we observe any valid state changes going from left to right, we have 00236 // moved one pulse clockwise [we will consider this "backward" or "negative"]. 00237 // 00238 // If we observe any valid state changes going from right to left we have 00239 // moved one pulse counter clockwise [we will consider this "forward" or 00240 // "positive"]. 00241 // 00242 // We might enter an invalid state for a number of reasons which are hard to 00243 // predict - if this is the case, it is generally safe to ignore it, update 00244 // the state and carry on, with the error correcting itself shortly after. 00245 void QEI::encode(void) 00246 { 00247 00248 int change = 0; 00249 int chanA = channelA_.read(); 00250 int chanB = channelB_.read(); 00251 00252 //2-bit state. 00253 currState_ = (chanA << 1) | (chanB); 00254 00255 if (encoding_ == X2_ENCODING) { 00256 00257 //11->00->11->00 is counter clockwise rotation or "forward". 00258 if ((prevState_ == 0x3 && currState_ == 0x0) || 00259 (prevState_ == 0x0 && currState_ == 0x3)) { 00260 00261 pulses_++; 00262 00263 } 00264 //10->01->10->01 is clockwise rotation or "backward". 00265 else if ((prevState_ == 0x2 && currState_ == 0x1) || 00266 (prevState_ == 0x1 && currState_ == 0x2)) { 00267 00268 pulses_--; 00269 00270 } 00271 00272 } else if (encoding_ == X4_ENCODING) { 00273 00274 //Entered a new valid state. 00275 if (((currState_ ^ prevState_) != INVALID) && (currState_ != prevState_)) { 00276 //2 bit state. Right hand bit of prev XOR left hand bit of current 00277 //gives 0 if clockwise rotation and 1 if counter clockwise rotation. 00278 change = (prevState_ & PREV_MASK) ^ ((currState_ & CURR_MASK) >> 1); 00279 00280 if (change == 0) { 00281 change = -1; 00282 } 00283 00284 pulses_ -= change; 00285 } 00286 00287 } 00288 00289 prevState_ = currState_; 00290 00291 } 00292 00293 void QEI::index(void) 00294 { 00295 if(firstZ){ 00296 Zshift = pulses_; 00297 firstZ = false; 00298 } 00299 revolutions_++; 00300 int pls = pulses_ - Zshift; 00301 int x = pls % pulsesPerRev_; 00302 int y = pls / pulsesPerRev_; 00303 if (pls > 0) { 00304 if (x > pulsesPerRev_ / 2) { 00305 y++; 00306 } 00307 } else { 00308 if (x < pulsesPerRev_ / -2) { 00309 y--; 00310 } 00311 } 00312 00313 pulses_ = pulsesPerRev_ * y + Zshift; 00314 00315 }
Generated on Mon Aug 22 2022 06:14:15 by
