ein zwei graue Haare später, die mikrocontroller.net Variante mit Polling in pur Arduino Style.
Da ich noch nie was mit Interrupts und/oder Timer gemacht habe, habe ich mich da wohl zu sehr verwirren lassen. Schlussendlich poll ich nun einfach jede Millisekunde. Wenn ich das INTERVAL(1) von Combie näher angesehen hätte, wäre ich da vermutlich eher draufgekommen.
Aber gut, hier ein Sketch, getestet auf einem Uno und auf einem NodeMCU/ESP8266.
/*
Encoder zu Fuß
basiernd auf https://www.mikrocontroller.net/articles/Drehgeber#Dekoder_f.C3.BCr_Drehgeber_mit_wackeligen_Rastpunkten
noiasca
*/
// Arduino UNO, NANO
const byte pinA = 2; // encoder pin A to GND
const byte pinB = 3; // encoder pin B to GND
const byte pinButton = 4; // the push button of the encoder
//NodeMCU
//const byte pinA = D2; // encoder pin A to GND
//const byte pinB = D3; // encoder pin B to GND
//const byte pinButton = D4; // the push button of the encoder
int8_t enc_delta; // -128 ... 127
// Dekodertabelle für normale Drehgeber
// volle Auflösung
//const int8_t table[16] PROGMEM = {0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, 1, 0}; // vier Phasen Wechsel pro Rastpunkt
// Dekodertabelle für wackeligen Rastpunkt
// halbe Auflösung
//const int8_t table[16] PROGMEM = {0, 0, -1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, -1, 0, 0}; // zwei Phasen Wechsel pro Rastpunkt
// viertel Auflösung
const int8_t table[16] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0}; // ein Phasen Wechsel pro Rastpunkt
int digitalReadFast(uint8_t pin) // ohne PWM/Timer Absicherung
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
if (*portInputRegister(port) & bit) return HIGH;
return LOW;
}
void encoder_polling()
{
static int8_t last = 0; // alten Wert speichern
last = (last << 2) & 0x0F;
if (digitalReadFast(pinA)) last |= 2;
if (digitalReadFast(pinB)) last |= 1;
enc_delta += pgm_read_byte(&table[last]);
}
int8_t encode_read( void ) // Encoder auslesen
{
int8_t val;
//cli();
val = enc_delta;
enc_delta = 0;
//sei();
return val;
}
void setup() {
Serial.begin(115200);
Serial.println("Encoder");
pinMode (pinA, INPUT_PULLUP);
pinMode (pinB, INPUT_PULLUP);
pinMode (pinButton, INPUT_PULLUP);
}
void loop() {
// read
static uint32_t previousMillis = 0;
uint32_t currentMillis = millis(); // es geht nur um den millis Wechsel, da reichen uns 8 bit.
if (currentMillis != previousMillis) // each new millisecond
{
encoder_polling();
previousMillis = currentMillis;
}
//output
static int8_t val;
static int8_t oldval;
val += encode_read();
if (val != oldval)
{
Serial.println(val);
}
if (digitalRead(pinButton) == LOW)
{
val = 0;
Serial.println(val);
}
oldval = val;
}
PS @Combie: was mir noch aufgefallen ist, meiner Meinung ist die Tabellenbenennung bei dir anders.
z. B.:
{0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, 1, 0}; wertet bei mir vier Phasen Wechsel pro Rastpunkt aus
Mikrokontroller.net schreibt auch "volle Auflösung". du benennst die Tabellen genau andersrum.