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:

/media/uploads/jocis/qeix4.png

(+) Count UP; (-) Count DOWN

Committer:
jocis
Date:
Tue Sep 02 18:23:36 2014 +0000
Revision:
0:46b8d5680f66
Child:
1:ac6b7b1bf6c5
Added documentation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jocis 0:46b8d5680f66 1 #include "QEIx4.h"
jocis 0:46b8d5680f66 2
jocis 0:46b8d5680f66 3 // state machine for decoting - don't change!!!
jocis 0:46b8d5680f66 4 short QEIx4::_modeLUT[16] = { 0, 21, 2, 47, 4, 5, 34, 27, 36, 9, 30, 11, 16, 41, 14, 15 };
jocis 0:46b8d5680f66 5
jocis 0:46b8d5680f66 6 // bit masks for state machine - don't change!!!
jocis 0:46b8d5680f66 7 #define QEIx4_MASK 0xC
jocis 0:46b8d5680f66 8 #define QEIx4_INC 0x10
jocis 0:46b8d5680f66 9 #define QEIx4_DEC 0x20
jocis 0:46b8d5680f66 10 #define QEIx4_CHG 0x30
jocis 0:46b8d5680f66 11 #define QEIx4_A 1
jocis 0:46b8d5680f66 12 #define QEIx4_B 2
jocis 0:46b8d5680f66 13 #define QEIx4_S0 0x0
jocis 0:46b8d5680f66 14 #define QEIx4_S1 0x4
jocis 0:46b8d5680f66 15 #define QEIx4_S2 0x8
jocis 0:46b8d5680f66 16 #define QEIx4_S3 0xC
jocis 0:46b8d5680f66 17
jocis 0:46b8d5680f66 18 //#define DEB(x) printf (x)
jocis 0:46b8d5680f66 19 #define DEB(x)
jocis 0:46b8d5680f66 20
jocis 0:46b8d5680f66 21 ///////////////////////////////////////////////////////////////////////////////
jocis 0:46b8d5680f66 22
jocis 0:46b8d5680f66 23 QEIx4::QEIx4 ( PinName pinA, PinName pinB, PinName pinI, bool bUseIRQ ) : _pinA(pinA), _pinB(pinB), _pinI(pinI)
jocis 0:46b8d5680f66 24 {
jocis 0:46b8d5680f66 25 _bUseIRQ = bUseIRQ;
jocis 0:46b8d5680f66 26 _bZeroOnIndex = false;
jocis 0:46b8d5680f66 27 _cpr = 500;
jocis 0:46b8d5680f66 28
jocis 0:46b8d5680f66 29 // synchronize state machine
jocis 0:46b8d5680f66 30 _counter = 0;
jocis 0:46b8d5680f66 31 ProcessISR ();
jocis 0:46b8d5680f66 32 _mode += QEIx4_S2;
jocis 0:46b8d5680f66 33 ProcessISR ();
jocis 0:46b8d5680f66 34 _counter = 0;
jocis 0:46b8d5680f66 35
jocis 0:46b8d5680f66 36 }
jocis 0:46b8d5680f66 37
jocis 0:46b8d5680f66 38 ///////////////////////////////////////////////////////////////////////////////
jocis 0:46b8d5680f66 39
jocis 0:46b8d5680f66 40 QEIx4::~QEIx4()
jocis 0:46b8d5680f66 41 {
jocis 0:46b8d5680f66 42 _pinA.rise ( NULL );
jocis 0:46b8d5680f66 43 _pinA.fall ( NULL );
jocis 0:46b8d5680f66 44 _pinB.rise ( NULL );
jocis 0:46b8d5680f66 45 _pinB.fall ( NULL );
jocis 0:46b8d5680f66 46 }
jocis 0:46b8d5680f66 47
jocis 0:46b8d5680f66 48 ///////////////////////////////////////////////////////////////////////////////
jocis 0:46b8d5680f66 49
jocis 0:46b8d5680f66 50 void QEIx4::ProcessISR ( void )
jocis 0:46b8d5680f66 51 {
jocis 0:46b8d5680f66 52 DEB (".");
jocis 0:46b8d5680f66 53 _mode &= QEIx4_MASK;
jocis 0:46b8d5680f66 54 if ( _pinA ) _mode |= QEIx4_A;
jocis 0:46b8d5680f66 55 if ( _pinB ) _mode |= QEIx4_B;
jocis 0:46b8d5680f66 56
jocis 0:46b8d5680f66 57 _mode = _modeLUT[_mode];
jocis 0:46b8d5680f66 58
jocis 0:46b8d5680f66 59 if ( _mode & QEIx4_CHG )
jocis 0:46b8d5680f66 60 {
jocis 0:46b8d5680f66 61 bool bCounterChange = false;
jocis 0:46b8d5680f66 62
jocis 0:46b8d5680f66 63 if ( _mode & QEIx4_INC )
jocis 0:46b8d5680f66 64 {
jocis 0:46b8d5680f66 65 _counter++;
jocis 0:46b8d5680f66 66 bCounterChange = true;
jocis 0:46b8d5680f66 67 }
jocis 0:46b8d5680f66 68 if ( _mode & QEIx4_DEC )
jocis 0:46b8d5680f66 69 {
jocis 0:46b8d5680f66 70 _counter--;
jocis 0:46b8d5680f66 71 bCounterChange = true;
jocis 0:46b8d5680f66 72 }
jocis 0:46b8d5680f66 73 if ( _bZeroOnIndex && _pinI != NC && _pinI == 1 )
jocis 0:46b8d5680f66 74 {
jocis 0:46b8d5680f66 75 _counter = 0;
jocis 0:46b8d5680f66 76 _bZeroOnIndex = false;
jocis 0:46b8d5680f66 77 CounterZero ();
jocis 0:46b8d5680f66 78 bCounterChange = true;
jocis 0:46b8d5680f66 79 }
jocis 0:46b8d5680f66 80
jocis 0:46b8d5680f66 81 if ( _bUseIRQ )
jocis 0:46b8d5680f66 82 {
jocis 0:46b8d5680f66 83 switch ( _mode & QEIx4_MASK )
jocis 0:46b8d5680f66 84 {
jocis 0:46b8d5680f66 85 case QEIx4_S0:
jocis 0:46b8d5680f66 86 _pinB.rise ( NULL );
jocis 0:46b8d5680f66 87 _pinB.fall ( NULL );
jocis 0:46b8d5680f66 88 _pinA.rise ( this, &QEIx4::ProcessISR );
jocis 0:46b8d5680f66 89 DEB ("S0");
jocis 0:46b8d5680f66 90 break;
jocis 0:46b8d5680f66 91 case QEIx4_S1:
jocis 0:46b8d5680f66 92 _pinA.rise ( NULL );
jocis 0:46b8d5680f66 93 _pinA.fall ( NULL );
jocis 0:46b8d5680f66 94 _pinB.rise ( this, &QEIx4::ProcessISR );
jocis 0:46b8d5680f66 95 DEB ("S1");
jocis 0:46b8d5680f66 96 break;
jocis 0:46b8d5680f66 97 case QEIx4_S2:
jocis 0:46b8d5680f66 98 _pinB.rise ( NULL );
jocis 0:46b8d5680f66 99 _pinB.fall ( NULL );
jocis 0:46b8d5680f66 100 _pinA.fall ( this, &QEIx4::ProcessISR );
jocis 0:46b8d5680f66 101 DEB ("S2");
jocis 0:46b8d5680f66 102 break;
jocis 0:46b8d5680f66 103 case QEIx4_S3:
jocis 0:46b8d5680f66 104 _pinA.rise ( NULL );
jocis 0:46b8d5680f66 105 _pinA.fall ( NULL );
jocis 0:46b8d5680f66 106 _pinB.fall ( this, &QEIx4::ProcessISR );
jocis 0:46b8d5680f66 107 DEB ("S3");
jocis 0:46b8d5680f66 108 break;
jocis 0:46b8d5680f66 109 }
jocis 0:46b8d5680f66 110 }
jocis 0:46b8d5680f66 111
jocis 0:46b8d5680f66 112 if ( bCounterChange )
jocis 0:46b8d5680f66 113 {
jocis 0:46b8d5680f66 114 CounterChange ();
jocis 0:46b8d5680f66 115 }
jocis 0:46b8d5680f66 116 }
jocis 0:46b8d5680f66 117 }
jocis 0:46b8d5680f66 118
jocis 0:46b8d5680f66 119 ///////////////////////////////////////////////////////////////////////////////
jocis 0:46b8d5680f66 120 ///////////////////////////////////////////////////////////////////////////////
jocis 0:46b8d5680f66 121 ///////////////////////////////////////////////////////////////////////////////