Forum: Mikrocontroller und Digitale Elektronik Drehregler an uC - geht das?


von Markus Krötz (Gast)


Lesenswert?

Hallo,

ich würde gerne an meinen Mikrocontroller (ATmega16) einen Drehregler
schalten (an den PORTD) und der Mikrocontroller soll dann die Drehung
auswerten und dementsprechend einen Wert hoch- bzw. runterzählen (je
nach Drehrichtung). Meine Frage ist nun, ob ich das mit einem
Drehregler überhaupt lösen kann, denn der macht doch normalerweise
nichts anderes, als die Spannung hoch- bzw. runterzudimmen und das kann
ich doch schlecht mit nem Mikrocontroller abfragen, oder?

Oder benötigt man für dieses Vorhaben besondere Drehregler?
Sollte es gehen, könnte mir dann bitte jemand auch den Anschluss, sowie
auch die Ansteuerung/Abfrage mittels uC erklären?

Vielen Dank für Eure Hilfe

Markus

von Markus Krötz (Gast)


Lesenswert?

Vielleicht sollte ich noch anmerken, dass ich unter einem Drehregler
z.B. die die Regler auf einem Mischpult oder ähnlichem (Lautsprecher,
uvm.) meine - keine Ahnung, wie die Dinger wirklich heißen, Drehregler
klang mir aber am wahrscheinlichsten.

von Till (Gast)


Lesenswert?

Wenn dein Drehregler ein Potentiometer ist / ein einstellbarer
Widerstand, dann lässt er sich mit einem Mikrocontroller mit ADC
auslesen, wenn es sich um einen Drehgeber handelt mit digitalen
Eingängen wie z.B. hier:
http://www.sprut.de/electronic/pic/programm/rotary/rotary.html

von Markus Krötz (Gast)


Lesenswert?

D.h. den Potentiometer schließe ich einfach an eines meiner ADC-Bits an
(habe den ATmega16, und laut Datenblatt sind die PORTSA alle ADC0 -
ADC7 Poins) - und das wars schon? Was bekommt der Mikrocontroller dann
für Werte?

von Markus Krötz (Gast)


Lesenswert?

es ist spät in der Nacht, also ADC-Bits sollte ADC-Ports heißen und ADC0
- ADC7 Poins sollte eigentlich ADC0 - ADC7 Pins heißen - sorry.

von Markus Krötz (Gast)


Lesenswert?

Da fällt mir gerade ein: Potentiometer haben ja einen Anfang und einen
Endregelzustand. Mein Drehregler sollte das aber nicht besitzen, d.h.
ich hätte gerne einen Dreher/Drehregler, den man beliebig oft um seine
eigene Achse drehen kann - gibt es sowas?

von thkais (Gast)


Lesenswert?

In diesem Fall sollte man einen digitalen Drehsensor benutzen. Man
bekommt zwei Phasenverschobene Rechtecksignale. Das gleiche Prinzip ist
in einer Maus eingebaut (wenns nicht gerade ne optische ist...).
Allerdings sind diese Sensoren nicht gerade billig - es kommt auch auf
die gewünschte Auflösung an. Potentiometer ohne Anschlag gibt es zwar,
sind aber sehr selten und außerdem hat man zwischen 0° und 359° einen
extremen Sprung. Ein digitaler Sensor kann ohne Probleme mehrere
Umdrehungen erkennen.
Was hast Du denn vor? Evtl. gibts auch eine andere Lösung.

von Mark Hämmerling (Gast)


Lesenswert?

Salut,

dann meinst Du einen Drehencoder (rotary encoder). Die geben ein 90°
phasenverschobenes Signal an zwei Pins aus. Anhand dessen kannst Du die
Richtung bestimmen (warten auf Flanke an Pin 1, bei Eintritt Auswertung
des Pegels an Pin 2 -> Richtung).
Link zu Code hat Till ja schon gegeben. Ich selbst setze auch einen
Drehencoder in meinem Dimmer ein: http://semitone.sf.net

Viel Erfolg!
Mark

von Till (Gast)


Lesenswert?

eine weitere anleitung wo der encoder mit interrupt ausgelesen wird ist
hier
http://www.mcmanis.com/chuck/Robotics/projects/lab-x3/quadratrak.html

die encoder gibts für 95cent im surplushandel

von Mark Hämmerling (Gast)


Lesenswert?

Salut,

