Welche Encoder Library?

Habt ihr eine Empfehlung welche Library für Rotary Encoder verwendet werden soll?

Sollte irgendwas schlankes, unkompliziertes sein. Einsatz sollte in erster Linie auf Uno/Nano und ESP8266/ES32 sein. Die Auswahl scheint ja schier unendlich zu sein

https://playground.arduino.cc/Main/RotaryEncoders/

welche verwendet ihr - und warum?

(deleted)

Ich nutze die "Encoder" Library von Paul Stoffregen, die sowohl auf AVRs als auch dem ESP32 funktioniert. Zudem wird sie auch von der "LcdMenuLib2" eingebunden, die ich ebenfalls in vielen Projekten nutze.

danke - probiere ich aus!
Karma+
(OT: fürs LCD nehm ich lieber meine mit deuschen Umlauten...)

Ich nutze diese "Encoder" Library mit der halben oder gar einer viertel Auflösung

combie:
Ich nutze diese "Encoder" Library mit der halben oder gar einer viertel Auflösung

combie, hättest du das auch als Arduino-Sketch in deiner Wühlkiste, dass du zur Verfügung stellen könntest?

noiasca:
combie, hättest du das auch als Arduino-Sketch in deiner Wühlkiste, dass du zur Verfügung stellen könntest?

Da sind doch nur minimale Anpassungen nötig. Das Größte ist noch das auf Timer2 zu ändern und das ist auch nicht schwer

Hier dieses, dümpelt schon seit 2 Jahren in meiner Wühlkise rum:

#include <INTERVAL.h>
#include <CombiePin.h>
/*
 * Quelle:https://www.mikrocontroller.net/topic/drehgeber-auslesen#41978
 * 
 * Pin 2 und Pin 4 kommen an die Schaltkontakte 
 * Pullup aktiv
 * 
 * Pin 3 ist GND für den DrehEncoder
 * 
 * So kann man den Encoder direkt in die Buchse des UNO stecken.
 */

using DekoderTabelle = const int8_t[16];
DekoderTabelle  einPhasenwechselProRastpunkt  = {0, 1,-1, 0,-1, 0, 0, 1, 1, 0, 0,-1, 0,-1, 1, 0}; 
DekoderTabelle zweiPhasenwechselProRastpunkt  = {0, 0,-1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1, 0, 0};
DekoderTabelle vierPhasenwechselProRastpunkt  = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0};



template<byte phaseApin, byte phaseBpin, typename T>
class DrehEncoder
{
  private:
  Combie::Pin::InputPin<phaseApin> phaseA;
  Combie::Pin::InputPin<phaseBpin> phaseB;
  const DekoderTabelle &tabelle;
  T count;        // Aktuelle Drehencoder Stellung
  int8_t last;    // Dekoder Tabellen Index Merker

  public:
  DrehEncoder(const DekoderTabelle &tabelle):tabelle(tabelle),count(0),last(0){}
  
  void init()
  {
    count = 0;
    phaseA.initPullup();
    phaseB.initPullup();
  }

  T get()
  {
    last <<= 2;
    last |= phaseA;
    last |= phaseB << 1;
    last &= 0x0F;
    count += tabelle[last];
    return count;
  }
};


using DekoderResultType = long;
DrehEncoder<4,2,DekoderResultType> drehEncoder(vierPhasenwechselProRastpunkt);



void setup() 
{
  Serial.begin(9600);
  Serial.println("Start");
  drehEncoder.init();
  pinMode(3,OUTPUT); // GND für Encoder
}

void loop() 
{
  static DekoderResultType letzterCount = 0;
  INTERVAL(1)
  {
    DekoderResultType neuerCount  =  drehEncoder.get(); 
  
    // nur ausgeben wenn FIFO leer genug
    if((Serial.availableForWrite() > 10) && (letzterCount != neuerCount))
    {
       Serial.println(neuerCount);
       letzterCount = neuerCount;
    }
  }
}

Hallo,

dann zeig ich meine Encoder Lib auch einmal. Basiert auf Peter Danneggers Methoden. Zusätzlich kann man einen Zählbereich vorgeben, nützlich für Menüs, Timereinstellungen oder andere definierten Einstellbereiche. Tja und dann gibts noch eine Dynamikeinstellung. Wenn man langsam dreht reagiert er normal. Dreht man schneller ändern sich die Werte entsprechend schneller. Für große Änderungen nützlich um sich nicht tot zu kurbeln.

Edit:
meine Lib verwendet die CombieLib für die Pins einlesen. Link zur CombieLib

DocEncoder.zip (4.83 KB)

combie/doc, danke beide eure Beispiele laufen . Karma+

@combie: läuft die combiePin eigentlich auch auf esp8266 und esp32?

@doc: ich würde dir empfehlen, in deinem Beispiel den #include von der combiePin in den Anwender Sketch zu geben und einen Link dazu, wo man diese findet. Damit sieht man sofort was man dazu noch alles braucht. Libs die mit der Arduino IDE kommen, zu includen ist imho in Ordnung - aber externe Abhängigkeiten ... da hast mir schon ein Ei gelegt.

Frohe Ostern

noiasca:
... da hast mir schon ein Ei gelegt.

Doc als Osterhase :wink:

Gruß Tommy

Passt zu Ostern - finde ich. :grin:

Wenns als Ersatz für die Eiersuche gedacht war ... Auftrag erfüllt... :slight_smile:

noiasca:
@combie: läuft die combiePin eigentlich auch auf esp8266 und esp32?

Nöö ...
So erstmal nicht.

#ifndef ARDUINO_ARCH_AVR
  #error "This library only supports boards with an AVR processor."
#endif

noiasca:
läuft die combiePin eigentlich auch auf esp8266 und esp32?

Du müßtest dich mit den Registern auseinandersetzen. Dafür eine Tabelle erstellen und abhängig inkludieren. Ich hatte das einmal für mich um den ATtiny841 erweitert. Anderer Registersatz, andere Adressen.

Wenn du beim von der IDE verwendeten derzeitigen avr-gcc 7.3 bleibst, in der Hoffnung wird nie aktualisiert, kann dir combie bestimmt noch seine ältere Variante geben die nicht auf Portadressen sondern auf Portnamen beruhte. Wäre einfacher - aber nicht gcc Zukunftskompatibel.

CombiePin_plus_ATtiny841.zip (305 KB)

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.

Ja, kann sein, dass ich mich da vertan habe und mir das durch die Lappen gegangen ist.

Neee ...
Dem ist nicht so.

Die Tabelle heißt bei mir "einPhasenwechselProRastpunkt" und ist für Drehenkoder gedacht, welche einen Phasenwechsel pro Rastung haben.

{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

Weil dein Encoder halt 4 Phasenwechsel pro Rastung liefert!
Mit meiner Tabelle vierPhasenwechselProRastpunkt, welche genau für solche Encoder gedacht ist, würde dieser bei jedem Rastpunkt eine einzelne Zählung machen.