www.mikrocontroller.net

Forum: Projekte & Code Drehgeber/Encoder 1-, 2- oder 4-schrittig


Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab jetzt nochmal den Code schön gemacht und hier reingestellt, weil 
der Ursprungsthread doch recht unübersichtlich ist.
Und auch, weil regelmäßig Threads zu Problemen mit anderen Codes im 
Forum auftauchen. Das Thema ist also immer noch sehr aktuell.
Auch wenn dieser Code sehr kurz ist, ist das Thema keineswegs trivial.


Besonders habe ich nun das Problem der 2- und 4-schrittigen Drehgeber 
behandelt.

Es sind jetzt 3 Auslesefunktionen drin, brauchen tut man aber nur die 
eine zu Deinem Drehgeber passende.
Man hätte das auch per Defines machen können, aber ich wollte auch 
Anfänger nicht zu sehr verwirren.

Der besondere Kniff an den Mehrschritt-Routinen ist, daß die nicht 
verwendeten 1 oder 2 unteren Bits erhalten bleiben müssen. Nur dadurch 
ist weiterhin die Entprellung gewährleistet.


Das Prinzip ist immer noch das gleiche, also Abtastung im 
Timerinterrupt. Damit ergibt sich eine automatische Entprellung.

Eine Entprellung in Hardware mit RC-Gliedern hat demgegenüber den 
Nachteil, daß sie schwer zu dimensionieren ist.
Wählt man die Zeitkonstante zu kurz, können Preller durchkommen, wählt 
man sie zu lang, kommt es zu Fehlern bei schnellem Drehen.


Ich habe das Programm mit nem Drehgeber mit 96 Stellungen und 15mm 
Drehknopf getestet. Man muß schon sehr schnell drehen, damit Schritte 
verloren gehen.


Wichtig ist, daß die Auslesefunktion "encode_read*()" so oft aufgerufen 
wird, daß nicht mehr als 127 Schritte dazwischen liegen.
Wenn das nicht gehen sollte, kann man aber die Schrittvariable und die 
Auslesefunktion einfach auf 16 Bit erweitern (int16_t), dann sinds 32767 
Schritte, das sollte dann reichen.


Peter

