www.mikrocontroller.net

Forum: Compiler & IDEs Drehencoder entprellen, aber wie?


Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

in einem meiner Projekte verwende ich einen Drehencoder.

Der Encoder hat ne Rastung, pro Rasteinheit liefert er zwei Inkremente 
ab.

Prinzipell funktioniert die Auswertung. Angeschlossen ist der Drehgeber 
an zwei externe INTs (PinChange an AVR ATmega88).

Im Programm gibt es nun Probleme, weil das Ding prellt. Ne "normale" 
Entprellung kommt nicht in Frage, weil man ja keine Pulse verpassen 
will.

Das Problem ist, daß Linksdrehen (-) nicht die Umkehrung von 
Rechtsdrehen (+) ist, d.h. im Programm wird die Folge +-+ anders 
interpretiert als ++- anders als + etc.

Hat jemand ne Idee wie man das lösen könnte? Hier mal die 
C-Implementierung:
#ifndef _DREHGEBER_H_
#define _DREHGEBER_H_

#define DREH_INVALID -128

static inline char drehgeber_step(void);
static inline char drehgeber_job(void);

#if defined (__GNUC__) && defined (__AVR__)
#    include <avr/pgmspace.h>
#else
#    define PROGMEM
#    define pgm_read_byte(x) (*(x))
#endif // avr-gcc

// Aufrufen, wenn eine Flanke an einem der Ports festgestellt wurde,
// zB aus einer ISR heraus. 
char drehgeber_step ()
{
    static const char drehgeber_transitions[] PROGMEM = 
    {
         0,                       1,           -1, DREH_INVALID,
        -1,                       0, DREH_INVALID,            1, 
         1,            DREH_INVALID,            0,           -1, 
         DREH_INVALID,           -1,            1,            0
    };
    
    static uint8_t a_alt;
    uint8_t a = a_alt;
    
    if (IS_SET (PORT_DREH_A))        a |= (1 << 2);
    if (IS_SET (PORT_DREH_B))        a |= (1 << 3);
    
    a_alt = a >> 2;
    
    return (char) pgm_read_byte (& drehgeber_transitions[a]);
}

// Mein Drehgeber hat eine Rasterung und bei jeden Raster erzeugt er *zwei*
// Flanken. Man muss also die Anzahl der Schritte etwas mühsam durch 2 teilen.
char drehgeber_job(void)
{
    char step = drehgeber_step();
    char s = 0;
    
    if (DREH_INVALID != step)
    {
        static char tick;
        char t = step + tick;
        
        if (t >=  2)    s =  1;
        if (t <= -2)    s = -1;
        
        t -= s;
        t -= s;
        
        tick = t;
    }
    
    return s;
}
#endif // _DREHGEBER_H_


Was das Makro IS_SET macht sollte klar sein, aufgerufen wird 
drehgeber_job() in der PinChange ISR:
#include <inttypes.h>
#include <avr/interrupt.h>

#include "drehgeber.h"

static int8_t volatile steps; // vom Drehgeber

...

SIGNAL (SIG_PIN_CHANGE0)
{
    steps += drehgeber_job();
}

int main()
{
   ...
   // Leeraufruf zum Initialisieren
   drehgeber_step();
   ...
}


Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Im Programm gibt es nun Probleme, weil das Ding prellt. Ne "normale"
>Entprellung kommt nicht in Frage, weil man ja keine Pulse verpassen
>will.

Macht man im TImerinterrupt alle 1 bzw. 10ms.

Drehgeber: Beispielcode in C

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#ARGL#

Hätt ich auch seber mal draufkommen können, das auszuprobieren...

Reagiert im 10ms-Job zwar merklich langsamer als vorher, aber wenigstens 
zählt er nicht mehr falsch...

EDIT

und @ 2.5kHz ist's so wie ich's mir vorstelle :-)

So einfach ist die Welt...

Autor: D. S. (jasmin)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
auf alle Fälle mit 0,1 uf keramik c von den pulskontaten nach masse.

das ist oft mehr als die halbe miete !!!

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Schaltung ist fertig und keinPlatz mehr... mit der Poll-per-IRQ 
klappt's ja prima und mit minimaler Hardware :-)

Autor: fantozzi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Codevorschlag ohne Klimbim (für Encoder mit 2 Werten pro Rasterung im 
polling):

neu= PORTB&0b.0000.0011;   // einlesen der beiden Pins

if (alt!=neu)
{
//   Auswertung der Richtung
//   jede Richtung hat separaten Zähler
if(alt==0 && neu==1)zahler_down++;
if(alt==1 && neu==3)zahler_down++;
if(alt==3 && neu==2)zahler_down++;
if(alt==2 && neu==0)zahler_down++;

if(alt==0 && neu==2)zahler_up++;
if(alt==2 && neu==3)zahler_up++;
if(alt==3 && neu==1)zahler_up++;
if(alt==1 && neu==0)zahler_up++;

//wenn einer der Richtungszähler den Wert 2 hat
//wird er auf Null zurückgesetzt und der Hauptzähler bewegt
if(zahler_up   == 2)  {Hauptzahler++;    zahler_up=0;}
if(zahler_down == 2)  {Hauptzahler--;    zahler_down=0;}

//zum Entprellen:wenn ein Zähler den Wert 1 erreicht
//wird die Gegenrichtung zurückgesetzt
if(zahler_up == 1)  {zahler_down=0; }
if(zahler_down == 1)  {zahler_up=0;  }

alt=neu;
}


ich weiss der thread ist alt , ist bei google aber noch weit vorne wenn 
man nach --Drehencoder entprellen-- sucht

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
fantozzi schrieb:
> Codevorschlag ohne Klimbim

Also 13 IFs, das ist ne riesen Menge Klimbim.

Der Code im obigen Link braucht kein einziges IF, der ist kurz und 
knackig (wenig Zyklen, wenig Flash).


Peter

Autor: fantozzi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
:-)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Also 13 IFs, das ist ne riesen Menge Klimbim.

Hat ja auch 3,5 Jahre gedauert, bis er fertig war.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dietmar Steiner schrieb:
> auf alle Fälle mit 0,1 uf keramik c von den pulskontaten nach masse.
>
> das ist oft mehr als die halbe miete !!!

Da der Thread offenbar bei der Suche noch so weit vorne ist:
Oben genannten Tipp bitte unter keinsten Umständen machen. Das ist 
allergröbster Pfusch und zerstört nicht nur die Kontakte, sondern 
erzeugt auch noch extreme Störungen.

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.