Library for decoding quadrature encoders. Uses a ring buffer so you can be sure to process every tick in the order that it happened. This library is not really intended for public use yet and does not have much documentation.
Dependents: LineFollowing DeadReckoning
PololuEncoder.h@2:22ac2b4a8012, 2014-02-20 (annotated)
- Committer:
- DavidEGrayson
- Date:
- Thu Feb 20 20:09:21 2014 +0000
- Revision:
- 2:22ac2b4a8012
- Parent:
- 1:138f5421c287
- Child:
- 3:a2dd8d8bde4c
Don't do any I/O in the constructor; that's a bad idea because then people cannot set up their I/O lines in the right order and with the right delays.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
DavidEGrayson | 0:82ccff71d12a | 1 | #include <mbed.h> |
DavidEGrayson | 0:82ccff71d12a | 2 | |
DavidEGrayson | 1:138f5421c287 | 3 | #define POLOLU_ENCODER_EVENT_INC 0x40 |
DavidEGrayson | 1:138f5421c287 | 4 | #define POLOLU_ENCODER_EVENT_DEC 0x80 |
DavidEGrayson | 1:138f5421c287 | 5 | #define POLOLU_ENCODER_EVENT_ERR 0xC0 |
DavidEGrayson | 0:82ccff71d12a | 6 | |
DavidEGrayson | 0:82ccff71d12a | 7 | #define POLOLU_ENCODER_BUFFER_SIZE 256 |
DavidEGrayson | 0:82ccff71d12a | 8 | |
DavidEGrayson | 0:82ccff71d12a | 9 | typedef uint8_t PololuEncoderEvent; |
DavidEGrayson | 0:82ccff71d12a | 10 | |
DavidEGrayson | 0:82ccff71d12a | 11 | class PololuEncoderBuffer |
DavidEGrayson | 0:82ccff71d12a | 12 | { |
DavidEGrayson | 0:82ccff71d12a | 13 | private: |
DavidEGrayson | 0:82ccff71d12a | 14 | volatile uint32_t consumerIndex; // The index in the ring buffer that will be consumed next. |
DavidEGrayson | 0:82ccff71d12a | 15 | volatile uint32_t producerIndex; // The index in the ring buffer that will be populated next, which is currently empty. |
DavidEGrayson | 0:82ccff71d12a | 16 | volatile uint8_t buffer[POLOLU_ENCODER_BUFFER_SIZE]; |
DavidEGrayson | 0:82ccff71d12a | 17 | |
DavidEGrayson | 0:82ccff71d12a | 18 | public: |
DavidEGrayson | 0:82ccff71d12a | 19 | bool hasEvents() const |
DavidEGrayson | 0:82ccff71d12a | 20 | { |
DavidEGrayson | 0:82ccff71d12a | 21 | return consumerIndex != producerIndex; |
DavidEGrayson | 0:82ccff71d12a | 22 | } |
DavidEGrayson | 0:82ccff71d12a | 23 | |
DavidEGrayson | 0:82ccff71d12a | 24 | bool hasSpace() const |
DavidEGrayson | 0:82ccff71d12a | 25 | { |
DavidEGrayson | 0:82ccff71d12a | 26 | return ((producerIndex + 1) % POLOLU_ENCODER_BUFFER_SIZE) != consumerIndex; |
DavidEGrayson | 0:82ccff71d12a | 27 | } |
DavidEGrayson | 0:82ccff71d12a | 28 | |
DavidEGrayson | 0:82ccff71d12a | 29 | uint8_t readEvent() |
DavidEGrayson | 0:82ccff71d12a | 30 | { |
DavidEGrayson | 0:82ccff71d12a | 31 | uint8_t event = buffer[consumerIndex]; |
DavidEGrayson | 0:82ccff71d12a | 32 | consumerIndex = (consumerIndex + 1) % POLOLU_ENCODER_BUFFER_SIZE; |
DavidEGrayson | 0:82ccff71d12a | 33 | return event; |
DavidEGrayson | 0:82ccff71d12a | 34 | } |
DavidEGrayson | 0:82ccff71d12a | 35 | |
DavidEGrayson | 0:82ccff71d12a | 36 | void writeEvent(uint8_t event) |
DavidEGrayson | 0:82ccff71d12a | 37 | { |
DavidEGrayson | 0:82ccff71d12a | 38 | buffer[producerIndex] = event; |
DavidEGrayson | 0:82ccff71d12a | 39 | producerIndex = (producerIndex + 1) % POLOLU_ENCODER_BUFFER_SIZE; |
DavidEGrayson | 0:82ccff71d12a | 40 | } |
DavidEGrayson | 0:82ccff71d12a | 41 | }; |
DavidEGrayson | 0:82ccff71d12a | 42 | |
DavidEGrayson | 0:82ccff71d12a | 43 | class PololuEncoder |
DavidEGrayson | 0:82ccff71d12a | 44 | { |
DavidEGrayson | 0:82ccff71d12a | 45 | public: |
DavidEGrayson | 0:82ccff71d12a | 46 | PololuEncoder(PinName pinNameA, PinName pinNameB, PololuEncoderBuffer * buffer, uint8_t id) |
DavidEGrayson | 0:82ccff71d12a | 47 | : pinA(pinNameA), pinB(pinNameB), buffer(buffer), id(id) |
DavidEGrayson | 0:82ccff71d12a | 48 | { |
DavidEGrayson | 2:22ac2b4a8012 | 49 | } |
DavidEGrayson | 2:22ac2b4a8012 | 50 | |
DavidEGrayson | 2:22ac2b4a8012 | 51 | void init() |
DavidEGrayson | 2:22ac2b4a8012 | 52 | { |
DavidEGrayson | 0:82ccff71d12a | 53 | pinA.rise(this, &PololuEncoder::isr); |
DavidEGrayson | 0:82ccff71d12a | 54 | pinA.fall(this, &PololuEncoder::isr); |
DavidEGrayson | 0:82ccff71d12a | 55 | pinB.rise(this, &PololuEncoder::isr); |
DavidEGrayson | 0:82ccff71d12a | 56 | pinB.fall(this, &PololuEncoder::isr); |
DavidEGrayson | 1:138f5421c287 | 57 | previousState = readState(); |
DavidEGrayson | 2:22ac2b4a8012 | 58 | count = 0; |
DavidEGrayson | 0:82ccff71d12a | 59 | } |
DavidEGrayson | 0:82ccff71d12a | 60 | |
DavidEGrayson | 0:82ccff71d12a | 61 | void isr() |
DavidEGrayson | 0:82ccff71d12a | 62 | { |
DavidEGrayson | 1:138f5421c287 | 63 | uint8_t event = 0; |
DavidEGrayson | 1:138f5421c287 | 64 | uint8_t newState = readState(); |
DavidEGrayson | 1:138f5421c287 | 65 | switch((previousState << 2) | newState) |
DavidEGrayson | 0:82ccff71d12a | 66 | { |
DavidEGrayson | 1:138f5421c287 | 67 | case 0x1: // 0b0001 |
DavidEGrayson | 1:138f5421c287 | 68 | case 0x7: // 0b0111 |
DavidEGrayson | 1:138f5421c287 | 69 | case 0xE: // 0b1110 |
DavidEGrayson | 1:138f5421c287 | 70 | case 0x8: // 0b1000 |
DavidEGrayson | 1:138f5421c287 | 71 | event = id | POLOLU_ENCODER_EVENT_INC; |
DavidEGrayson | 1:138f5421c287 | 72 | count += 1; |
DavidEGrayson | 1:138f5421c287 | 73 | break; |
DavidEGrayson | 1:138f5421c287 | 74 | case 0x2: // 0b0010 |
DavidEGrayson | 1:138f5421c287 | 75 | case 0xB: // 0b1011 |
DavidEGrayson | 1:138f5421c287 | 76 | case 0xD: // 0b1101 |
DavidEGrayson | 1:138f5421c287 | 77 | case 0x4: // 0b0100 |
DavidEGrayson | 1:138f5421c287 | 78 | event = id | POLOLU_ENCODER_EVENT_DEC; |
DavidEGrayson | 1:138f5421c287 | 79 | count -= 1; |
DavidEGrayson | 1:138f5421c287 | 80 | break; |
DavidEGrayson | 1:138f5421c287 | 81 | case 0x3: // 0b0011 |
DavidEGrayson | 1:138f5421c287 | 82 | case 0x6: // 0b0110 |
DavidEGrayson | 1:138f5421c287 | 83 | case 0x9: // 0b1001 |
DavidEGrayson | 1:138f5421c287 | 84 | case 0xC: // 0b1100 |
DavidEGrayson | 1:138f5421c287 | 85 | event = id | POLOLU_ENCODER_EVENT_ERR; |
DavidEGrayson | 1:138f5421c287 | 86 | break; |
DavidEGrayson | 1:138f5421c287 | 87 | } |
DavidEGrayson | 1:138f5421c287 | 88 | previousState = newState; |
DavidEGrayson | 1:138f5421c287 | 89 | |
DavidEGrayson | 2:22ac2b4a8012 | 90 | if (event != 0 && buffer != NULL && buffer->hasSpace()) |
DavidEGrayson | 1:138f5421c287 | 91 | { |
DavidEGrayson | 1:138f5421c287 | 92 | buffer->writeEvent(event); |
DavidEGrayson | 0:82ccff71d12a | 93 | } |
DavidEGrayson | 0:82ccff71d12a | 94 | } |
DavidEGrayson | 1:138f5421c287 | 95 | |
DavidEGrayson | 1:138f5421c287 | 96 | int32_t getCount() |
DavidEGrayson | 1:138f5421c287 | 97 | { |
DavidEGrayson | 1:138f5421c287 | 98 | return count; |
DavidEGrayson | 1:138f5421c287 | 99 | } |
DavidEGrayson | 1:138f5421c287 | 100 | |
DavidEGrayson | 1:138f5421c287 | 101 | private: |
DavidEGrayson | 1:138f5421c287 | 102 | uint8_t readState() |
DavidEGrayson | 1:138f5421c287 | 103 | { |
DavidEGrayson | 1:138f5421c287 | 104 | return pinA | (pinB << 1); |
DavidEGrayson | 1:138f5421c287 | 105 | } |
DavidEGrayson | 1:138f5421c287 | 106 | |
DavidEGrayson | 1:138f5421c287 | 107 | InterruptIn pinA; |
DavidEGrayson | 1:138f5421c287 | 108 | InterruptIn pinB; |
DavidEGrayson | 1:138f5421c287 | 109 | PololuEncoderBuffer * buffer; |
DavidEGrayson | 1:138f5421c287 | 110 | uint8_t previousState; |
DavidEGrayson | 1:138f5421c287 | 111 | volatile uint8_t id; |
DavidEGrayson | 1:138f5421c287 | 112 | volatile int32_t count; |
DavidEGrayson | 0:82ccff71d12a | 113 | }; |