Мы дошли до момента, когда стандартные Arduino-библиотеки становятся слишком громоздкими. Создаем свою библиотеку на чистом C с минимальным оверхедом.
Структура библиотеки:
encoder.h:
#ifndef ENCODER_H
#define ENCODER_H
#include <stdint.h>
#include <avr/io.h>
typedef struct {
uint8_t pinA;
uint8_t pinB;
volatile int16_t counter;
} Encoder;
void encoder_init(Encoder* enc, uint8_t pinA, uint8_t pinB);
void encoder_update(Encoder* enc);
int16_t encoder_get(Encoder* enc);
#endif
encoder.c:
#include "encoder.h"
void encoder_init(Encoder* enc, uint8_t pinA, uint8_t pinB) {
enc->pinA = pinA;
enc->pinB = pinB;
enc->counter = 0;
// Настраиваем пины как входы с подтяжкой
DDRD &= ~(1 << pinA);
DDRD &= ~(1 << pinB);
PORTD |= (1 << pinA) | (1 << pinB);
}
void encoder_update(Encoder* enc) {
static uint8_t lastState = 0;
uint8_t currentState = (PIND >> enc->pinA) & 1;
currentState |= ((PIND >> enc->pinB) & 1) << 1;
if (currentState != lastState) {
// Обновляем счетчик
if ((lastState == 0b00 && currentState == 0b01) ||
(lastState == 0b01 && currentState == 0b11) ||
(lastState == 0b11 && currentState == 0b10) ||
(lastState == 0b10 && currentState == 0b00)) {
enc->counter++;
} else {
enc->counter--;
}
lastState = currentState;
}
}
int16_t encoder_get(Encoder* enc) {
int16_t val = enc->counter;
enc->counter = 0; // Сброс после чтения
return val;
}
Использование:
#include "encoder.h"
Encoder myEncoder;
void setup() {
Serial.begin(115200);
encoder_init(&myEncoder, 2, 3);
}
void loop() {
encoder_update(&myEncoder);
int16_t val = encoder_get(&myEncoder);
if (val != 0) {
Serial.println(val);
}
delay(10);
}