wo denn z.B.? Falls Du die Alps von Pollin meinst, die gibt's schon
längere Zeit nicht mehr. ;(
Wäre für Tips sehr dankbar.

Mark

von Tom (Gast)


Lesenswert?

Such mal im Forum hier. Die Bestell-Adresse wurde des Öfteren gepostet.

von Markus Krötz (Gast)


Lesenswert?

Ah, genau, ich glaube so ein Drehencoder dürfte genau das sein, was ich
suche.

Ich habe unter anderem diesen hier gefunden:
http://www.mercateo.com/p/115-743412/Encoder_STEC11B_5V_300V.html.

Dort steht "Beschreibung horizontal mit Taster..." bedeutet das, dass
dieser Drehencoder auch als Taster funktioniert?

Könntet ihr mir vielleicht knapp beschreiben, wie ich diesen Encoder an
mein Mikrocontroller anschließe (muss der an die ADC-Pins und an wie
viele oder muss ich noch nen AD/DC-Wandler zwischenschalten, etc)? Ich
würde mal tippen, das Ding hat 2 Anschlüsse an den uC, einen für Dreher
in Rechtsrichtung, einen für Dreher in Linksrichtung, oder so. Und bei
nem Tastendruck könnte evtl. auf beiden Kanälen eine 1 kommen?

Und außerdem, wie steuere ich das Teil an (vor allem, wenn der auch als
Taster funktionieren kann), so ähnlich wie im Folgenden (Code aus dem
Forum hier)?

  ADMUX=(1<<6)|(1<<7);
  ADCSRA=(1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
  ADCSRA|=(1<<ADIE);
  ADCSRA|= (1<<ADEN) | (1<<ADSC);

SIGNAL(SIG_ADC) {
  char cOutText[100];
  int nADCValue;
  nADCValue = ADCL;
  nADCValue |= (ADCH<<8);
  sprintf(cOutText,"measured%d : %d\r\n",(ADMUX&7),nADCValue);
  SendZTString0(cOutText);
  ADCSRA|=(1<<ADSC);
  if ((ADMUX&7)==7)
    ADMUX^=7;
  else
    ADMUX++;
}

Vielen Dank für Eure Antworten, die waren schon einmal ein mehr als
große Hilfe.

Gruß

Markus

von Peter D. (peda)


Lesenswert?

Die Encoder liefern einen Gray-Code.

Man schließt sie einfach an 2 beliebige Pins an und wertet sie im
Timerinterrupt aus, ob sich der Zustand geändert hat.
Je nach Änderung zählt man dann hoch oder runter:

hoch:
0->1
1->3
3->2
2->0

runter:
0->2
2->3
3->1
1->0


Peter

von Stephan Schwarz (Gast)


Angehängte Dateien:

Lesenswert?

Ne...    beim Drehimpulsgeber bekommst du doch schon digitale Signale,
was willst du danoch mit einem ADC  :-).
Aber ich hatte vor 3 Wochen die selben Fragen wie du.
Deshalb lies einfach mal hier nach.
http://www.mikrocontroller.net/forum/read-1-81560.html#81585

Im Anhang ist meine Quellecode zum einlesen. Funktioniert auch!
Hat da jemand Verbesserungsvorschläge?


Meine Fragen:
Ich hab für das einlesen des Gebers auch 2 HW IR geopfert.
Geht das nicht auch anders. Ich will aber natürlich auch zu jeder Zeit
des Programmablauf mein Gerät bedienen können.
Da werde ich wohl bei den HW IR`s bleiben müssen oder?

Ausserdem hab ich als TYP für die Variable, die der Geber steuert einen
ENUM genommen. Ich war eigetlich der Meinung, dass wenn ich den letzten
Wert in der Reihe erreicht habe und nochmal inkremmentiere
--> ich dann wieder beim Anfange der Wertereihe ankomme. Dem ist aber
nicht so wie kann ich das ändern?

von Till (Gast)


Lesenswert?

"Könntet ihr mir vielleicht knapp beschreiben, wie ich diesen Encoder
an
mein Mikrocontroller anschließe"

Nein.

a) ist das hier schon des öfteren beschrieben

b) sind oben mindestens zwei links zu seiten mit detailierter
beschreibung inclusive funktionierendem code.

zur verfügbarkeit - also ich habe einen ganzen stapel im regal.

von Markus Krötz (Gast)


Lesenswert?

> zur verfügbarkeit - also ich habe einen ganzen stapel im regal.

Verkaufst du die Dinger (und wenn ja für wie viel denn)? Was sind das
dann für Drehencoder, mit Rasterung (und wie viel) und mit Taster oder
ohne?

Den Anschluss habe ich mittlerweile auch rausgekriegt, danke ;-)

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

@Stephan,

wenn ich Deinen Code richtig verstehe, wertest Du nur 2 von 4
Phasenwechsel aus, d.h. Du nutzt den Encoder nur zur Hälfte aus.


"Ich hab für das einlesen des Gebers auch 2 HW IR geopfert.
Geht das nicht auch anders."

Ja, siehe Anhang.


"Ich war eigetlich der Meinung, dass wenn ich den letzten
Wert in der Reihe erreicht habe und nochmal inkremmentiere
--> ich dann wieder beim Anfange der Wertereihe ankomme. Dem ist aber
nicht so"

Das wäre ja schlimm, der Compiler darf nicht einfach die Zahlenformate
willkürlich ändern.
Ein Byte zählt immer von 0...255 bzw. -128...127. Wenn Du was anderes
willst, dann mußt Du das selber tun, z.B.:

char i;
if( i == 6 )
  i = 0;
if( i == -1 )
  i = 5;


Peter

von Stephan Schwarz (Gast)


Lesenswert?

@peter

Danke für die Lehrstunde :-)
Das gibt mal wieder ein VB ( virtuelles Bier )
Hab deinen Code zwar noch nicht ganz verstanden, aber den werde ich nun
mal auseinander nehmen.

@ markus

mein Code  ---------->    Anfängerbeispiel
peter`s Code ----------->   wohl deutlich mehr profimässig

von Markus Krötz (Gast)


Lesenswert?

lach he Stephan, ich zücke den Hut vor jedem, der sich mit dem uC ein
bisschen auskennt. Dass man am eigenen Code fast immer was zum
verbessern finden würde, geht wohl den meisten so. Wäre ja auch
schlimm, wenn alles schon perfekt wäre.

Ich muss jetzt nur noch nen (billigen) Drehencoder ergattern und dann
wirst du schon sehen (Stephan) was ein Anfängerbeispiel ist, keine
Sorge ;-).

Grüßle und vielen Dank

von Stephan Schwarz (Gast)


Lesenswert?

In dem andern posting, das ich schon angegeben habe, hat jemand
geschrieben, das es Bei Bürklin welche für 2 Euro gibt. da steht auch
ne Artikelnummer.
Ich selber hab eine bei Bürklin bestellt für 7 &#8364;. Mir egal, ich
muss ihn ja nicht bezahlen.
ABer das eigentlich teuere ist doch eh immer der Versand, wenn ich nur
ein geringe Menge bestelle.
Wenn du es billig haben willst, das würde ich dir empfehlen. In einem
Coanrad Shop oder bei Kürklin oder ähnlichen selber Vorbeizuschauen.
Aber bei einer gerigne Stückzahl ( 2-3) zum experimentiren ist der
Preis doch eh nicht so entscheidend.
Oder brauchst du grössere Mengen.?

Ich bin auf der Suche nach einem sehr leichtgängigem Teil.
Ich will damit ein Jog Shuttle bauen, das aber auch einen zusätzlichen
Taster hat.

von Markus Krötz (Gast)


Lesenswert?

Ähnliches schwebt mir auch vor, darum wäre ich einem leichtgängigen Teil
nicht gerade abgeneigt ;-).

von Till (Gast)


Lesenswert?

extrem leichtgängig sind die optischen encoderscheiben die sich zuweilen
hinten an motoren finden welche man aus alten druckern ausschlachtet

von Rahul (Gast)


Lesenswert?

Hallo!
Mit Interesse habe ich diesen Thread verfolgt, da ich auch einen
Drehencoder verwenden möchte.
Vor ein paar Jahren habe ich einen bei Apotheken-Conrad erworben
(Damals sollte eine Schaltung mit einem PIC enstehen (bähbäh!)).
Dieser Drehencoder hat 5 Anschlüsse: 2 für die Bewegung in axialer
Richtung (drücken des Tasters) und 3 für die Rotation.
Die Rotation liefert die phaseverschobenen Signale an den beiden
Ausgängen. Der dritte Anschluss in dieser Gruppe ist der gemeinsame
Kontakt.
Da der AVR einen Interrupt-Eingang besitzt, der auf Flankenwechsel in
beide Richtung reagieren kann, müsste es doch möglich sein, auf einen
entsprechenden Interrupt zu warten, dann den anderen Eingang einzulesen
und entsprechend auszuwerten. Notfalls müsste man die
Detektionsrichtung des Interrupts umkehren, was bei entgegengesetzter
Drehung den Verlust eines Schrittes zur Folge hätte.
Könnte das so gehen?

So wie ich das Programm von Peter verstehe, wird regelmässig der Port
eingelesen, mit dem vorherigen Zustand verglichen und dann entsprechend
gehandelt. Dient die Abfrage per Timer-Interrupt einem Entprellen (wie
bei dem ASM-Code in der Codesammlung)?
Leider habe ich momentan keinen Zugang zu einem Oszilloskop und kann
mir somit nicht das Schalt(Prell-)verhalten des Encoders ansehen.

Soweit erst mal,
Gruß Rahul

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Die Pin-Change-Interrupts sind für Drehencoder ungeeignet, am
einfachsten geht es mit dem folgenden Code in einem Timer-Interrupt:
http://dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29

von Ingo Henze (Gast)


Lesenswert?

Ich hatte kürzlich versucht, Drehencoder bei Oppermann-Electronic zu
bestellen (ALPS mit Schalter, 0.95 Euro), aber leider sind die nicht
mehr lieferbar.
Da ich den Schalter nicht wirklich benötige, kämen für mich auch die
für 2 Euro von Bürklin in Frage. Da kann ich aber leider als
Privatperson ja nicht bestellen, oder?
Und dann hab ich auch nicht gefunden, wie hoch denn da die
Versandkosten sind.

von Markus Krötz (Gast)


Lesenswert?

