#include "encoder.h" #include "hardware/gpio.h" #define PIN_A 10 #define PIN_B 11 #define REST 3 /* A = B = 1: both contacts open at a detent */ #define DIR -1 /* as wired on the bench, the raw count runs down clockwise */ static volatile int32_t steps, clicks; static volatile int8_t acc; /* edges since the last rest */ static volatile uint8_t prev; /* index = previous AB << 2 | current AB; invalid (bounce) transitions count 0 */ static const int8_t TABLE[16] = { 0,-1, 1, 0, 1, 0, 0,-1, -1, 0, 0, 1, 0, 1,-1, 0 }; static uint8_t read_ab(void){ return (uint8_t)((gpio_get(PIN_A) << 1) | gpio_get(PIN_B)); } static void on_edge(uint gpio, uint32_t events){ uint8_t cur; int8_t d; (void)events; if(gpio != PIN_A && gpio != PIN_B) return; cur = read_ab(); d = TABLE[(prev << 2) | cur]; steps += d; acc = (int8_t)(acc + d); prev = cur; if(cur == REST){ /* a full click is 4 edges; accept 2 or more in case bounce hid some, ignore wiggles of 1 */ if(acc >= 2) clicks += DIR; else if(acc <= -2) clicks -= DIR; acc = 0; } } void encoder_init(void){ gpio_init(PIN_A); gpio_set_dir(PIN_A, GPIO_IN); gpio_pull_up(PIN_A); gpio_init(PIN_B); gpio_set_dir(PIN_B, GPIO_IN); gpio_pull_up(PIN_B); prev = read_ab(); gpio_set_irq_enabled_with_callback(PIN_A, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, on_edge); gpio_set_irq_enabled(PIN_B, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true); } int32_t encoder_count(void){ return clicks; } int32_t encoder_steps(void){ return DIR * steps; } int encoder_ab(void){ return read_ab(); }