|
| 1 | +/** |
| 2 | + * This example reads multiple encoders using pin change interrupts, on an |
| 3 | + * Arduino Uno or Nano. |
| 4 | + * |
| 5 | + * @boards AVR |
| 6 | + * |
| 7 | + * The ATmega328P microcontroller only has two interrupt pins (2 and 3), so if |
| 8 | + * you want to use more than two interrupt-driven encoders, you'll either have |
| 9 | + * to use a timer interrupt to continuously poll the encoders, or use the chip's |
| 10 | + * pin change interrupts. This example demonstrates the latter. |
| 11 | + * |
| 12 | + * Connections |
| 13 | + * ----------- |
| 14 | + * |
| 15 | + * Connect three encoders to the pins of port C as follows: |
| 16 | + * |
| 17 | + * - A0: pin A of encoder #0 |
| 18 | + * - A1: pin B of encoder #0 |
| 19 | + * - A2: pin A of encoder #1 |
| 20 | + * - A3: pin B of encoder #1 |
| 21 | + * - A4: pin A of encoder #2 |
| 22 | + * - A5: pin B of encoder #2 |
| 23 | + * |
| 24 | + * Connect the common pins to ground, the internal pull-up resistors will be |
| 25 | + * enabled. |
| 26 | + * |
| 27 | + * Behavior |
| 28 | + * -------- |
| 29 | + * |
| 30 | + * When the position of one of the encoders changes, it is printed to the Serial |
| 31 | + * monitor. |
| 32 | + * |
| 33 | + * Written by PieterP, 2021-08-11 |
| 34 | + * https://github.com/tttapa/Arduino-Helpers |
| 35 | + */ |
| 36 | + |
| 37 | +#include <Arduino_Helpers.h> |
| 38 | +#include <AH/Hardware/RegisterEncoders.hpp> |
| 39 | + |
| 40 | +// The number of encoders to read: |
| 41 | +constexpr uint8_t num_enc = 3; |
| 42 | +// Mask the bottom 6 bits of the GPIO registers (2 pins × 3 encoders). |
| 43 | +// This determines which pins are used: |
| 44 | +const uint8_t pin_mask = 0x3F; |
| 45 | +// The actual encoder object that keeps track of the encoder state: |
| 46 | +RegisterEncoders<uint8_t, num_enc, int32_t, true> encoders; |
| 47 | +// AVR uses 8-bit GPIO registers, so the register type is uint8_t. |
| 48 | +// Then we specify the number of encoders, the position type, |
| 49 | +// and whether the encoders should be interrupt-safe: since we'll |
| 50 | +// be calling `encoders.update()` in an interrupt handler, it is |
| 51 | +// important that this is set to true. |
| 52 | + |
| 53 | +// Pin change interrupt handler that reads the pins and updates the state: |
| 54 | +ISR (PCINT1_vect) { encoders.update(PINC & pin_mask); } // read port C |
| 55 | + |
| 56 | +void setup() { |
| 57 | + PCMSK1 |= pin_mask; // enable pin change interrupt for given pins in port C |
| 58 | + DDRC &= ~pin_mask; // input mode for port C |
| 59 | + PORTC |= pin_mask; // enable pull-up resistors for port C |
| 60 | + PCICR |= 1 << 1; // enable pin change interrupt for port C |
| 61 | + Serial.begin(115200); |
| 62 | +} |
| 63 | + |
| 64 | +void loop() { |
| 65 | + // The previous position of each encoder, to detect changes: |
| 66 | + static int32_t prevPos[num_enc] {}; |
| 67 | + |
| 68 | + // Read the encoder positions and print if they changed: |
| 69 | + for (uint8_t i = 0; i < num_enc; ++i) { |
| 70 | + int32_t newPos = encoders[i].read(); |
| 71 | + if (newPos != prevPos[i]) { |
| 72 | + Serial << '[' << i << "] " << newPos << endl; |
| 73 | + prevPos[i] = newPos; |
| 74 | + } |
| 75 | + } |
| 76 | +} |
0 commit comments