Hallo ich versuche einen Drehimpulsgeber von Conrad(705594 - 62) an meinem xmega128A1 zu betreiben. Angeschlossen sind PinA und PinB des Impulsgebers an PORTC Pin0 und Bin1. Ich verwende hierfür die integrierten PullUps(PORT_OPC_WIREDANDPULL_gc). Folgender Code wird in einem Interrupt jede Millisekunde ausgeführt: cli(); newB = (PORTC.IN & 0x02); newA = (PORTC.IN & 0x01); if(newB != oldB || newA != oldA) { xorA = newA != oldA; xorB = newB != oldB; if(oldA == oldB) { if(xorA == 0 && xorB == 1) cnt++; if(xorA == 1 && xorB == 0) cnt--; } else { if(xorA == 0 && xorB == 1) cnt--; if(xorA == 1 && xorB == 0) cnt++; } oldA = newA; oldB = newB; } sei(); Leider funktioniert dieser Code nur halb. Bei einer Drehung im Uhrzeigersinn wird wie gewollt incrementiert aber anschließend sofort wieder decrementiert. Nach dem 3. Drehimpuls wird dann 2 mal decrementiert. Bei einer Drehung gegen den Uhrzeigersinn ist das gleiche Verhalten zu beobachten nur wird nach dem dritten Drehimpuls doppelt incrementiert. Ich starre den Code nun schon eine geschlagene Stunde an aber weiß nicht, wo das Problem liegt. Bei der logischen Gestaltung habe ich mich an den Algorithmus aus dem Datenblatt des Drehimpulsgebers gehalten welcher hier auch angefügt ist. Seht ihr vielleicht wo das Problem liegt? Danke schon mal Gruß Domi
Dominik schrieb: < Ich starre den Code nun schon eine geschlagene Stunde an aber weiß > nicht, wo das Problem liegt. Das du den Code anstarrst ist zwar schön, wie du aber gesehen hast, hilft dir das nicht viel. Nimm Papier und Belistift, 'erfinde' die Eingangswerte, für den Ablauf, der zu Problemen führt und geh den Code durch, wobei du alle Operationen genau so machst, wie sie dein Computer auch macht. So findet man raus, wo man den Denkfehler gemacht hat.
Das mit dem "Anstarren" war eine Anspielung auf die vielen Lösungsversuche die ich schon hinter mir habe. Unter anderem auch das durchspielen eines Beispiels. Aber danke für den Hilfeversuch.
und den cli() bzw. sei() entfernst du stillschweigend gleich mal aus der ISR (aber das ist im Moment nicht das Problem)
Dominik schrieb: > Das mit dem "Anstarren" war eine Anspielung auf die vielen > Lösungsversuche die ich schon hinter mir habe. Unter anderem auch das > durchspielen eines Beispiels. Na dann zeig doch mal. Der ENcode steht auf A B oldA oldB xorA xorB 0 0 0 0 jetzt wechselt der Encoder zu 1 0 wie gehts weiter? Dann wechselt er zu 1 1 und weiter gehts zu 0 1 und 0 0 für diese Reihenfolge (ich hoffe ich hab mich da jetzt nicht vertan) spielst du die entsprechenden Durchläufe durch die ISR durch (wobei du natürlich dann auch immer den jeweils vorhergehenden Wert von oldA und oldB benutzt). Ecntschulige: aber wir müssen hier auf der anderen Seite des Bildschirms genau das gleiche tun, um dem Fehler auf die Spur zu kommen. Da es aber dein Projekt ist, solltest du das in erster Linie tun und nicht wir.
Das Problem könnte auch im Drehgeber selbst liegen. Die Dinger prellen wie Hund und die Überlappung der Kontakte ist nicht so wie im Datenblatt. Wenn Du die Möglichkeit hast guck Dir das Ding mal mit einem Ossy an dann siehst Du vielleicht das es so nicht gehen kann. mfG Michael
michael_ohl schrieb: > Das Problem könnte auch im Drehgeber selbst liegen. Die Dinger prellen > wie Hund und die Überlappung der Kontakte ist nicht so wie im > Datenblatt. Mit entprellender Software ist das überhaupt kein Problem. Peter
Gemäß dem Fall dass sich jeder um seine Fehler und Anliegen kümmert auch wenn dies Stunden dauert hätte das den Verlust der Existenzberechtigung dieses Forums zur Folge. Gepostet habe ich mein Problem hier da ich mir sicher bin, dass jemand der schon mal einen Drehgeber in Betrieb genommen hat, den Fehler sofort sehen würde. Und ich denke viele Beiträge dieses Forums beruhen auf dieser Intention aber ich möchte keine Grundsatzdiskussion beginnen sondern mein Problem lösen. Anstatt nochmal ein Beispiel händisch durch meinen Corde zu exorzieren habe ich mal ein Beispiel durch das angefügte Schema geführt. Mit dem Ergebnis, dass da was nicht stimmen kann da dort die Unterscheidung zwischen Übergang(AB = 01/10) zu einer Auswertung führt und die anschließende Endposition(wechsel zu AB = 11/00) nochmals. Ich scheine den Code noch nicht verstanden zu haben. Gehe ich richtig in der Annahme das bei jeder Einrastung des Drehgebers AB = 00 oder 11 ist und nur bei einer Drehung sich entweder A oder B zuerst ändert. Also 1. Rastpunkt: AB = 00 Übergang CW: AB = 10 2.Rastpunkt: AB = 11 übergang CCW: AB = 01 1. Rastpunkt: AB = 00 Gruß Domi
Der Knackpunkt ist, daß es bei jedem Phasenwechsel zu Prellungen kommen kann. Du mußt daher Deinen Code daraufhin abklopfen, ob er jederzeit diese Prellungen kompensieren kann. Mein Code geht daher den Ansatz, daß er alle 4 Phasenwechsel zählt. Und da sich gemäß Graycodedefinition immer nur ein Pin ändert, zählt er jeden zuviel gezählten Preller bei der nächsten Abtastung exakt wieder zurück. Nur für die Auswertung wird dann das Ergebnis je nach Rastung /2 bzw. /4 geteilt, wobei die für die Entprellung wichtigen unteren Bits erhalten bleiben. Es mag andere effizientere Lösungen geben, aber solange eine Lösung nicht funktioniert, gehört sie nicht zu diesen. Du mußt also nur feststellen, ob Deine Lösung auch zielführend oder eine Sackgasse ist. Ich denke, für ein Forum reicht es, eine funktionierende Lösung aufzuzeigen. Damit jemand kostenlos Arbeit für Dich aufwendet, muß es dafür auch einen Anreiz geben. Also ein Problem, für das es noch keine oder nur eine sehr aufwendige Lösung gibt. Peter P.S.: Haben die Xmega nicht sogar Encoderhardware?
Dein Code sieht richtig aus. Stimmen die Zeitdigramme im Datenblatt, sollte der Zähler (cnt) bei jeder Raste genau zweimal inkrementiert bzw. dekrementiert werden. Deine Beobachtungen deuten aber daraufhin, dass die Diagramme im Daten- blatt nicht stimmen, und dass die Rastpunkte nicht zwischen, sondern auf den Flanken eines der beiden Signale A und B liegen. Dann kann der Zähler bei einer Drehung auf die jeweils nächste Raste 1, 2 oder 3 Inkremente weiterzählen. Bei der Auswertung muss dies natürlich berück- sichtigt werden. Das Ablaufdiagramm aus dem Datenblatt wäre dann falsch. Das wäre nicht weiter verwunderlich, denn auch das zweite Ablaufdiagramm (mit der Interruptsteuerung) ist Murks. Drehgeberauswertungen, die durch einen Interrupt eines der beiden Drehgebersignale ausgelöst werden, haben noch nie zuverlässig funktioniert. Um festzustellen, ob obiges auf deinen Drehgeber zutrifft, musst du nachschauen, wann genau die Signale A und B umschalten. Liefert bereits eine minimale Bewegung des Drehgebers aus einer Rastposition heraus nach rechts oder links eine Signalflanke, musst du deine Auswertung ändern. Ist hingegen auf beiden Seiten der Rastposition etwas Luft, in der sich die Signale nicht ändern, entspricht der Drehgeber dem Datenblatt, und irgendwo hat sich noch ein anderer Fehler versteckt.
Wie du bereits sagtes gibt es die Möglichkeit einer effizienteren Lösung. Aus diesem Grund lasse ich mich ungerne von anderen Quellcodes leiten da man durch dessen logische Vorgehensweise vorbelastet wird und diese oft unbewusst übernimmt. Nach 2 weiteren Stunden des "Anstarrens" meines Codes bin ich nun endlich auf eine alternative Lösung gekommen welche immun gegen prellen ist. Ob diese nun effizient ist oder nicht darf jeder für sich beurteilen. Vorab noch: der eigentliche Fehler lag in der Datentypengestaltung meiner Variablen newA newB oldA usw. Durch die Verwendung des in stdbool.h enthaltenen bool Datentyps funktioniert folgender Code nun einwandfrei bei mir: newB = (PORTC.IN & 0x02); newA = (PORTC.IN & 0x01); if(newB != oldB || newA != oldA) { if(oldA == oldB) { xorA = newA != oldA; xorB = newB != oldB; if(xorA == 0 && xorB == 1) cnt--; if(xorA == 1 && xorB == 0) cnt++; } } oldA = newA; oldB = newB; Wie bereits angedeutet wird die Drehrichtung aus dem Verlassen der Gleichheit von A und B erkannt. In einer Rastposition ist A und B immer gleich. Bewegt sich der Drehgeber ändert sich entweder A oder B zuerst. War vor dieser Änderung A und B gleich so ergibt sich die Drehrichtung aus dem Zuerst geänderten Wert. Ich poste diese Lösung unter Vorbehalt. Ich habe sie nicht auf extreme Rahmenbedingungen getestet. Gruß Domi
Stichwort Rahmenbedingung: Ich verwende keine Hardware-Entprellung und verwende die internen PullUps. Somit ist der Drehgeber direkt an den XMega angeschlossen.
Dominik schrieb: > Vorab noch: der eigentliche Fehler lag in der Datentypengestaltung > meiner Variablen newA newB oldA usw. Stimmt, das hatte ich übersehen, als ich schrieb, dass der Code richtig aussähe. Das Probem liegt in dieser Zeile:
1 | if(oldA == oldB) |
Sind die alten Signalpegel beide high, dann ist oldA=1 und oldB=2, so dass sie fälschlicherweise als ungleich ausgewertet werden. Mit der Verwendung von Bool-Variablen ist der Wertebereich auf {0, 1} einge- schränkt, so dass dieses Problem nicht auftreten kann.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.