Simon Ford
/
LabVIEW_PID
Simple PID example for LabVIEW
QEI.cpp
- Committer:
- simon
- Date:
- 2010-08-03
- Revision:
- 1:ddfe18427154
- Parent:
- 0:e3b759ab4b5c
File content as of revision 1:ddfe18427154:
//****************************************************************************/ //@section LICENSE // //Copyright (c) 2010 ARM Limited // //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal //in the Software without restriction, including without limitation the rights //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //copies of the Software, and to permit persons to whom the Software is //furnished to do so, subject to the following conditions: // //The above copyright notice and this permission notice shall be included in //all copies or substantial portions of the Software. // //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //THE SOFTWARE. //****************************************************************************/ //@section DESCRIPTION // // Quadrature Encoder Interface. // // A quadrature encoder consists of two code tracks on a disc which are 90 // degrees out of phase. It can be used to determine how far a wheel has // rotated, relative to a known starting position. // // Only one code track changes at a time leading to a more robust system than // a single track, because any jitter around any edge won't cause a state // change as the other track will remain constant. // // Encoders can be a homebrew affair, consisting of infrared emitters/receivers // and paper code tracks consisting of alternating black and white sections; // alternatively, complete disk and PCB emitter/receiver encoder systems can // be bought, but the interface, regardless of implementation is the same. // // +-----+ +-----+ +-----+ // Channel A | ^ | | | | | // ---+ ^ +-----+ +-----+ +----- // ^ ^ // ^ +-----+ +-----+ +-----+ // Channel B ^ | | | | | | // ------+ +-----+ +-----+ +----- // ^ ^ // ^ ^ // 90deg // // This interface uses X4 encoding which calculates the pulse count based on // reading the current state after each rising and falling edge of either // channel. // // +-----+ +-----+ +-----+ // Channel A | | | | | | // ---+ +-----+ +-----+ +----- // ^ ^ ^ ^ ^ // ^ +-----+ ^ +-----+ ^ +-----+ // Channel B ^ | ^ | ^ | ^ | ^ | | // ------+ ^ +-----+ ^ +-----+ +-- // ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ // ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ // Pulse count 0 1 2 3 4 5 6 7 8 9 ... // // An optional index channel can be used which determines when a full // revolution has occured. // // If a 4 pules per revolution encoder was used, the following would be // observed. // // +-----+ +-----+ +-----+ // Channel A | | | | | | // ---+ +-----+ +-----+ +----- // ^ ^ ^ ^ ^ // ^ +-----+ ^ +-----+ ^ +-----+ // Channel B ^ | ^ | ^ | ^ | ^ | | // ------+ ^ +-----+ ^ +-----+ +-- // ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ // ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ // ^ ^ ^ +--+ ^ ^ +--+ ^ // ^ ^ ^ | | ^ ^ | | ^ // Index ------------+ +--------+ +----------- // ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ // Pulse count 0 1 2 3 4 5 6 7 8 9 ... // Rev. count 0 1 2 // // Rotational position in degrees can be calculated by: // // (pulse count / X * N) * 360 // // Where X is the encoding type [in our case X=4], and N is the number of // pulses per revolution. // // Linear position can be calculated by: // // (pulse count / X * N) * (1 / PPI) // // Where X is encoding type [in our case X=4], N is the number of pulses per // revolution, and PPI is pulses per inch, or the equivalent for any other // unit of displacement. PPI can be calculated by taking the circumference // of the wheel or encoder disk and dividing it by the number of pulses per // revolution. //****************************************************************************/ //****************************************************************************/ // Includes //****************************************************************************/ #include "QEI.h" QEI::QEI(PinName channelA, PinName channelB, PinName index, int pulsesPerRev) { channelA_ = new InterruptIn(channelA); channelB_ = new InterruptIn(channelB); index_ = new InterruptIn(index); pulses_ = 0; revolutions_ = 0; pulsesPerRev_ = pulsesPerRev; //Workout what the current state is. int chanA = channelA_->read(); int chanB = channelB_->read(); //2-bit state. currState_ = (chanA << 1) | (chanB); prevState_ = currState_; channelA_->rise(this, &QEI::encode); channelA_->fall(this, &QEI::encode); 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_; } // 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); //Entered an invalid state, or no change. if ((currState_ ^ prevState_) == INVALID || currState_ == prevState_) { //Even if the state was invalid, it will eventually //correct itself if we simply update the state. prevState_ = currState_; } //Entered a valid state. else { //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_++; }