mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Drehencoder auswerten ohne Timer


Autor: Michael Juen (jmibk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

es gibt zwar einige Themen bezüglich Drehencoder, aber ich mach noch 
einen ;-). Nein, ich habe keine Antwort auf die Frage gefunden:

Es geht darum, einen Drehencoder (den Pana von Pollin) an einem 
ATMEGA8515 auszuwerten.

Das Ding hängt an PD6 und PD7, der gemeinsame Anschluss auf Masse. 
Pullups sind aktiv, das klappt alles.
Ich hab ein SPeicherregister (encoder_state), welches den vorherigen 
Zustand speichern kann und 3 Temp Register (temp1, temp2, temp3) für den 
Fall zur verfügung.

Prroblem an der Sache: Ich kann weder die Pins am µC ändern (auf einen 
IRQ Pin legen oder sowas) noch einen Timer verwenden, da alle beiden 
Timer bereits vergeben sind.

Ich hab jetzt immer versucht, nachdem ich "11" oder "00" eingelesen 
habe, im nächsten Schritt zu schauen, welcher der beiden Pins ist als 
erstes gewechselt, dann gehts Zeittechnisch einfacher, da die 
Drehencodergeschichte nur ca 10x die Sekunde aufgerufen wird.
Der Zustand, in der Rasterung muss eigentlich immer 11 oder 00 sein, 
leider ist das hier nicht immer so.

Hat jemand einen Code, oder zumindest anregungen, wie man das ohne 
Hilfsmittel mit dem bloßen 2 Pins ohne Timer und IRQs lösen kann, eine 
links und rechtsdrehung zu unterscheiden und ein Unterprogramm 
aufzurufen?

Wenns geht kein C Code.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael Juen schrieb:

> Prroblem an der Sache: Ich kann weder die Pins am µC ändern (auf einen
> IRQ Pin legen oder sowas) noch einen Timer verwenden, da alle beiden
> Timer bereits vergeben sind.

Darf ich fragen womit?

Meistens kann man auch mehrere Funktionalitäten in eine Timer-ISR legen.

Autor: MaWin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du fragst jetzt nicht wirklich, wie man Drehencoder auswertet?

Was bitteschön gefällt dir an den ungefähr 10000 Beschreibungen wie man 
Drehencoder auswertet nicht ?

http://dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29

Nein, man braucht keinen Timer, man muss nur nicht zu schnell (sinnlos) 
und nicht zu langsam (man verliert Schritte) abfragen.

Und geh nicht wie im psychotischen Zwang gerade den Weg, der nicht zum 
Erfolg führt, nämlich den Weg der Flankenerkennung.

Autor: Gast123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pins im Hauptprogramm in einer Endlosschleife pollen, um die Auswertung 
vorzunehmen. Dann brauchst du keinen Timer.

