Quadrature Encoder Interface for motion control with resistance to jitter and chatter on AB signals and motor vibrations
Dependents: QEIx4_Example realtimeMM_V3 realtimeMM_V3
Quadrature Encoder Interface for Motion Control.
A class to decode pulses on a rotary encoder with AB signals (quadrature encoder). It uses all 4 edges of the AB signals to increase the counter resolution 4 times of cycles per rotation/revolution (CPR) (e.g. an encoder with 500 CPR get 2000 counts per rotation)
In opposite to most common QEI implementation this is resistant to jitter and chatter on AB signals and motor vibrations. When using interrupts (IRQ_NO_JAMMING-mode) only the needed edge and pin is activated to prevent jamming CPU time with unnecessary interrupts. Whes reaching the next position the edge that triggerd this position (state) is ignored to aboid oscillating up/down counts.
It can also be used in polling mode i.g. in idle routines if interrupts are not desired. At this mode be sure that the sampling frequency is heigher than the maximum rotation speed (expeced counts per second)
The internal state machine is based on a look up table (LUT) to minimize interrupt retention time and get all necessary flags at once.
Additional the rotation speed of the encoder can be measured. The algorithm is based on the measuring time between the edges to get a very precise speed at very slow rotation.
The library is designed to support closed loop speed- and motion-controller for also slow and smooth motions like movie camera motion control.
Quadrature Encoder Signals:
(+) Count UP; (-) Count DOWN
QEIx4.h@2:c0b87b11b9cd, 2014-10-01 (annotated)
- Committer:
- jocis
- Date:
- Wed Oct 01 10:23:21 2014 +0000
- Revision:
- 2:c0b87b11b9cd
- Parent:
- 1:ac6b7b1bf6c5
replaced virtual functions by attached functions; added documentation
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jocis | 1:ac6b7b1bf6c5 | 1 | /* |
jocis | 0:46b8d5680f66 | 2 | * @author Jochen Krapf |
jocis | 1:ac6b7b1bf6c5 | 3 | * parts by Andy Kirkham |
jocis | 0:46b8d5680f66 | 4 | * |
jocis | 0:46b8d5680f66 | 5 | * @section LICENSE |
jocis | 0:46b8d5680f66 | 6 | * |
jocis | 1:ac6b7b1bf6c5 | 7 | * Copyright (c) 2014 Jochen Krapf, MIT License |
jocis | 0:46b8d5680f66 | 8 | * |
jocis | 0:46b8d5680f66 | 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software |
jocis | 0:46b8d5680f66 | 10 | * and associated documentation files (the "Software"), to deal in the Software without restriction, |
jocis | 0:46b8d5680f66 | 11 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, |
jocis | 0:46b8d5680f66 | 12 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is |
jocis | 0:46b8d5680f66 | 13 | * furnished to do so, subject to the following conditions: |
jocis | 0:46b8d5680f66 | 14 | * |
jocis | 0:46b8d5680f66 | 15 | * The above copyright notice and this permission notice shall be included in all copies or |
jocis | 0:46b8d5680f66 | 16 | * substantial portions of the Software. |
jocis | 0:46b8d5680f66 | 17 | * |
jocis | 0:46b8d5680f66 | 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
jocis | 0:46b8d5680f66 | 19 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
jocis | 0:46b8d5680f66 | 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
jocis | 0:46b8d5680f66 | 21 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
jocis | 0:46b8d5680f66 | 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
jocis | 0:46b8d5680f66 | 23 | * |
jocis | 0:46b8d5680f66 | 24 | * @section DESCRIPTION |
jocis | 1:ac6b7b1bf6c5 | 25 | * mbed QEI (quadrature encoder interface) library, for decoding AB signals from a rotary encoder |
jocis | 0:46b8d5680f66 | 26 | * |
jocis | 0:46b8d5680f66 | 27 | * Use cases: |
jocis | 0:46b8d5680f66 | 28 | * - Rotary encoder in closed loop motor regulation |
jocis | 0:46b8d5680f66 | 29 | * - Hand wheel |
jocis | 0:46b8d5680f66 | 30 | * - Input device for motion control (MoCo) |
jocis | 0:46b8d5680f66 | 31 | */ |
jocis | 0:46b8d5680f66 | 32 | |
jocis | 0:46b8d5680f66 | 33 | #include "mbed.h" |
jocis | 1:ac6b7b1bf6c5 | 34 | #include "FPointer_vi.h" |
jocis | 0:46b8d5680f66 | 35 | |
jocis | 2:c0b87b11b9cd | 36 | /** Quadrature Encoder Interface for Motion Control. |
jocis | 1:ac6b7b1bf6c5 | 37 | * |
jocis | 2:c0b87b11b9cd | 38 | * A class to decode pulses on a rotary encoder with AB signals (quadrature encoder). |
jocis | 2:c0b87b11b9cd | 39 | * It uses all 4 edges of the AB signals to increase the counter resolution 4 times of cycles per rotation/revolution (CPR) (e.g. an encoder with 500 CPR get 2000 counts per rotation) |
jocis | 1:ac6b7b1bf6c5 | 40 | * |
jocis | 2:c0b87b11b9cd | 41 | * In opposite to most common QEI implementation this is resistant to jitter and chatter on AB signals and motor vibrations. |
jocis | 2:c0b87b11b9cd | 42 | * When using interrupts (IRQ_NO_JAMMING-mode) only the needed edge and pin is activated to prevent jamming CPU time with unnecessary interrupts. |
jocis | 2:c0b87b11b9cd | 43 | * Whes reaching the next position the edge that triggerd this position (state) is ignored to aboid oscillating up/down counts. |
jocis | 0:46b8d5680f66 | 44 | * |
jocis | 2:c0b87b11b9cd | 45 | * It can also be used in polling mode i.g. in idle routines if interrupts are not desired. |
jocis | 2:c0b87b11b9cd | 46 | * At this mode be sure that the sampling frequency is heigher than the maximum rotation speed (expeced counts per second) |
jocis | 1:ac6b7b1bf6c5 | 47 | * |
jocis | 1:ac6b7b1bf6c5 | 48 | * The internal state machine is based on a look up table (LUT) to minimize interrupt retention time and get all necessary flags at once. |
jocis | 0:46b8d5680f66 | 49 | * |
jocis | 1:ac6b7b1bf6c5 | 50 | * Additional the rotation speed of the encoder can be measured. The algorithm is based on the measuring time between the edges to get a very precise speed at very slow rotation. |
jocis | 1:ac6b7b1bf6c5 | 51 | * |
jocis | 1:ac6b7b1bf6c5 | 52 | * The library is designed to support closed loop speed- and motion-controller for also slow and smooth motions like movie camera motion control. |
jocis | 0:46b8d5680f66 | 53 | * |
jocis | 0:46b8d5680f66 | 54 | * Example: |
jocis | 0:46b8d5680f66 | 55 | * |
jocis | 0:46b8d5680f66 | 56 | * @code |
jocis | 0:46b8d5680f66 | 57 | #include "mbed.h" |
jocis | 0:46b8d5680f66 | 58 | #include "QEIx4.h" |
jocis | 0:46b8d5680f66 | 59 | |
jocis | 2:c0b87b11b9cd | 60 | DigitalOut LEDalive(LED1); |
jocis | 2:c0b87b11b9cd | 61 | DigitalOut LEDzero(LED2); |
jocis | 2:c0b87b11b9cd | 62 | DigitalOut LEDup(LED4); |
jocis | 2:c0b87b11b9cd | 63 | DigitalOut LEDdown(LED3); |
jocis | 2:c0b87b11b9cd | 64 | |
jocis | 2:c0b87b11b9cd | 65 | Timer t; // timer for polling |
jocis | 0:46b8d5680f66 | 66 | |
jocis | 0:46b8d5680f66 | 67 | // ports for nxp LPC 1768 |
jocis | 2:c0b87b11b9cd | 68 | QEIx4 qei1(p30, p29, p28, (QEIx4::EMODE)(QEIx4::IRQ | QEIx4::SPEED)); // QEI with index signal for zeroing |
jocis | 2:c0b87b11b9cd | 69 | QEIx4 qei2(p21, p22, NC, QEIx4::IRQ_NO_JAMMING); // QEI with AB signals only |
jocis | 2:c0b87b11b9cd | 70 | QEIx4 qei3(p25, p24, NC, QEIx4::POLLING); // QEI without interrups in polling mode |
jocis | 2:c0b87b11b9cd | 71 | |
jocis | 2:c0b87b11b9cd | 72 | // The callback functions |
jocis | 2:c0b87b11b9cd | 73 | void myCounterChangeCallback(int value) |
jocis | 2:c0b87b11b9cd | 74 | { |
jocis | 2:c0b87b11b9cd | 75 | static int valueLast=-1; |
jocis | 0:46b8d5680f66 | 76 | |
jocis | 2:c0b87b11b9cd | 77 | if ( value > valueLast ) { |
jocis | 2:c0b87b11b9cd | 78 | LEDup = !LEDup; |
jocis | 2:c0b87b11b9cd | 79 | LEDdown = 0; |
jocis | 2:c0b87b11b9cd | 80 | } else { |
jocis | 2:c0b87b11b9cd | 81 | LEDdown = !LEDdown; |
jocis | 2:c0b87b11b9cd | 82 | LEDup = 0; |
jocis | 2:c0b87b11b9cd | 83 | } |
jocis | 2:c0b87b11b9cd | 84 | valueLast = value; |
jocis | 2:c0b87b11b9cd | 85 | } |
jocis | 2:c0b87b11b9cd | 86 | |
jocis | 2:c0b87b11b9cd | 87 | void myIndexTriggerCallback(int value) |
jocis | 2:c0b87b11b9cd | 88 | { |
jocis | 2:c0b87b11b9cd | 89 | qei1 = 0; // reset counter |
jocis | 2:c0b87b11b9cd | 90 | LEDzero = 1; |
jocis | 2:c0b87b11b9cd | 91 | } |
jocis | 2:c0b87b11b9cd | 92 | |
jocis | 2:c0b87b11b9cd | 93 | int main() |
jocis | 2:c0b87b11b9cd | 94 | { |
jocis | 0:46b8d5680f66 | 95 | t.start(); |
jocis | 0:46b8d5680f66 | 96 | |
jocis | 2:c0b87b11b9cd | 97 | qei1.setIndexTrigger(true); // set the flag to zero counter on next index signal rises |
jocis | 2:c0b87b11b9cd | 98 | qei1.setSpeedFactor(1.0f); // factor to scale from Hz (edges pe second = 4 * CPS) to user units (1.0=Hz, 1/(4*CPR)=rps, 1/(60*4*CPR)=rpm, 360/(4*CPR)=°/s, ...) |
jocis | 2:c0b87b11b9cd | 99 | qei3.attachIndexTrigger(myIndexTriggerCallback); |
jocis | 2:c0b87b11b9cd | 100 | |
jocis | 2:c0b87b11b9cd | 101 | qei3.attachCounterChange(myCounterChangeCallback); |
jocis | 0:46b8d5680f66 | 102 | |
jocis | 2:c0b87b11b9cd | 103 | while(1) { |
jocis | 0:46b8d5680f66 | 104 | qei3.poll(); // poll manually without interrupt - sampling in this loop with about 2kHz |
jocis | 1:ac6b7b1bf6c5 | 105 | |
jocis | 2:c0b87b11b9cd | 106 | if ( t.read_ms() > 250 ) { // every quater second (4 Hz) |
jocis | 0:46b8d5680f66 | 107 | t.reset(); |
jocis | 0:46b8d5680f66 | 108 | t.start(); |
jocis | 2:c0b87b11b9cd | 109 | LEDalive = !LEDalive; |
jocis | 1:ac6b7b1bf6c5 | 110 | |
jocis | 2:c0b87b11b9cd | 111 | printf ( "\r\n%6d %6d %6d %10.3f", (int)qei1, (int)qei2, (int)qei3, (float)qei1.getSpeed() ); // print counter values |
jocis | 0:46b8d5680f66 | 112 | } |
jocis | 0:46b8d5680f66 | 113 | |
jocis | 2:c0b87b11b9cd | 114 | wait_us(20); // for about 50kHz polling |
jocis | 0:46b8d5680f66 | 115 | } |
jocis | 0:46b8d5680f66 | 116 | } |
jocis | 0:46b8d5680f66 | 117 | * @endcode |
jocis | 0:46b8d5680f66 | 118 | */ |
jocis | 1:ac6b7b1bf6c5 | 119 | class QEIx4 |
jocis | 1:ac6b7b1bf6c5 | 120 | { |
jocis | 0:46b8d5680f66 | 121 | public: |
jocis | 0:46b8d5680f66 | 122 | |
jocis | 1:ac6b7b1bf6c5 | 123 | typedef enum EMODE { |
jocis | 1:ac6b7b1bf6c5 | 124 | POLLING = 0, |
jocis | 1:ac6b7b1bf6c5 | 125 | IRQ = 1, |
jocis | 1:ac6b7b1bf6c5 | 126 | IRQ_NO_JAMMING = 2, |
jocis | 1:ac6b7b1bf6c5 | 127 | SPEED = 4, |
jocis | 1:ac6b7b1bf6c5 | 128 | } EMODE; |
jocis | 1:ac6b7b1bf6c5 | 129 | |
jocis | 0:46b8d5680f66 | 130 | /** constructor of QEIx4 object |
jocis | 0:46b8d5680f66 | 131 | * |
jocis | 0:46b8d5680f66 | 132 | * @param pinA Pin number of input/interrupt pin for encoder line A. All port pins are possible except p19 and p20 |
jocis | 0:46b8d5680f66 | 133 | * @param pinB Pin number of input/interrupt pin for encoder line B. All port pins are possible except p19 and p20 |
jocis | 0:46b8d5680f66 | 134 | * @param pinI Pin number of input pin for optional encoder index or reference switch. |
jocis | 1:ac6b7b1bf6c5 | 135 | * @param eMode Flag to use interrups to detect changes on line A and B. For none interrupt use mode POLLING and call the function poll() frequently. For optional speed calculation the mode SPEED can be ored |
jocis | 0:46b8d5680f66 | 136 | */ |
jocis | 1:ac6b7b1bf6c5 | 137 | QEIx4 ( PinName pinA, PinName pinB, PinName pinI=NC, EMODE eMode=IRQ ); |
jocis | 1:ac6b7b1bf6c5 | 138 | |
jocis | 0:46b8d5680f66 | 139 | /** destructor of QEIx4 object |
jocis | 0:46b8d5680f66 | 140 | */ |
jocis | 0:46b8d5680f66 | 141 | ~QEIx4(); |
jocis | 0:46b8d5680f66 | 142 | |
jocis | 0:46b8d5680f66 | 143 | /** Gets the actual counter value. |
jocis | 0:46b8d5680f66 | 144 | * |
jocis | 0:46b8d5680f66 | 145 | * @return Actual counter value |
jocis | 0:46b8d5680f66 | 146 | */ |
jocis | 1:ac6b7b1bf6c5 | 147 | int read() { |
jocis | 1:ac6b7b1bf6c5 | 148 | return _counter; |
jocis | 1:ac6b7b1bf6c5 | 149 | } |
jocis | 0:46b8d5680f66 | 150 | |
jocis | 0:46b8d5680f66 | 151 | /** Gets the actual counter value as int operator. |
jocis | 0:46b8d5680f66 | 152 | * |
jocis | 0:46b8d5680f66 | 153 | * @return Actual counter value as int operator |
jocis | 0:46b8d5680f66 | 154 | */ |
jocis | 1:ac6b7b1bf6c5 | 155 | operator int () { // int-Operator |
jocis | 1:ac6b7b1bf6c5 | 156 | return _counter; |
jocis | 1:ac6b7b1bf6c5 | 157 | } |
jocis | 1:ac6b7b1bf6c5 | 158 | |
jocis | 0:46b8d5680f66 | 159 | /** Sets the counter value at actual encoder position to given value. |
jocis | 0:46b8d5680f66 | 160 | * |
jocis | 0:46b8d5680f66 | 161 | * @param Counter value |
jocis | 0:46b8d5680f66 | 162 | */ |
jocis | 1:ac6b7b1bf6c5 | 163 | void write ( int counter ) { |
jocis | 1:ac6b7b1bf6c5 | 164 | _counter = counter; |
jocis | 1:ac6b7b1bf6c5 | 165 | } |
jocis | 1:ac6b7b1bf6c5 | 166 | |
jocis | 0:46b8d5680f66 | 167 | /** Sets the counter value at actual encoder position to given value as assign operator. |
jocis | 0:46b8d5680f66 | 168 | * |
jocis | 0:46b8d5680f66 | 169 | * @param Counter value |
jocis | 0:46b8d5680f66 | 170 | */ |
jocis | 1:ac6b7b1bf6c5 | 171 | int operator= ( int counter ) { // Assign-Operator |
jocis | 1:ac6b7b1bf6c5 | 172 | write(counter); |
jocis | 1:ac6b7b1bf6c5 | 173 | return counter; |
jocis | 1:ac6b7b1bf6c5 | 174 | } |
jocis | 1:ac6b7b1bf6c5 | 175 | |
jocis | 0:46b8d5680f66 | 176 | /** Polls the state machine manually and updates the counter value. |
jocis | 0:46b8d5680f66 | 177 | */ |
jocis | 1:ac6b7b1bf6c5 | 178 | void poll () { |
jocis | 1:ac6b7b1bf6c5 | 179 | ProcessISR(); |
jocis | 1:ac6b7b1bf6c5 | 180 | } |
jocis | 1:ac6b7b1bf6c5 | 181 | |
jocis | 2:c0b87b11b9cd | 182 | /** Sets the flag for zeroing on next high on index pin while AB lines triggers next counting. The trigger calls tha callback function in which the counter can be set to zero or the actual counter can be latched in for later offset calculation |
jocis | 0:46b8d5680f66 | 183 | * |
jocis | 2:c0b87b11b9cd | 184 | * @param Flag for triggering. Set to 1 for call the attached callback. It is reseted after this call |
jocis | 0:46b8d5680f66 | 185 | */ |
jocis | 2:c0b87b11b9cd | 186 | void setIndexTrigger ( bool bIndexTrigger ) { |
jocis | 2:c0b87b11b9cd | 187 | _bIndexTrigger = bIndexTrigger; |
jocis | 1:ac6b7b1bf6c5 | 188 | } |
jocis | 0:46b8d5680f66 | 189 | |
jocis | 1:ac6b7b1bf6c5 | 190 | /** attach - Overloaded attachment function. |
jocis | 1:ac6b7b1bf6c5 | 191 | * |
jocis | 1:ac6b7b1bf6c5 | 192 | * Attach a C type function pointer as the callback. |
jocis | 1:ac6b7b1bf6c5 | 193 | * |
jocis | 1:ac6b7b1bf6c5 | 194 | * Note, the callback function prototype must be:- |
jocis | 1:ac6b7b1bf6c5 | 195 | * @code |
jocis | 1:ac6b7b1bf6c5 | 196 | * void myCallbackFunction(int); |
jocis | 1:ac6b7b1bf6c5 | 197 | * @endcode |
jocis | 1:ac6b7b1bf6c5 | 198 | * @param A C function pointer to call. |
jocis | 1:ac6b7b1bf6c5 | 199 | */ |
jocis | 1:ac6b7b1bf6c5 | 200 | void attachCounterChange(void (*function)(int) = 0) { |
jocis | 1:ac6b7b1bf6c5 | 201 | fPointerCounterChange.attach (function); |
jocis | 1:ac6b7b1bf6c5 | 202 | } |
jocis | 1:ac6b7b1bf6c5 | 203 | |
jocis | 1:ac6b7b1bf6c5 | 204 | /** attachCounterChange - Overloaded attachment function. |
jocis | 1:ac6b7b1bf6c5 | 205 | * |
jocis | 1:ac6b7b1bf6c5 | 206 | * Attach a C++ type object/method pointer as the callback. |
jocis | 1:ac6b7b1bf6c5 | 207 | * |
jocis | 1:ac6b7b1bf6c5 | 208 | * Note, the callback method prototype must be:- |
jocis | 1:ac6b7b1bf6c5 | 209 | * @code |
jocis | 1:ac6b7b1bf6c5 | 210 | * public: |
jocis | 1:ac6b7b1bf6c5 | 211 | * static void myCallbackFunction(int); |
jocis | 1:ac6b7b1bf6c5 | 212 | * @endcode |
jocis | 1:ac6b7b1bf6c5 | 213 | * @param A C++ object pointer. |
jocis | 1:ac6b7b1bf6c5 | 214 | * @param A C++ method within the object to call. |
jocis | 1:ac6b7b1bf6c5 | 215 | */ |
jocis | 1:ac6b7b1bf6c5 | 216 | template<class T> |
jocis | 1:ac6b7b1bf6c5 | 217 | void attachCounterChange(T* item, void (T::*method)(int)) { |
jocis | 1:ac6b7b1bf6c5 | 218 | fPointerCounterChange.attach( item, method); |
jocis | 1:ac6b7b1bf6c5 | 219 | } |
jocis | 1:ac6b7b1bf6c5 | 220 | |
jocis | 1:ac6b7b1bf6c5 | 221 | /** attachDirectionChange - Overloaded attachment function. |
jocis | 1:ac6b7b1bf6c5 | 222 | * |
jocis | 1:ac6b7b1bf6c5 | 223 | * Attach a C type function pointer as the callback. |
jocis | 1:ac6b7b1bf6c5 | 224 | * |
jocis | 1:ac6b7b1bf6c5 | 225 | * Note, the callback function prototype must be:- |
jocis | 1:ac6b7b1bf6c5 | 226 | * @code |
jocis | 1:ac6b7b1bf6c5 | 227 | * void myCallbackFunction(int); |
jocis | 1:ac6b7b1bf6c5 | 228 | * @endcode |
jocis | 1:ac6b7b1bf6c5 | 229 | * @param A C function pointer to call. |
jocis | 1:ac6b7b1bf6c5 | 230 | */ |
jocis | 1:ac6b7b1bf6c5 | 231 | void attachDirectionChange(void (*function)(int) = 0) { |
jocis | 1:ac6b7b1bf6c5 | 232 | fPointerDirectionChange.attach (function); |
jocis | 1:ac6b7b1bf6c5 | 233 | } |
jocis | 1:ac6b7b1bf6c5 | 234 | |
jocis | 1:ac6b7b1bf6c5 | 235 | /** attachDirectionChange - Overloaded attachment function. |
jocis | 1:ac6b7b1bf6c5 | 236 | * |
jocis | 1:ac6b7b1bf6c5 | 237 | * Attach a C++ type object/method pointer as the callback. |
jocis | 1:ac6b7b1bf6c5 | 238 | * |
jocis | 1:ac6b7b1bf6c5 | 239 | * Note, the callback method prototype must be:- |
jocis | 1:ac6b7b1bf6c5 | 240 | * @code |
jocis | 1:ac6b7b1bf6c5 | 241 | * public: |
jocis | 1:ac6b7b1bf6c5 | 242 | * static void myCallbackFunction(int); |
jocis | 1:ac6b7b1bf6c5 | 243 | * @endcode |
jocis | 1:ac6b7b1bf6c5 | 244 | * @param A C++ object pointer. |
jocis | 1:ac6b7b1bf6c5 | 245 | * @param A C++ method within the object to call. |
jocis | 1:ac6b7b1bf6c5 | 246 | */ |
jocis | 1:ac6b7b1bf6c5 | 247 | template<class T> |
jocis | 1:ac6b7b1bf6c5 | 248 | void attachDirectionChange(T* item, void (T::*method)(int)) { |
jocis | 1:ac6b7b1bf6c5 | 249 | fPointerDirectionChange.attach( item, method); |
jocis | 1:ac6b7b1bf6c5 | 250 | } |
jocis | 1:ac6b7b1bf6c5 | 251 | |
jocis | 2:c0b87b11b9cd | 252 | /** attachIndexTrigger - Overloaded attachment function. |
jocis | 2:c0b87b11b9cd | 253 | * |
jocis | 2:c0b87b11b9cd | 254 | * Attach a C type function pointer as the callback. |
jocis | 2:c0b87b11b9cd | 255 | * |
jocis | 2:c0b87b11b9cd | 256 | * Note, the callback function prototype must be:- |
jocis | 2:c0b87b11b9cd | 257 | * @code |
jocis | 2:c0b87b11b9cd | 258 | * void myCallbackFunction(int); |
jocis | 2:c0b87b11b9cd | 259 | * @endcode |
jocis | 2:c0b87b11b9cd | 260 | * @param A C function pointer to call. |
jocis | 2:c0b87b11b9cd | 261 | */ |
jocis | 2:c0b87b11b9cd | 262 | void attachIndexTrigger(void (*function)(int) = 0) { |
jocis | 2:c0b87b11b9cd | 263 | fPointerIndexTrigger.attach (function); |
jocis | 2:c0b87b11b9cd | 264 | } |
jocis | 2:c0b87b11b9cd | 265 | |
jocis | 2:c0b87b11b9cd | 266 | /** attachIndexTrigger - Overloaded attachment function. |
jocis | 2:c0b87b11b9cd | 267 | * |
jocis | 2:c0b87b11b9cd | 268 | * Attach a C++ type object/method pointer as the callback. |
jocis | 2:c0b87b11b9cd | 269 | * |
jocis | 2:c0b87b11b9cd | 270 | * Note, the callback method prototype must be:- |
jocis | 2:c0b87b11b9cd | 271 | * @code |
jocis | 2:c0b87b11b9cd | 272 | * public: |
jocis | 2:c0b87b11b9cd | 273 | * static void myCallbackFunction(int); |
jocis | 2:c0b87b11b9cd | 274 | * @endcode |
jocis | 2:c0b87b11b9cd | 275 | * @param A C++ object pointer. |
jocis | 2:c0b87b11b9cd | 276 | * @param A C++ method within the object to call. |
jocis | 2:c0b87b11b9cd | 277 | */ |
jocis | 2:c0b87b11b9cd | 278 | template<class T> |
jocis | 2:c0b87b11b9cd | 279 | void attachIndexTrigger(T* item, void (T::*method)(int)) { |
jocis | 2:c0b87b11b9cd | 280 | fPointerIndexTrigger.attach( item, method); |
jocis | 2:c0b87b11b9cd | 281 | } |
jocis | 2:c0b87b11b9cd | 282 | |
jocis | 1:ac6b7b1bf6c5 | 283 | /** Sets the factor for the getter-functions to convert in another unit (1.0=Hz, 1/(4*CPR)=rps, 1/(60*4*CPR)=rpm, 360/(4*CPR)=°/s, ...) |
jocis | 1:ac6b7b1bf6c5 | 284 | * |
jocis | 1:ac6b7b1bf6c5 | 285 | * @param fSpeedFactor - factor to scale from Hz (edges per second = 4 * CPS) to user units |
jocis | 1:ac6b7b1bf6c5 | 286 | */ |
jocis | 1:ac6b7b1bf6c5 | 287 | void setSpeedFactor(float fSpeedFactor) { |
jocis | 1:ac6b7b1bf6c5 | 288 | _fSpeedFactor = fSpeedFactor; |
jocis | 1:ac6b7b1bf6c5 | 289 | } |
jocis | 1:ac6b7b1bf6c5 | 290 | |
jocis | 1:ac6b7b1bf6c5 | 291 | /** Gets the actual speed as float value. The value is scales by the facor set by setPositionFactor() |
jocis | 1:ac6b7b1bf6c5 | 292 | * |
jocis | 1:ac6b7b1bf6c5 | 293 | * @return Actual encoder speed as float |
jocis | 1:ac6b7b1bf6c5 | 294 | */ |
jocis | 1:ac6b7b1bf6c5 | 295 | float getSpeed(); |
jocis | 1:ac6b7b1bf6c5 | 296 | |
jocis | 1:ac6b7b1bf6c5 | 297 | /** Sets the factor for the getter-functions to convert in another unit (e.g. CPR (cycles per rotation) * 4.0 to get 1.0 for a full rotation) |
jocis | 1:ac6b7b1bf6c5 | 298 | * |
jocis | 1:ac6b7b1bf6c5 | 299 | * @param fPositionFactor Factor to scale from counts to user unit |
jocis | 1:ac6b7b1bf6c5 | 300 | */ |
jocis | 1:ac6b7b1bf6c5 | 301 | void setPositionFactor ( float fPositionFactor ) { |
jocis | 1:ac6b7b1bf6c5 | 302 | _fPositionFactor = fPositionFactor; |
jocis | 1:ac6b7b1bf6c5 | 303 | } |
jocis | 1:ac6b7b1bf6c5 | 304 | |
jocis | 1:ac6b7b1bf6c5 | 305 | /** Gets the actual counter value as float value. The value is scales by the facor set by setSpeedFactor() |
jocis | 1:ac6b7b1bf6c5 | 306 | * |
jocis | 1:ac6b7b1bf6c5 | 307 | * @return Actual encoder position as float |
jocis | 1:ac6b7b1bf6c5 | 308 | */ |
jocis | 1:ac6b7b1bf6c5 | 309 | float getPosition () { |
jocis | 1:ac6b7b1bf6c5 | 310 | return (float)_counter * _fPositionFactor; |
jocis | 1:ac6b7b1bf6c5 | 311 | } |
jocis | 1:ac6b7b1bf6c5 | 312 | |
jocis | 1:ac6b7b1bf6c5 | 313 | |
jocis | 0:46b8d5680f66 | 314 | protected: |
jocis | 0:46b8d5680f66 | 315 | InterruptIn _pinA, _pinB; |
jocis | 0:46b8d5680f66 | 316 | DigitalIn _pinI; |
jocis | 1:ac6b7b1bf6c5 | 317 | FPointer_vi fPointerCounterChange; |
jocis | 1:ac6b7b1bf6c5 | 318 | FPointer_vi fPointerDirectionChange; |
jocis | 2:c0b87b11b9cd | 319 | FPointer_vi fPointerIndexTrigger; |
jocis | 1:ac6b7b1bf6c5 | 320 | |
jocis | 0:46b8d5680f66 | 321 | int _counter; |
jocis | 1:ac6b7b1bf6c5 | 322 | short _state; |
jocis | 1:ac6b7b1bf6c5 | 323 | short _eMode; |
jocis | 2:c0b87b11b9cd | 324 | bool _bIndexTrigger; |
jocis | 1:ac6b7b1bf6c5 | 325 | |
jocis | 1:ac6b7b1bf6c5 | 326 | Timer _SpeedTimer; |
jocis | 1:ac6b7b1bf6c5 | 327 | |
jocis | 1:ac6b7b1bf6c5 | 328 | unsigned int _nSpeedLastTimer; |
jocis | 1:ac6b7b1bf6c5 | 329 | unsigned int _nSpeedTimeoutMax; |
jocis | 1:ac6b7b1bf6c5 | 330 | unsigned int _nSpeedTimeoutCount; |
jocis | 1:ac6b7b1bf6c5 | 331 | int _nSpeedAvrTimeSum; |
jocis | 1:ac6b7b1bf6c5 | 332 | int _nSpeedAvrTimeCount; |
jocis | 1:ac6b7b1bf6c5 | 333 | float _fLastSpeed; |
jocis | 0:46b8d5680f66 | 334 | |
jocis | 1:ac6b7b1bf6c5 | 335 | void ProcessISR ( void ); |
jocis | 1:ac6b7b1bf6c5 | 336 | void callback_timeout(); |
jocis | 1:ac6b7b1bf6c5 | 337 | |
jocis | 1:ac6b7b1bf6c5 | 338 | float _fPositionFactor; |
jocis | 1:ac6b7b1bf6c5 | 339 | float _fSpeedFactor; |
jocis | 1:ac6b7b1bf6c5 | 340 | |
jocis | 1:ac6b7b1bf6c5 | 341 | private: |
jocis | 1:ac6b7b1bf6c5 | 342 | static short _modeLUT[32]; |
jocis | 0:46b8d5680f66 | 343 | }; |