Ich glaub ich nehm den von Conrad
(http://www1.conrad.de/scripts/wgate/zcop_b2c/~flN0YXRlPTg4MjgzNjQyNQ==?~template=PCAT_AREA_S_BROWSE&glb_user_js=Y&shop=B2C&p_init_ipc=X&~cookies=1).
Die sind zwar megaschweineteuer, aber in meinem Umkreis gibts keinen
anderen Laden als den Conrad und wenn ich bei den anderen noch die
Versandkosten dazurechne, bin ich auch bei 7 Euro :-(.

Übrigens Stephan: Hier gibts sogenannte Codie-Räder, vielleicht ist das
ja auch was für dich (sind aber relativ teuer, unter
D->Drehgeber->Codie-Rad): http://de.farnell.com/jsp/home/homepage.jsp

von Ingo Henze (Gast)


Lesenswert?

Man kann übrigens Conrad-Artikel nicht so ohne weiteres verlinken,
besser die Artikelnummer hier reinschreiben, damit kommt man einfacher
zum Ziel.

von Till (Gast)


Lesenswert?

" Ich hatte kürzlich versucht, Drehencoder bei Oppermann-Electronic zu
bestellen (ALPS mit Schalter, 0.95 Euro), aber leider sind die nicht
mehr lieferbar. "

mächte sein das ich die letzten 50Stück gekauft habe, werden jetzt wohl
nach und nach an PICs angelötet...

von Ingo Henze (Gast)


Lesenswert?

Hmmmm, was ist los?
Deine Aussage kann ich überhaupt nicht deuten :-)

"mächte sein..." == "könnte sein" ?

von Till (Gast)


Lesenswert?

-ä +ö möchte=könnte

von Ingo Henze (Gast)


Lesenswert?

Ahso, das bringt etwas Klarheit in das Dunkel der
Drehgeberbestellungen.

Interessant find ich bei Bürklin auch das Teil mit den 31 LEDs rundrum
(75 E 680), sieht bestimmt cool aus, wenn man da den aktuellen Wert
anzeigt oder so.
Leider kostet da einer aber schlappe 24 Euro (naja ok, ab 10 Stk. nur
noch 18,70 :-)

von Peter D. (peda)


Lesenswert?

@Rahul,

"Dient die Abfrage per Timer-Interrupt einem Entprellen (wie bei dem
ASM-Code in der Codesammlung)?"


in der Tat ergibt sich neben den anderen Vorteilen (beliebige Pins,
mehrere Encoder möglich) auch ein Entprelleffekt.

Gerade Billigteile prellen gerne mal und auch jegliche Störimpulse
(elektrostatische Aufladung) können beim Flankeninterrupt Fehlzählungen
bewirken.


Ich hatte auch Stephans Beispiel so verstanden, daß die 3ms Wartezeit
im Interrupt zur Entprellung nötig sind.
Aber bezüglich Warten im Interrupt hab ich ja schon öfter meine Meinung
kund getan.



Peter

von Till (Gast)


Lesenswert?

also meiner erfahrung nach reicht 1ms für die alpsteile aus um zu
entprellen

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Entprellen ist bei Drehencodern mit Gray-Code überhaupt nicht nötig.

von Ingo Henze (Gast)


Lesenswert?

Ja, hab ich auch festgestellt :-)
Meine 10 Zeilen Assemblercode haben überraschenderweise auf Anhieb
funktioniert.

von Till (Gast)


Lesenswert?

"Entprellen ist bei Drehencodern mit Gray-Code überhaupt nicht
nötig."