Autor: Andreas K. (derandi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Timer bräuchte er wenn er die Drehgeschwindigkeit erfassen will, z.B. 
für schnelles Scrollen (wenn man schneller dreht werden pro realen 
Schritt mehrere in Software gemacht).

Autor: Bernhard M. (boregard)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael Juen schrieb:
> erstes gewechselt, dann gehts Zeittechnisch einfacher, da die
> Drehencodergeschichte nur ca 10x die Sekunde aufgerufen wird.
> Der Zustand, in der Rasterung muss eigentlich immer 11 oder 00 sein,

Das ist definitiv zu wenig, gerade weil Du die Werte zwischen zwei 
Raststellungen sicher erkennen must, um die Drehrichtung zu erkennen.
100x pro Sekunde ist meiner Meinung nach immer noch zuwenig, wenn man 
halbwegs schnell drehen will.
Ich verwende 1000x pro Sekunde...

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mach`s in einem Job der Mainloop, der 1000 mal pro Sekunde 
aufgerufen wird, natürlich von einem Timer synchronisiert, der nebenher 
noch andere Dinge erledigt.

...

Autor: A.Drei (allu) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falls Du Bascom verwendest, probier mal:

Dim Flag_dreh_flanke As Bit
Dim Dreh_impulse As Integer
Set Portd.6                 ' Pullups einschalten
Set Portd.7
Config Portd.6 = Input      ' Drehgeber
Config Portd.7 = Input

Do

' Drehcoder auswerten und dann die Impulse zaehlen
' ... muss möglichst oft durchlaufen werden

     If Flag_dreh_flanke = 0 Then

         If Pind.6 = 1 Then
            Set Flag_dreh_flanke

            If Pind.7 = 1 Then
               Incr Dreh_impulse
            Else
               Decr Dreh_impulse
            End If
         End If


       Else
            If Pind.6 = 0 Then
               Reset Flag_dreh_flanke

               If Pind.7 = 0 Then
               Incr Dreh_impulse
            Else
               Decr Dreh_impulse
            End If

            End If
      End If

' und alle anderen Programmteile
loop

Gruß   allu

Autor: Jörg H. (idc-dragon)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Mit Bascom kann ich nicht dienen, aber mit rein interruptgesteuerter 
Verarbeitung. Ich persönlich finde das mit dem Timer-Polling auch nicht 
so doll, oft versuche ich den uC so gut es geht schlafen zu lassen.

Zugegeben hat man beim Prellen des Kontaktes einen Haufen "unnütze" 
Interrupts, aber halt auch nur wenn jemand dran dreht und nicht ständig.

Bei der Auswertung ist der "Trick" gegen Prellen, dass man eine 
State-Machine mitführen muß. Flanken auf einem Kontakt erzeugen dann 
noch keine Schritte, sondern erst wenn ein Zyklus komplett ist. Oft 
sieht man die Primitivimplementierung: Bei Flanke an dem einen Kontakt 
nimm den anderen für die Richtung. Das funktioniert nicht zuverlässig!

Den Code hier habe ich mit dem dem Panasonic-Encoder von Pollin 
erfolgreich im Einsatz. Ist aus dem Forum abgeguckt. Das Message-Senden 
an die Hauptschleife mag natürlich bei euch anders aussehen.

Es gibt auch andere Encoder, mit Rastung nach 360° der Pulsfolge, nicht 
nach 180°. Dann wird es komplizierter. Habe ich auch, aber ist nicht so 
elegant.
#include <stdint.h>
#include <avr/io.h> // for device register definitions
#include <avr/interrupt.h> // for interrupt handlers
#include <util/delay.h> // for delay loops
#include "msg.h" // messages waking up the main loop
#include "rotary.h" // own interface

// define how the encoder is connected (Port B is hard coded)
#define ENC_A PB4
#define ENC_B PB1

static uint8_t rotary_status;
static uint8_t rotary_step;


void rotary_init(void)
{
  PORTB |= _BV(ENC_B) | _BV(ENC_A); // enable pullups

  _delay_us(10); // let the lines settle before reading the current status

  rotary_status = rotary_step = PINB & (_BV(ENC_A) | _BV(ENC_B));

  PCMSK0 |= _BV(PCINT1) | _BV(PCINT4); // enable the line for pin change interrupt
  PCICR |= _BV(PCIE0); // enable pin change interrupt 0, for port B
}


SIGNAL(SIG_PIN_CHANGE0)
{
  uint8_t status_cur;

  status_cur = PINB & (_BV(ENC_A) | _BV(ENC_B)); // read the change
  if ((status_cur ^ rotary_step) == (_BV(ENC_A) | _BV(ENC_B))) // both lines have changed?
  {  // full gray code cycle is done
    struct msg message; // message for result
    message.id = e_rotary;

    if ((status_cur ^ rotary_status) == _BV(ENC_A)) // contact A
    {  // turn towards the right
      message.bdata = 1;
    }
    else
    {  // turn towards the left
      message.bdata = -1;
    }
    msg_post(&message); // send it

    rotary_step = status_cur; // remember stable state
  }
  rotary_status = status_cur; // remember any state
}

Gruß
Jörg

Autor: Marcus Stangl (mstangl)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
hier noch eine Version in Assembler. Der Aufruf der Routine erfolgt alle 
277µs. Die Rückgabewerte für L/R liegen in den Variablen ,countRIGHT' 
und
,countLEFT'.

Gruß
Marcus

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.