Autor: Sven S. (schwerminator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin Peter,
ich nutze deinen Code um einen 2-schrittigen Drehgeber auszulesen. Das 
klappt auch hervorragend, wenn ich zum Beispiel einen Wert hoch- und 
herunterzähle. Nun möchte ich aber den Drehgeber zur Navigation in einem 
Menu einsetzen. Die Hauptschleife in meiner main.c sieht wie folgt aus:
while(1){
  if(input_read_encoder() > 0)
    menu_next_entry(&menu_context);
  else if(input_read_encoder() < 0)
    menu_prev_entry(&menu_context);
  else if(input_get_key())
    menu_select(&menu_context);
}

Es wird also immer die Funktion, die bei dir encode_read2() heißt 
aufgerufen und überprüft ob man mit oder gegen den Uhrzeigersinn gedreht 
hat. Das Ganze klappt aber nicht wirklich zuverlässig. Theoretisch soll 
bei jedem Einrasten entweder die Funktion menu_next_entry() oder 
menu_prev_entry() aufgerufen werden. Dem ist aber nicht so, denn 
manchmal muss ich den Drehgeber 4-5 Rastungen weit drehen, damit auf den 
nächsten Menüpunkt gesprungen wird. Manchmal reicht aber auch eine 
Rastung. Setze ich deinen Code möglicherweise falsch ein?

Vielen Dank, Sven

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du die Funktion nicht an mehreren Stellen gleichzeitig aufrufst, 
sollte es funktionieren.


Gib dochmal die Variable "val" aus meinem Beispiel auf das LCD aus, ob 
sie richtig zählt.

Ich hab den Code noch leicht verbessert:

http://www.mikrocontroller.net/articles/Drehgeber#...

damit er schon nach der Initialisierung richtig zählt und das "volatile" 
hinzugefügt, damit er auch bei Inlining funktioniert.


Peter

Autor: Sven S. (schwerminator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,
der Tipp mit dem mehrmaligen Aufrufen war schonmal Gold wert, viel 
besser, aber dennoch brauche ich manchmal noch 2-3 Dreher, um zu 
springen. Woran könnte es jetzt noch liegen?
while(1){
  val = input_read_encoder();
    
  if(val > 0)
    menu_next_entry(&menu_context);
  else if(val < 0)
    menu_prev_entry(&menu_context);
  else if(input_get_key())
    menu_select(&menu_context);
}

Und ja, wenn ich val einfach hoch- und runterzählen lasse, klappts 
perfekt.

mfG, Sven

Autor: Bill (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> der Ursprungsthread
welcher?

>> den Code
welcher?

Autor: D. E. (stb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ursprungsthread:
Beitrag "Drehgeber auslesen"


Code: http://www.mikrocontroller.net/attachment/40597/ENCODE.C

Siehe "Dateianhang: ..." im ersten Beitrag dieses Threads.

Autor: Sven S. (schwerminator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube ich habe jetzt die Geschichte gelöst: Vorher war die 
Abtastfrequenz bei 100Hz, ich dachte das reicht bei langsamen Drehen. 
Nun habe ich 1kHz und es läuft problemlos. Tja da dachte ich, ich könnte 
das Interruptaufkommen reduzieren, geht aber anscheinend nicht. Egal.

Danke nochmal.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuch mal, ob es so besser geht:
while(1){
  val += input_read_encoder();
    
  if(val > 0){
    val--;
    menu_next_entry(&menu_context);
  }else if(val < 0){
    val++;
    menu_prev_entry(&menu_context);
  }else if(input_get_key())
    menu_select(&menu_context);
}


Peter

Autor: Stephan Henning (stephan-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter ( danni )

wenn ich Deinen Code im µVision compilieren will, hagelt es Fehler ohne 
Ende.
Ich meine die aus dem Ursprungsthread.
Wo Du beide Varianten ( Tabelle und Umwandlung ) darstellst.

Fehlermeldung von Keil:

compiling Gray.c51...
GRAY.C51(25): error C141: syntax error near 'INT_T0', expected 'const'
GRAY.C51(26): error C132: 'INT_T0': not in formal parameter list
GRAY.C51(26): error C141: syntax error near '{'
Target not created
etc.pp.

Ich habe keine Ahnung von "C" . Wo liegt das Problem ???

Hintergrund:
Ich habe mit meiner ASM Routine einige Sorgen.

Beitrag "Probleme mit dem drehgebr 8051 in ASM"

Daher will ich mal sehen was Deine Routine draus macht.


Danke

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stephan Henning wrote:
> Ich meine die aus dem Ursprungsthread.

Dann poste nächstes mal auch in dem richtigen Thread.
Denke mal an Deine Mitmenschen, die vielleicht auch Anfänger sind und 
dann völlig konfusioniert sind, weil Du was im falschen Thread postest 
:(


> GRAY.C51(25): error C141: syntax error near 'INT_T0', expected 'const'

Heißt, er kennt 'INT_T0' nicht.
Ich hab mir die Interrupt-Nummern in verstehbare Symbole definiert:

#define INT_EX0         0
#define INT_T0          1
#define INT_EX1         2
#define INT_T1          3
#define INT_UART        4

Einfügen, dann gehts.


> Ich habe keine Ahnung von "C" . Wo liegt das Problem ???

Das ist in der Tat ein Problem.
Ohne C-Kenntnisse wirst Du ja nicht verstehen, was Du machst.
Ich kann Dich auch nicht ans Händchen nehmen und Dir alles beibringen.
Ich würde Dir erstmal raten, C aufm PC zu lernen, z.B. mit men alten 
Borland-C im DOS-Fenster, damit man nicht den ganzen Windows-Schrunz 
mitmachen muß.


Peter

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
mal ne Frage:
muss ich bei zwei Drehgebern auch zweimal die gleiche Routine verwenden?
Gruß

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast
wrote:
> muss ich bei zwei Drehgebern auch zweimal die gleiche Routine verwenden?
> Gruß

Ja, Du mußt die benötigten Routinen kopieren und umbenennen, natürlich 
mit verschiedenen Pins und Variablen.


Peter

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Peter,
danke für die Antwort!
Gruß

Autor: clonephone82 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,

In deinem Ursprungsthread hast du den Pin Change Interrupt erwähnt, ganz 
am Schluss.

Ich kenne die AVRs nicht so gut aber damit meinst du einen pin Interrupt 
der auf beide Flanken reagiert oder.

=> Also statt über einen Timer IRQ zu pollen - verwendet man einfach die 
pin change Interrupts => aber dann halt für die A-Spur und B-Spur sonst 
wird es ja nicht gehen - oder?

... also so pseudo code:

IRQ(A pin-schange)
{
   dein_enocde_code();
}


IRQ(B pin-change)
{
   dein_enocde_code();
}

Ich möchte auf einem 80MHz Controller ein Drehgeber damit auslesen. 
Maximale Drehfrequenz 70kHz.

Ich hoffe das es geht ohne die CPU zu sehr zu belasten.

sg
Danke

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.