mit dem code von sprut habe ich gelegentliche fehler bekommen wenn zu
schnell abgefragt. ich hab mit dem encoder gezählt und den wert auf
display ausgegeben.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Soweit ich diesen PIC-Code
(http://www.sprut.de/electronic/pic/programm/rotary/rotary.html)
entziffern kann wird die Dekodierung dort falsch gemacht. Wenn die
Eingangswerte geändert sind kennt das Programm nur 2 Fälle: entweder
wurde nach rechts gedreht, oder es wurde nach links gedreht. Der 3.
Fall, dass überhaupt nicht gedreht wurde sondern einfach nur eines der
beiden Signale prellt, wird überhaupt nicht behandelt.

von Till (Gast)


Lesenswert?

ich dachte die struktur dort ist

wenn nicht links, und nicht rechts, dann geh zum ende und mach nix

jedenfalls funktioniert es wenn man halt nur alle 1ms schaut.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

> ich dachte die struktur dort ist
> wenn nicht links, und nicht rechts, dann geh zum ende und mach nix

;ist neu = alt?
; ja: nicht verdreht, also nichts tun
; nein: encoder verdreht, aber in welche Richtung?

Danach wird nur noch zu "rechts" oder "links" verzweigt.

> jedenfalls funktioniert es wenn man halt nur alle 1ms schaut.

Das ist bei diesem Code kein Wunder, bei richtiger Dekodierung darf die
Abtastfrequenz beliebig hoch sein.

von Markus Krötz (Gast)


Lesenswert?

Also ich hab jetzt den Drehimpulsgeber von Conrad (705586), nur dieser
"bescheidene" Laden liefert ein Datenblatt mit, dass meines Erachtens
mehr einer Erörterung denn einem Schaltplan gleicht.

Gut, die einen drei Anschlüsse werden wohl A, C, B sein. Davon muss ich
wohl C an Ground und A und B jeweils (mit 5V versehen?) an den
Mikrocontroller (sagen wir mal PINA0 und PINA1), oder?
Doch für was sind die zwei weiteren Anschlüsse da? Für Ground und 5
Volt? Sinnvoll wäre das, wenn einer davon den Tastendruck abfrägt, also
vermute ich mal, einer von beiden muss auch an Ground und der andere an
einen dritten Pin am Mikrocontroller (und an 5V?) (sagen wir PINA2).

Ist das nun richtig angeschlossen und welcher Anschluss stimmt?

Die Auswertung des Tastendrucks würde dann folgendermaßen gehen (für
die Drehung habe ich vor Peter's Code zu benutzen): Ich schaue
einfach, ob dan PINA2 eine 1 kommt. Ist dies der Fall, setze ich meine
Variable pressed auf true, wenn nicht wird pressed auf false gesetzt.
Funktioniert das so?

Der Code würde dann wie folgt aussehen:

SIGNAL (SIG_OVERFLOW0)
{
  static char enc_last = 0xFE;
  char i, j;

  i = 0;

  // jetzt kommt die hinzugefügte Zeile
  pressed = PHASE_C; // PHASE_C bedeutet PORTA -> A2
  // Ende der Änderung

  if( PHASE_A )
    i = 1;

  j = 3;
  if( PHASE_B )
    i ^= j;        // convert gray to binary

  j = enc_last - i;      // difference last - new
  if( (char)(j & 1) ){      // bit 0 = value (1)
    enc_last = i;      // store new as next last

    i = enc_delta;
    if( (char)(j & 2) )      // bit 1 = direction (+/-)
      i -= 2;
    enc_delta = ++i;
  }
}

von Markus Krötz (Gast)


Lesenswert?

Wie ist das: Muss jeder Impuls (A, B und für den Taster auch einer der
anderen) an 5 Volt mitangeschlossen werden?

Und geht das mit dem Tastendruck abfangen so wie in meinem obigen Code
gedacht oder nicht?

von Markus Krötz (Gast)


Lesenswert?

Sorry, wenn ich mich nochmal melde, aber es wäre cool, wenn mir jemand
sagen könnte, ob alle Ausgänge des Impulsgebers, die an den uC führen,
mit 5Volt in Reihe geschaltet werden müssen und wie ich den Impuls für
den Taster anschließe und auslese.

Vielen Dank für Eure Hilfe

Markus

von Stephan Schwarz (Gast)


Lesenswert?

Morgen markus,

also ich denke es gibt da verschieden Arten der Beschaltung.
Die Pullups extern benutze ich garnciht, da ich die Internen des µC
benutze.
Anscheinend gibt es auch unterschiedliche Aren von Encodern. Einige
brauchen anscheiend eine Richtige Betriebsspannung  also +5V und GND.
Meinen Encoder benutze ich eher wie einen Schalter. z.B. legen ich halt
einen der beiden Kontakte für den axialen Druckschalter auf GND und den
anderen Natürlich an den µC. D.H. der Schalter ist dann low_aktiv im
Zusammenspiel mit dem internen Pullup. Die Kontakte von Drehgeber sind
für mich auch nichts anderes als 2 gekoppelte, zeitlich versetzte,
Schalter. Als lege ich auch hier den gemeinsamen Pin auf GND und Taste
die anderen beiden mit dem µC ab.
Ich denke du hast ein ähnliches Modell wie ich. Wie die andern (mit
Betriebsstapnnung) arbeiten hab ich auch noch nicht ganz geblickt.
Wenn ich mir die Schaltung unter Sprut.de anschaue.´dann denke ich mir
doch anhand der Pullup`s, das auch diese Schaltung lowaktiv ist. Aber
wofür brache ich denn dann noch +5V an Encoder.
Aber wahrscheinlich arbeiten die einfach mit einer schlaueren Technik.

von Ingo Henze (Gast)


Lesenswert?

@Markus
Ich hab mir auch die Dinger von Conrad bestellt, allerdings 705514 bzw.

705538, die sind wohl faktisch baugleich mit Deinem.
Das Datenblatt dazu ist aber deutlich besser, ab Seite 6 steht
eigentlich alles, was Du wissen mußt.
Zumindest hab ich die Teile problemlos in Betrieb nehmen können.

Gruß
Ingo

von Rahul (Gast)


Lesenswert?

Der Code von Sprut.de entspricht dem Ablaufdiagramm im Datenblatt
(#705514 von Conrad).
Die Abtastrate von 1ms hängt wohl mit dem RC-Glied am Eingang zusammen:
wenn man den Encoder schneller dreht bzw. abfragt, ergibt sich nur eine
Analogspannung am Eingang (meine Vermutung).
Die Eingangsbeschaltung mit dem RC-Glied dient dem Entprellen, was man
mit Peters Methode ja auch bewerkstelligen kann (weniger externe
Bauteile).
Gruß Rahul

von Stephan Schwarz (Gast)


Lesenswert?

Ich bin gerade dabei den Code von Peter mal zu zerlegen.
Mit dem Timer, das hab ich schonmal geschnallt.
Aber der Ablauf in der ISR ist mir noch nicht ganz klar.
wie kann ich denn folgende Zeile deuten?

#define Phase_A     (PINC & 1<<PINC0)
ich hab da eine Problem mit dem <<, die Verwendung in der Art ist mir
nicht klar, obwohl ich das nun schon oft gesehen habe.
Kann mir das bitte mal einer erklären.

PINC ist der Inhalt des 8Bit Registers, das den Zustand von PORTC
anzeigt. Diese 8 Bit werden mit (1<<PINC0) logisch bitweise verundet.
aber was stell der Ausdruck (1<<PINC0 dar)?

von Rahul (Gast)


Lesenswert?

Pinc0 müsste eine Zahl mit dem Wert 0 sein. Es wird also eine 1 auf
Stelle 2^0=1 nach links verschoben. Phase_a ist also die bitweise
Verundung des Inhalts des PortC mit 0x01. Es wird geprüft, ob das LSBit
1 ist. Beim 8051 gibt es dafür spezielle Bitoperationen, die aber auch
nur bei bestimmten Registern funktionieren.

von Stephan Schwarz (Gast)


Lesenswert?

Die Zeile ist aus dem Codebeispiel von Peter.
(siehe etwas weiter oben / ENCODE.C)

Dort ist aber PINCO aber nicht als Variable deklariert.
Also was ist PINCO dann??
Ich habe auch ähnliche Verständnisprobleme mit z.B.

TCCRO = 1<<CS01;
oder
TIMSK = 1<<TOIEO;

woher weis der µC denn dort, wohin oder wieweit, er die 1 schieben
soll? Ist CS01 und TOIEO irgendwo hinterlegt?

Aber wenn das stimmt, was du sagst Rahul, dann könnte ich anstatt
1<<PINCO auch einfach 0x01 schreiben.

von Rahul (Gast)


Lesenswert?

ja, kann man. PINC0 ist aber übersichtlicher, sobald man mit der
Nomenklatur von C etwas vertrauter ist.
PINC0, CS01, T0IE0 sind Definitionen in Header-Dateien. Einfach mal
eine .h-Datei im Editor öffnen. Da wirst du die Definitionen finden.
Gruß Rahul

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Schau dir doch einfach mal den Code von http://dse-faq.e-online.de an,
das ist eine einfache Zustandsmaschine bei der die Uebergaenge ganz
simpel in einer Tabelle abgelegt sind; das benoetigt sicher auch nicht
mehr Platz im Speicher als Peters Programm und ist meiner Meinung nach
einfacher zu durchschauen. Entprellen ist nicht noetig. Das
Sprut-Programm entspricht dem kleinen Ablaufdiagramm im
Conrad-Datenblatt und kann kein Prellen erkennen, im grossen
Ablaufdiagramm wird die Dekodierung richtig gemacht. Aber warum soll
man die Vorteile des Gray-Code verschenken nur um ein paar
Programmzeilen zu sparen?

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?


von Markus Krötz (Gast)


Lesenswert?

@Ingo und andere

Also schließe ich den Encoder praktisch folgendermaßen an?

A und B kommen an jeweils zwei Pins am Mikrocontroller. C kommt an GND.
E kommt an einen Pin am Mikrocontroller und F kommt wieder an GND?

Gruß

Markus

von Ingo Henze (Gast)


Lesenswert?

Ja genau, ich hab aber noch externe Pullup-Widerstände vom A und B (den
Druck-Taster verwende ich nicht) nach +5V angeschlossen, ist aber wohl
nicht unbedingt erforderlich.
Die im Conrad-Datenblatt angegebenen Kondensatoren nach Masse hab ich
weggelassen.
So funktioniert es bei mir sehr gut, ich frage nicht flankengesteuert
sondern die Zustände in einem Timer-Interrupt alle 4 ms ab (wurde
weiter oben beschrieben).

Gruß
Ingo

von Stephan Schwarz (Gast)


Lesenswert?

so hab mir das unter
http://dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29
mal geauer angeshen, da ich ja nun meinenCode auch mal optimieren will.
Peter kann ich leidernicht nachvollziehen.
Unter diesen Link wird ja beschrieben, das es genau 4 Zustände gibt,
die von einander zu unterscheiden sind. Dabei sind dann die Flanken an
sich garnicht so wichtig, sondern es geht um den Vorher - Nachher
Vergleich.
Nun hab ich mir meien Encoder mal auf dem OSZI mal genau angschaut und
sehe da ein ganz anderes verhalten. Ich kann da nur 3 Zustände ausmach.
Das sieht da so aus.

Rechtsdrehung
      _________        __________         _______
Sig 1           |______|          |_______|        |_______
      ______           _______            _____
Sig 2        |_________|       |__________|      |_______


Linksdrehung
      ______        __________         _______
Sig 1        |______|          |_______|        |_______
      ______           _______            _____
Sig 2        |_________|       |__________|      |_______



OK OK  vergesst es  ich könnte mich selber in **piep***   ** piepen**.
So eine verdammte   ***piep***.   Mir ist gerade was eingefallen.
Mein Decoder war falsch angeschlossen. Ich hab einfach mit einem Summer
versucht rauszufinden wo welcher Kontakt liegt, aber das geht natürlich
nicht. Und dadurch kammen so seltsame Signale raus. Die man auch nicht
vernünftig auswerte kann. Ich hatte Ihn einfach falsch angeschlossen.

So ich fang jetzt nochmal an  ------->   jetzt sollte es wohl leichter
gehen.

von Markus Krötz (Gast)


Lesenswert?

Also ich habe jetzt den Dreher angeschlossen (ohne Widerstand und
Kondensator), und benutze folgenden Code:

SIGNAL (SIG_OUTPUT_COMPARE2) {
  static uint16_t lc=0;
  static char enc_last = 0xFE;
  char i, j;

  lc++;

  if (lc % 6 == 0) {

    i = 0;
    if( PHASE_A )
      i = 1;

    j = 3;
    if( PHASE_B )
      i ^= j;        // convert gray to binary

    j = enc_last - i;      // difference last - new
    if( (char)(j & 1) ){      // bit 0 = value (1)
      enc_last = i;      // store new as next last

      i = enc_delta;
      if( (char)(j & 2) )      // bit 1 = direction (+/-)
        i -= 2;
      enc_delta = ++i;
    }

  }
  if (lc >= 1000) {
    //sekundenzähler hier hochzählen
    seconds++;
    if (seconds == 60) {
      minutes++;
    seconds = 0;
    if (minutes == 1440) {
      state1++;
      eeprom_write_block(&state1, &eeprom_var1, sizeof(state1));
      minutes = 0;
    }
    }
    lc = 0;
  }
}


Anschließend in der main-procedure folgendes:

lcd_gotoxy(12, 0);
lcd_puts (enc_delta);


Genialerweise passiert nun folgendes, wenn ich den Dreher bewege: Das
Display schaltet sich an und aus - leider ist das nicht unbedingt der
Effekt, den ich erzielen wollte ;-) - wo liegt mein Fehler?

von Markus Krötz (Gast)


Lesenswert?

Ich hab echt keine Ahnung, warum plötzlich der Impulsgeber mit dem
Display "verbunden" ist, das ergibt für mich überhaupt keinen Sinn.?

von Rahul (Gast)


Lesenswert?

wie sieht denn deine Schaltung aus? An welchen Pins hängt dein
Impulsgeber und an welchen dein Display? Aus dem Programm kann man das
sehr schlecht erkennen. (

von Markus Krötz (Gast)


Lesenswert?

Also der Impulsgeber hängt an A0, A1 und A2 (Taster, der aber noch nicht
angeschlossen ist) und das Display an PORTB (4bit).

Dementsprechend sehen meine Definitionen so aus:

#define PHASE_A  (PINA & 1<<PINA0)  // PINA.0
#define PHASE_B (PINA & 1<<PINA1)  // PINA.1

von Markus Krötz (Gast)


Lesenswert?

Hm, was mir außerdem noch aufgefallen ist: Der Impulsgeber (Conrad, die
Art.-Nr. 705514) hat neben 5 kleineren Anschlüssen (würde sagen, dass
sind A, B, C, D und E) auch "von den Seiten her kommende" zwei
Metallstecker oder was das sind. Die hab ich mal gar nicht
angeschlossen, aber für was sind sie dann eigentlich nütze (dachte
erst, man müsste sie mit GND verbinden, aber steht ja nix in der Doku)?
Vielleicht liegt auch hier mein Fehler?

Allerdings wird mir dann trotzdem noch nicht klar, warum das Display an
den Taster gebunden ist.

von Rahul (Gast)


Lesenswert?

sicher, dass nur das Display Probleme macht? Nicht, dass Du mit Hilfe
des Tasters noch einen nette Kurzschluss erzeugst...
Die beiden Kontakte die Du meinst sind vermutlich für die mechanische
Befestigung vorgesehen, damit die Kraft nicht direkt auf
Funktionskontakte geht.
Gruß Rahul

von Peter D. (peda)


Lesenswert?

lcd_puts (enc_delta);

Ich kenne ja Dein lcd_puts() nicht, aber eine Zahlenausgabe scheint mir
das nicht zu sein.

Versuchs mal mit itoa() und gib dann den String auf das LCD aus.


Peter

von Markus Krötz (Gast)


Lesenswert?

Also, ich habs gerade getestet: am Code liegt es definitiv nicht. Dann
habe ich den Dreher nochmal neu gelötet, mit Widerstand (10k) und ich
hatte das gleiche Ergebnis. Wenn ich aber den Ausgang C des
Impulsgebers nicht auf GND sondern weg gelötet habe, dann kam dieses
An- und Ausschalten des Displays nicht mehr - sonst kam es immer, egal
ob ich Spannung angeschlossen hatte oder nicht. Irgendwas stimmt mit
dem Ausgang C oder meinem GND nicht mehr. Ein Kurzschluss von C nach
GND ist keinesfalls zu erkennen. Das ist echt merkwürdig...

von Markus Krötz (Gast)


Lesenswert?

Wow, das liegt absolut außerhalb meiner physikalischen Kenntnisse!
Anscheinend kommt es (aus welchen Gründen auch immer) zu einem
Kurzschluss, sobald ich an den Schalter Spannung anlege (egal, ob mit
oder ohne Widerstand), bzw. wenn ich den Widerstand mit der
5V-Spannungsquelle verbinde. Das Messgerät misst nämlich dann an den
Widerständen 0 Ohm (bei 10 kOhm-Widerständen). Noch entschließt sich
diese physikalische Eigenschaft meines Verstandes, da ich nirgends
einen Fehler entdecken kann, darum meine Frage:

Wenn ich den Drehimpulsschalter ohne Spannung anschließen könnte, wäre
das perfekt, allerdings weiß ich nicht ob das geht (als ich es versucht
habe, hat mein LCD zufällig (also auch wenn ich nicht am Schalter
gedreht habe) Werte zwischen 600 und 0 angezeigt - mit dem obigen
Code).

Grüßle

der physikalisch etwas verwirrte Markus

von Markus Krötz (Gast)


Lesenswert?

So, um das Problem mit der Spannung zu umgehen, hab ich einfach
geschaut, wo am uC noch 5 Volt Spannung an zwei Pins rauskommen und
einfach dort diese beiden Ports mit dem Dreher verbunden.

Das sind beim ATmega16 in meinem Fall (die B-Ports werden schon
verwendet) die Pins PC2 und PC3.

Ich habe die Pins umgeschrieben

#define PHASE_A  (PINC & 1<<PINC2)
#define PHASE_B (PINC & 1<<PINC3)

aber das LCD zeigt immer 0 an! Mit einem Messgerät habe ich jedoch
nachgemessen, dass an PINC2 und PINC3 entweder 5 Volt oder 0 Volt
hängen, also der Schalter scheint zu funktionieren.

Wo liegt nun das Problem? Erkennt jemand meinen Fehler?
Kann ich den Drehimpulsgeber an den PORTC überhaupt anschließen?

Vielen Dank für Eure Hilfe

Markus

von Peter D. (peda)


Lesenswert?

Mega16 - Port C - JTAG

klingelts ?

Das kommt doch jeden Tag zweimal.

Peter

von Markus Krötz (Gast)


Lesenswert?

Ähm, sorry, so gut kenn ich mich nicht aus. Aber wahrscheinlich heißt
das ich muss JTAGEN auf 1 setzen oder so? Ich schau mal hier im Forum
nach, ob ich was dazu finde.

von Markus Krötz (Gast)


Lesenswert?

Also ich hab JTAGEN auf false gesetzt, du hattest Recht es war auch true
gesetzt! Aber das Programm funktioniert trotzdem noch nicht :-(.

(PORTC&0x02) scheint immer wahr zu sein :-(.

von Markus Krötz (Gast)


Angehängte Dateien:

Lesenswert?

Hab mal mein Programm mitgeschickt. Auf dem LCD wird die ganze Zeit 0
angezeigt!

von Peter D. (peda)


Lesenswert?

if (PORTC&0x03) //T1 gedrückt wird

So kanns ja nicht gehen.
Du mußt die der Pinnummer entsprechenden Bitmasken nehmen, d.h. es darf
nur ein einziges Bit in der Maske gesetzt sein.

Warum nimmst Du nicht meine Schreibweise für die richtige Bitmaske ?


Peter

von Peter D. (peda)


Lesenswert?

Und PORTC geht schonmal garnicht.


Peter

von Markus Krötz (Gast)


Lesenswert?

... weil leider auch net gegangen ist :-(

Hält mich noch jemand anderes außer ich selbst für nen Trottel. Das
Ding will einfach nicht den Port auslesen, dabei kann ich sogar mit dem
Messgerät messen, dass einmal 0 und das andere Mal 5 Volt anliegen!

von Markus Krötz (Gast)


Lesenswert?

Der LCD zeigt meiner Meinung nach keine sinnvollen Zahlen an, manchmal
055, 455, 355, 0. Die Zahl wechselt aber nicht bei jedem Dreh, sondern
willkürlich.

von Rahul (Gast)


Lesenswert?

wie wäre es denn, wenn Du erst mal den Inhalt der Eingangspins auf LEDs
ausgibst?
Scheinbar mangelt es dir daran, Peters Code zu verstehen, und dann die
erzeugten Daten auf dem Display richtig darzustellen.
Notfalls könntest du den Drehencoder auch durch 2 Tasten simulieren,
und so dein Programm testen.
Übrigens ist (1<<PINC3) nicht 0x03, sondern 0x08, also 2 hoch 3.
Dein Ausdruck muß demnach (PORTC & 0x80) heissen, wobei einlesen von
Ports besser mit PINC gemacht werden (zumindest habe ich das irgendwo
in der AVR-LIBC mal gelesen...; gilt halt für den AVR-GCC).

Ich weiss ja nicht, welche Vorkenntnisse Du hast, aber mir scheint,
dass dir irgendwo noch so einiges fehlt.
Teilweise benutzt du in deinem Program _BV(...) und dann kennst du
Ausdrücke wie "1<<PINC0" nicht. Dabei bedeutet _BV(PINC0) nichts
anderes.

von Markus Krötz (Gast)


Lesenswert?

Ne, das mit den Pins kapier ich schon, nur habe ich halt n paar Sachen
ausprobiert und es funktioniert noch immer nicht (aber im Allgemeinen
mangelt es mir schon an Kenntnis).
Ich kann schon vorhersagen, was pasiert, wenn ich den Inhalt des
Eingangspins auf LED's ausgebe. Sie leuchten und wenn ich den
Drehimpulsgeber in irgendeine Richtung drehe, leuchten sie nicht. Bei
der nächsten Drehung leuchten sie wieder. Wie gesagt, dass kann ich ja
schon mit nem Messgerät messen, dass manchmal 5Volt und manchmal 0 Volt
anliegen.

Das Problem ist aber, dass mein Programm nicht erkennt, dass an PC2
oder PC3 eine 1 oder eine 0 liegt - komischerweise.

Bei der Fehleranalyse tendiere ich eher dahin, dass ich vielleicht
irgendwo einstellen muss, dass ich die PC2 und PC3 als Eingabe
verwenden möchte?

Muss ich evtl. irgendwo PORTC mit 0b00110000 initialisieren oder so?

von Ingo Henze (Gast)


Lesenswert?

Na das ist doch schon mal was. Bei Drehung leuchten beide LEDs oder gar
keine, so muß es auch sein.
In der eingerasteten Stellung des Drehgebers sind immer gleichzeitig A
und B mit C verbunden, bzw. beide nicht.
Die Richtung kann man nur während des Übergangs von einer Raststellung
zu nächsten ermitteln, hier schalten dann A oder B entsprechend früher
oder später in den jeweils anderen Zustand.

Ok, zumindest ist das so bei meinem Drehgeber von Conrad, ich kann
allerdings nicht ausschließen, das es auch andere gibt, die anders
funktionieren :-)

Wichtig erscheint mir der Hinweis mit PINC_ anstelle _PORTC, einlesen
geht doch nur über die PINx-Ports denke ich!

Gruß
Ingo

von Stephan Schwarz (Gast)


Lesenswert?

@ Markus

"Muss ich evtl. irgendwo PORTC mit 0b00110000 initialisieren oder
so?"


jo , jetzt hab ich auch mal in deinen Quellecode geschaut, Du benutzt
also die ISR von Peter.  Hast du die wirklich nachvollziehen können?
na egal, also ich arbeite nur mit Code, denn ich auch lesen kann.
Klar musst du die Datenflussrichtung am PORT bzw. PIN bestimmen, dafür
gibts ja die DDRX.  Kannst ja nochmal in dem Code nachschauen, denn ich
mal gepostet habe.
Aber wenn du dir bei einer bestimmten stelle in Programm nicht sicher
bist, wie es sich verhält. Dann würde ich dir dazu raten das Programm
bis auf eine Minimum der Funktionen zu reduzieren. So hab ich bisher
schon einige Fehler bei mir selber ausmärzem können.
In deinem Fall. musst du doch erstmal prüfen, ob deine Eingänge
überhaupt etwas im MC bewirken, also einfach alles rausschmeissen an
überflüssigem Code. Die PINS als Eingang setzen, eine Schalter
dranklemmen und in der TIMER ISR einfach mal eine LED je nach Status
der Taster ein oder auschalten.  Dann weisst du ob deine Eingänge
funktionieren und ob die ISR ausgeführt wird. Damit wärst du schon
einen riesen Schritt weiter und es dauert nur 10 min.  Wenn es nicht
klappt, würde ich mich erstaml mit den einfachen Sachen beschäftigen.
Z.B. LED über Schalter ein / aus schalten...........  usw.

von Markus Krötz (Gast)


Angehängte Dateien:

Lesenswert?

Sehr gute Neuigkeiten, bald seid ihr wahrscheinlich von mir erlöst.
Ich benutze nun Peter's Code und das Hochschalten funktioniert schon
fast ;-)

Leider verstehe ich den Code nicht so richtig, da habt ihr allerdings
richtig Recht.

Folgendes passiert nun:

Zu Beginn steht der Counter auf 0; Dann geht er bei der nächsten
Umdrehung nach oben auf 055, dann auf 255, 455, 655, 855, 1055, 1255,
etc. Wenn ich runterdrehe geht er von 0 auf 0 und dann auf 254, 252,
250, etc. Er geht also in Zweierschritten runter.
Wenn ich nun im Intervall von 0-254 wieder hochdrehe geht er (fast
korrekt) in Zweierschritten nach oben (fast korrekt, weil er ja in
Einerschritten hochzählen soll).

Kann mir jemand vielleicht ein allerletztes Mal helfen und sagen, wo
der Fehler liegt? Ich verstehe nämlich nicht, warum er das macht und
hab schon alles mögliche probiert. Anbei mein Code.

Vielen vielen Dank

Markus

von Markus Krötz (Gast)


Lesenswert?

Was ich vergessen habe: Eigentlich soll mein Zähler die Minuten in
Einserschritten hoch- oder runterzählen und das im Bereich von 0-1440.

von Peter D. (peda)


Lesenswert?

"int32_t minutes = 0;"


Du solltest Dich schon mal mit den Zahlenformaten beschäftigen, d.h.
wenn du "int32_t" benutzt auch wissen, was das bedeutet.

2^32 Minuten sind nämlich 8000 Jahre !

Warum willst Du so weit zählen ?


Wenn Du ein long nach char abschneidest und dann wieder nach long, das
muß ja schief gehen !

Bei Zuweisungen in ein anderes Zahlenformat, muß man immer prüfen, ob
das Ergebnis auch richtig ist.


Nimm doch zum Test erstmal "char" Werte, dann sind nur Zahlen von
-128...127 möglich.


Du änderst ziemlich planlos und an vielen Stellen gleichzeitig rum und
wunderst Dich dann, warum nichts mehr geht.
Mich wundert das nicht.

Versuchs mal mit der Baby-step Methode:
Mache nur eine Sache, teste sie und mache dann den nächste Schritt,
teste wieder usw.


Peter

von Stephan Schwarz (Gast)


Lesenswert?

ganz mein Reden Peter!  Bezüglich der Babysteps

und irgendwann verstehen wir ( Markus & Ich )  dann auch deinen Code
:-)

von Ingo Henze (Gast)


Lesenswert?

Fremden Code verstehen, gut und schön.
Und man muß das Fahrrad ja auch nicht immer wieder neu erfinden.

Aber für mich war es in vielen Fällen sehr hilfreich, daß ich mich
erstmal selber hingesetzt und überlagt hab, wie funktioniert das ganze
(die Harware, z.B. der Drehencoder) und wie kann ich das nun
programmtechnisch erfassen.
Und da hab ich mir einfach mal Papier und Bleistift genommen (wie
altmodisch :-) und mir das ganze aufgezeichnet/aufgeschrieben, z.B. die
möglichen Schalterzustände des Encoders mit 0 und 1.
Ja und dann hat es auch schnell "Klick" gemacht, sowohl beim Encoder
als auch bei mir selbst.

Gruß
Ingo

von Rahul (Gast)


Lesenswert?

So, ich bin endlich durch Peters Code durchgestiegen.
Kann es sein, dass Du Else-Zweige vermeidest?
Das macht den Code etwas unübersichtlich.
Prinzipiell müsste Markus nur die letzte IF-Abfrage in deinem Code
umändern, und zwar für den Fall, dass Bit 1 gesetzt ist, die Minuten in
die eine Richtung verändern und falls es gelöscht ist, in die andere
Richtung. Die Richtung hängt ja nicht nur von der Software, sondern
auch von der Hardware ab. Sehe ich das richtig?
Sie ist zumindest wahlfrei (also auch Linkshänder geeignet).
Und du gehst davon aus, dass enc_delta zu Beginn des Programms =0 ist?

Erklärung für Leute, die da noch nicht durchgestiegen sind:
Die Encoder liefern in der Raststellung eine zweitellige Binärzahl mit
zwei gleichen Elementen (00 oder 11).
Wird der Encoder bewegt, so wird nur eins der beiden Elemente
verändert. (Gray-Code / Phase_A und Phase_B)
Je nach dem, welcher Eingang sich verändert hat, wird der Variablen i
eine ungerade Zahl zugeordnet. Dadurch wird ein Schritt erkannt. In
welche Richtung sich bewegt wird, entscheidet das Bit 1.

Zu Ingo: Ich hätte es wahrscheinlich so wie Stephan mit 2
Hardware-Interrupts gemacht.
Gray-Code kannte ich zwar, aber irgendwie fehlte mir die Verbindung zu
Drehencodern mit nur zwei Ausgängen. Wir hatten das in Digitaltechnik
nur als Absolut-Drehencoder, sprich 4 Stellen für 16 Werte... Oder so,
ist schon wieder etwas her...
Die Impulsfolge erinnert auch an die Ansteuerung von Schrittmotoren...

Rahul

von Eddi (Gast)


Lesenswert?

n'Abend

Ich hab einfach mal meinen Encoder angelötet und Peters Code
ausprobiert. Abgesehen davon, daß ich noch die internen PullUps
angeschaltet und andere Pins genommen habe funktioniert das tadellos.
Hardware ist ein Mega32 mit 16MHz, Encoder an PIND6 und PIND7.

Ein weiteres riesen Dankeschön an den Meister !

Gruß
Eddi

von Peter D. (peda)


Lesenswert?

Ich habe hier mal versucht, die Wirkungsweise meines Codebeispiels
ausführlich zu erklären:

http://www.mikrocontroller.net/forum/read-4-37992.html


Die letzte Anweisung habe ich etwas umgeschrieben, ist einfacher zu
lesen, aber funktional identisch.
Da keine Zwischenvariable verwendet wird, muß man auch nicht mehr
aufpassen, ob char, int oder long gezählt werden soll.


Peter

von Markus Krötz (Gast)


Lesenswert?

Also es tut mir ja wirklich leid, aber ich habe nun noch einmal Peter's
Code benutzt und das Ding funktioniert noch immer so wie ich oben
beschrieben habe (nämlich im Zweierschritt und wenn ich bei 255
hochdrehen will, dann geht er auf 155, 255, 355, 455, ...).

Ich lasse mir die Werte nun dezimal auf den Bildschirm schreiben, die
an PHASE_A und PHASE_B liegen und komischerweise bekomme ich entweder 0
0 oder 4 8 angezeigt! Das hat aus meiner Sicht überhaupt nichts mit 00,
01, 11, 10 zu tun! Stimmt da was nicht?

von Eddi (Gast)


Lesenswert?

Hi Markus

Stimmt, daß mit den Zweierschritt habe ich bei dem Conrad-Drehgeber
auch.
Die Anzeige der Zahlen ist schon so "richtig". Nach 255 kommt 1 und
wenn du keine führenden Nullen bzw. Leerstellen ausfilterst ´bleibt
halt die 2. und 3. Stelle als 55 stehen. Ist also ein reines
Anzeigeproblem (ich benutze itoa() und wandle in 3stelligen char um).

Gruß
Eddi

von Markus Krötz (Gast)


Lesenswert?

Jo, ich habs gerade eben auch gemerkt, ich Dackel ;-). Wie hast du denn
das Problem mit den Zweierschritten bei dir geregelt?

Bei mir funktioniert jetzt alles, nur eben wird in Zweierschritten
hoch- und runtergezählt, was bei mir aber leider nicht der Fall sein
darf :-(.

von Eddi (Gast)


Lesenswert?

Momentan teil ich einfach durch 2 :) Sollte aber nicht die endgültige
Lösung sein.
Ich habs scon mit Änderung der Abfragerate durch Änderung des
Vorteilers probiert. Half auch nicht. Ich werde mir wohl nochmal das
Datenblatt des Drehgebers angucken, vielleicht findet man da ja eine
Lösung.

von Markus Krötz (Gast)


Lesenswert?

Was teilst du denn durch 2? Ich habs auch versucht, aber kein gescheites
Ergebnis rausbekommen (vielleicht teile ich auch was falsches).
Könntest du evtl. deinen Code posten?

Vielen Dank, Eddi

Grüßle

Markus

von Ingo Henze (Gast)


Lesenswert?

Mit der Abfragerate hat das nichts zu tun.
Hab mir Peters Code nicht genau angeschaut, aber allgemein möchte ich
folgendes sagen:
Man sollte nur den Übergang der Zustände in einer Richtung auswerten.
Also z.B. von
11 -> 01 bzw. 11 -> 10 (je nach Drehrichtung)
aber nicht dann auch noch von
01 -> 00 bzw. 10 -> 00

Das wär so, als würde man bei der PC-Tastatur sowohl beim Drücken als
auch beim Loslassen ein Tastencode erzeugen :-)

von Fritz Ganter (Gast)


Lesenswert?

"Das wär so, als würde man bei der PC-Tastatur sowohl beim Drücken als
auch beim Loslassen ein Tastencode erzeugen :-)"

Aber genau so ist es: Es gibt bei Tastatur und Maus ein Press und ein
Release event.

von Ingo Henze (Gast)


Lesenswert?

Jaja, das ist schon klar.
Nur wenn ich hier bei mir auf der Tastatur, sagen wir mal auf die Taste
"A" drücke (und schnell genug loslasse, sonst passieren da noch ganz
andere Dinge:-), erscheint da nur ein A.

Beim Drehendcoder will ich ja nur einen Tick haben, von einer
Raststellung zur nächsten (sofern er Raststellungen hat), und da reicht
es dann auch, nur einen Übergang auszuwerten.

von Markus Krötz (Gast)


Lesenswert?

Und was würde das hinsichtlich Peter's Code bedeuten?

von Markus Krötz (Gast)


Lesenswert?

Ich glaube, Ingo hatte wirklich Recht. Wenn ich mich recht entsinne
frägt Peter's Code 8 Zustände ab.
Ich habe mir - auch aufgrund Ingo's Antwort gedacht, einfach mal alle
Übergange anzeigen zu lassen und bin auf folgende gekommen (fragt mich
bitte nicht, warum meine Zahlen so komisch sind und nicht aus 00, 01,
10 oder 11 besteht, aber ihr werdet sehen, dass das identisch ist):

Zwei Übergänge (Peter's Code rechnet 4) bei Linksdrehung:

40 -> 00
08 -> 48

Und zwei Übergänge (Peter's Code rechnet wieder 4) bei Rechtsdrehung:

40 -> 48
08 -> 00

Daraus habe ich dann folgenden Code entwickelt (naja, ich hab nicht
viel überlegt, sondern einfach mal eingetragen zum Testen. Das lässt
sich natürlich noch optimieren ;-)):

// Der Drehimpulsgeber benutzt die Pins C2 und C3
#define PHASE_A  (PINC & 1<<PINC2)
#define PHASE_B (PINC & 1<<PINC3)

volatile int enc_delta = 0;
int old_a = 0;
int old_b = 0;
int new_a = 0;
int new_b = 0;

void init_timer (void) {
  TCCR2 = _BV (CS22) | _BV (WGM21);
  OCR2 = 124;
  TIMSK = _BV (OCIE2);
  DDRC  = 0xf3;   // PortC als Ausgang, 1111 0011, bis auf PC2,PC3
  PORTC = 0x0c;  // 0000 1100
  sei ();
}

SIGNAL (SIG_OUTPUT_COMPARE2) {
  static uint16_t lc=0;  // interner Counter
  char i = 0; // Peter's Code

  lc++; // erhoehe Counter

  // wenn Counter durch sieben teilbar, also alle 7ms, tue
  if (lc % 7 == 0) {

    if( PHASE_A )
      i = 1;

    if( PHASE_B )
      i ^= 3;

    i -= enc_last; // Differenz

    if( i & 1) {

      // Diese vier Zeilen sind neu
      old_a = new_a;
      old_b = new_b;
      new_a = PHASE_A;
      new_b = PHASE_B;
      enc_last += i; // Peter's Code

      // Berechne Links- oder Rechtsdrehung
      if ((old_a == 4) & (old_b == 0) & (new_a == 0) & (new_b == 0)) {
        enc_delta++;
      } else if ((old_a == 0) & (old_b == 8) & (new_a == 4) & (new_b ==
8)) {
        enc_delta++;
      } else if ((old_a == 4) & (old_b == 0) & (new_a == 4) & (new_b ==
8)) {
        enc_delta--;
      } else if ((old_a == 0) & (old_b == 8) & (new_a == 0) & (new_b ==
0)) {
        enc_delta--;
      }
    }
  }

  // Jede Sekunde, mache...
  if (lc >= 1000) {
    //sekundenzähler hier hochzählen
    seconds++;
    lc = 0; // Counter zuruecksetzen
  }
}

Bei mir funktioniert der Drehimpulsgeber nun perfekt ;-)

von Peter D. (peda)


Lesenswert?

Die Erklärung ist einfach:

Jeder Drehgeber macht 4 Phasen, aber nicht jeder rastet auch auf jeder
Phase ein.

Sehr empfindliche Drehgeber (z.B. 100 Schritte je Umdrehung) rasten auf
jeder Phase, da zählt der Code +/-1.

Unempfindliche Drehgeber (z.B. nur 10 Rastschritte) rasten nur jede 4.
Phase ein (+/-4), d.h. man teilt das Ergebnis /4 (= 2*
rechtsschieben).

Dazwischen gibt es eben auch welche, die jede 2.Phase einrasten (+/-2),
also Ergebnis /2 teilen (= 1* rechtsschieben).

Wenn Du Deinen Drehgeber also langsam drehst und nicht einrasten läßt
(festhälst), merkst Du deutlich, daß mein Code korrekt immer einen
Schritt weiterzählt, aber nur jeden 2.Zählwert eine Rastung erfolgt.


> Zwei Übergänge (Peter's Code rechnet 4) bei Linksdrehung:
>
> 40 -> 00
> 08 -> 48

Nein, das macht er eben nicht !!!

Du nimmst nicht das Ergebnis meines Codes, sondern liest die Pins
nochmal vollkommen neu ein:

> new_a = PHASE_A;
> new_b = PHASE_B;

Und dann gilt eben:

PINC2 = 4
PINC3 = 8

Frische bitte nochmal Deine Kenntnisse bezüglich Rechnen mit
Binärzahlen auf, dann weißt Du auch warum.
Dadurch ist Dein Code auch nicht mehr Pin unabhängig.

Mein Code liefert dagegen immer 0,1,2 oder 3.



Peter

von Stephan Schwarz (Gast)


Angehängte Dateien:

Lesenswert?

Hallo nochmal

Bei mir ruhte das Thema etwas, aber nun läuft das Ding endlich.
Nachdem ich dann auch begriffen habe, dass es nicht um die Übergänge
der "Schalterstellungen" beim Encoder geht, sondern einfach nur ein
schneller Vergeich der Zustände ( alt und neu ) nötig ist. Die Abfrage
über den Timer ist dabei doch deutlich schneller als, die
Schaltgeschwindigkeit des Encoders. Selbst bei sehr schneller Umdrehung
mit der Hand, hat man immer noch
min. 2 ms zum auswerten. Bei einer Taktfrequenz von 3,6846 MHZ
und einem Vorteiler von 64 fragt der µC immer noch alle 17µS den
Encoder ab. Also muss man sich dahin keine Sorgen machen. Der Vorteiler
kann sogar noch höher ausgelegt werden.

Ich hab das Thema noch mal aufgegriffen, weil ich als Einsteiger leider
mit Peter`s Code nicht zurechtkam und mir auch selber was basteln
wollte.
Ich denke mein Code ist was einfacher zulesen, und hilft evtl. Leuten
die sich später mal mit dem gleichen Thema  „rumärgern“.

Kann gtu sein, das der Code deutlich verbesseet werden könnte, aber es
funktioniert sehr gut und ist eben auch schön verständlich.
(hoffe Ich)

bis dann mal Stephan

von McMurkser (Gast)


Lesenswert?


Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.