Archiv verlassen und diese Seite im Standarddesign anzeigen : Drehimpuls auswerten
Hi!
Stehe wieder vor dem Problem, einen optischen Encoder oder Drehgeber auszuwerten. Mir hat damals jemand geholfen. Doch leider hab ich durch meinen Festplatten Crash alles damals verloren. Ich versuch mir momentan selber an dem Teil. Nur gibt es da ein Problem. Ich kann zwar die Richtung erkennen, doch leider springt der 2051er auch manchmal in die andere Richtung und zählt falsch herum. Kann mir einer bitte weitere Tips dazu geben, dieses Problem zu beheben? Schon mal Vielen Dank!
Hi.
Mein Programm ist zwar sehr verschwenderisch, weil der Controller dann nichts mehr anderes tut, aber es funktioniert zu 100 %. Man braucht halt dann einen zweiten Controller. Habe es gestern mit einer Timerabfrage probiert, funktioniert auch super, dann braucht man nur einen Controller. Aber hier das erste programm, ganz einfach..
INCLUDE 89C2051.mc
abfrage:
IF P1 = #11111111b THEN JMP aus
IF P1 = #11111100b THEN JMP ein
JMP abfrage
aus:
IF P1 = #11111110b THEN
CLR P3.0
NOP
NOP
SETB P3.0
LCALL wait_20000
JMP abfrage
END IF
IF P1 = #11111101b THEN
CLR P3.1
NOP
NOP
SETB P3.1
LCALL wait_20000
JMP abfrage
END IF
JMP aus
ein:
IF P1 = #11111110b THEN
CLR P3.1
NOP
NOP
SETB P3.1
LCALL wait_20000
JMP abfrage
END IF
IF P1 = #11111101b THEN
CLR P3.0
NOP
NOP
SETB P3.0
LCALL wait_20000
JMP abfrage
END IF
JMP ein
INCLUDE wait.asm
Hallo!
Ich leiste hier mal etwas Hilfe zur Selbsthilfe:
Im Bild ist ein Pulsdiagram, das so ein Drehgeber abgibt. Blau ist die eine Richtung und Rot die andere.
Sehr einfach wird es, wenn man einen ext. Interrupt benutzt, der nur auf die 'fallende Flanke' von 1 nach 0 reagiert. Wird dieser durch clock ausgelöst, muß nur in Abhängigkeit von dir ein entsprechendes Register hoch bzw. runtergezählt werden.
Int_ext_0
JNB Port_DIR,Andersrum
INC Drehgeber_Byte
RETI
Andersrum
DEC Drehgeber_Byte
RETI
Will man keinen ext. Interrupt opfern, muß ein internes Speicher-Bit her, um die 'fallende Flanke' erkennen zu können. Dieses Bit nimmt den Zustand von Clock bei der Letzten Abfrage auf. Nur wenn dieser in der vorherigen Abrfrage 1 war und nun 0 ist darf geschaltet werden, wobei auch beim Schalten nicht vergessen werden darf, das Speicher-Bit zu aktualisieren.
Läuft jetzt immer noch etwas schief, läßt sich eingrenzen, wo der Fehler liegt:
- Zähler macht was er will: Code und Pegel des Gebers prüfen
- Zähler zählt mehr als nur einen Impuls (Richtung stimmt): clock entprellen
Ich hoffe, daß hilft weiter... .
Gruß,
Arne
Hi!
Also, habt vielen Dank für die stetige Hilfe hier im Forum. Das Problem mit dem Encoder hat sich erledigt. Es funktioniert super! Es wird auch immer nur 1 Pulse gezählt und man kann nebenbei noch etwas anderes machen. Also keine Wartezeiten im Code!
Vielen Dank und nachträglich frohe Weihnachten an alle!
James...
Hallo,
wie hast du es denn jetzt gemacht (Code) ?
habe auch eine Anwendung.
Mein Encoder macht 500 Imp./Umdr.
@Gerado
Da hab ich mir so viel Mühe mit der Beschreibung gegeben und Du fragst nach dem Code? Wo liegt das Problem?
Gruß,
Arne
Hi...
Das mit der negativen Flanke kapier ich leider nicht. Deshalb hab ich es do über den Timer 0 gemacht. Geht zu 98%.Nur manchmal Springt er eins zuviel:
Warum? Ich setze doch das BIT DREHUNG, damit die Drehabfrage gestoppt wird.
INCLUDE 89C52.mc
Drehimpuls BIT 0
Drehung BIT 1
TL0PRE EQU 235
TH0PRE EQU 255
; Programmbeginn
;---------------------------------------------------------------
ORG 0h
JMP start
; Interruptroutinen
;---------------------------------------------------------------
ORG 0Bh
JMP timer0_int
; Funktionen
;---------------------------------------------------------------
; Interruptbehandlungsroutine Timer 0
timer0_int:
LCALL Drehimpulsgeber ;Drehimpulsgeberabfrage Stellung
LCALL Drehabfrage ;Drehimpulsgeberabfrage ob gedreht wurde
MOV TL0, #TL0PRE
mov TH0, #TH0PRE
RETI
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Initialisierung
;---------------------------------------------------------------
start:
; Timer 0 aktivieren
; Intervall: 0.01 ms
; Software-Kontrolle
mov TL0, #TL0PRE
mov TH0, #TH0PRE
; die SFR's initialisieren
CLR Drehimpuls
CLR Drehung
MOV R0,#00h
MOV SP, #30h
mov TMOD,#1
mov TCON,#16
MOV IE, #130
; Hauptprogramm
;---------------------------------------------------------------
main:
JMP main
;---------------------------------------------------------------
Links:
INC R0
RET
Rechts:
DEC R0
RET
Drehimpulsgeber:
IF BIT P3.6 THEN ;Wenn 3.6 und 3.7 high sind setzte Bit Drehimpuls
IF BIT P3.7 THEN
SETB Drehimpuls
CLR Drehung ;lösche das Bit Drehung für erneute Drehabfrage
END IF
END IF
IF NOT BIT P3.6 THEN ;Wenn 3.6 und 3.7 low sind lösche Bit Drehimpuls
IF NOT BIT P3.7 THEN
CLR Drehimpuls
CLR Drehung
END IF
END IF
RET
Drehabfrage: ;Abfrage, ob gedreht wurde
IF BIT Drehung THEN JMP Drehabfrage_AUS
IF BIT P3.6 THEN ;Wenn 3.6 high und 3.7 low sind dann
IF NOT BIT P3.7 THEN
SETB Drehung ;setze das Bit Drehung für Drehabfragenstop
IF BIT Drehimpuls THEN
LCALL Links
ELSE
LCALL Rechts
END IF
END IF
END IF
IF NOT BIT P3.6 THEN ;Wenn 3.6 low und 3.7 high sind dann
IF BIT P3.7 THEN
SETB Drehung ;setze das Bit Drehung für Drehabfragenstop
IF BIT Drehimpuls THEN
LCALL Rechts
ELSE
LCALL Links
END IF
END IF
END IF
Drehabfrage_AUS:
RET
negativen Flanke :confused: Wo hast Du denn die her? Von 'fallende Flanke' war die Rede. Was soviel bedeutet das nicht permanent auf HIGH oder LOW reagiert wird, sondern nur, wenn bei der ersten Abfrage ein HIGH erkannt wurde und bei der nachfolgenden ein LOW.
Bei den Interrupts z.B. muß man sich zwangsweise damit auseinandersetzen. Die externen laufen standartmäßig so, daß sobald der Interupt-Eingang ein LOW sieht, die Interrupt-Routine aufgerufen wird. Ist die Routine beendet und der Interupt-Eingang immer noch Low würde diese erneut aufgerufen werden. Das endet erst wenn am Eingang wieder ein HIGH liegt. Will man Impulse zählen, würde es zwangsweise passieren, das ein Impuls mehrfach gezählt wird. Beim setzen eines bestimmten SFR-Bits reagiert der MC nur noch auf das LOW am Interrupt-Eingang, wenn zwischendurch ein HIGH anlag. 'fallende Flanke' eben - Problem gelöst!
Wie das jetzt mit einem Timer gehen soll, werde ich mir wohl heute Abend mal näher anschauen. Aber eigentlich ist und bleibt er überflüssig... .
Gruß,
Arne
Sorry Arne, fallende Flanke.
Welches bestimmte Spezialfunktionregister-BIT ich setzen muß, damit es geht, weiß ich leider nicht.
Ich weiß nur, daß ich am Anfang die Stellung des DIG feststellen muß. Entweder sind beide auf High oder beide auf low. Wenn beide auf Low sind, das setze ich z.B. Bit 0 sonst lösche ich es.
Dann muß ich Abfragen, ob gedreht wird.
Wenn das BIT 0 gesetzt ist und dann die Stellung 0 1 ist, soll Links aufgerufen werden.
Wenn das BIT 0 gesetzt ist und dann die Stellung 1 0 ist, soll Rechts aufgerufen werden.
Wenn das BIT 0 gelöscht ist und dann die Stellung 0 1 ist, soll Rechts aufgerufen werden.
Wenn das BIT 0 gelöscht ist und dann die Stellung 1 0 ist, soll Links aufgerufen werden.
Oder ist das falsch?
Ach ja, wenn der Drehimpulsgeber 0 0 ist und ich ihn dann nach rechts oder nach links drehe, dann hab ich ja keine fallende Flanke, oder doch?
Hi Arne, ich glaube es hat sich erledigt.
Hab einfach folgende Befehle vertauscht:
LCALL Drehimpulsgeber ;Drehimpulsgeberabfrage Stellung
LCALL Drehabfrage ;Drehimpulsgeberabfrage ob gedreht wurde
jetzt sieht es so aus:
LCALL Drehabfrage ;Drehimpulsgeberabfrage ob gedreht wurde
LCALL Drehimpulsgeber ;Drehimpulsgeberabfrage Stellung
Keine Ahnung warum, aber jetzt funzt es.
Gute Nacht...
Hm.... es funktioniert doch nicht...:mad:
Gruß Florian
Hi Arne...
Wieviele ext. Interuppts würde ich für dein programm brauchen?
Gruß Florian
Hi,
'Meine Variante' braucht einen ext. Interrupt für das CLOCK-Signal (bzw. Interpretation). Um in den 'Flanken-Modus' zu kommen, verrät ein Blick in die Register:
IT1 (Bit 08Ah) bzw. IT0 (Bit 088h) muß gesetzt werden. Diese stehen im TCON (Timer/Counter Control Register).
Gruß,
Arne
Hi Arne,
wir haben in der Firma auch mehrere Programmierer,
wenn man Die mal was fragt: " bekommt man nie eine vernünftige Antwort"
nach dem Motto Herr Lehrer :"Ich weiss was".
Es soll auch Leute geben die nicht alles wissen!!.
Das es Datenbücher gibt weiss ich auch,ich könnte auch einen Up/Down
Zähler nehmen, nebst ein paar Logikbausteinen.
Trotzdem wünsche ich Dir einen "Guten Rutsch",
kannst ja mal darüber nachdenken !!
MfG Gerado
@Gerado
Ehrlich gasagt, bin ich mir nicht ganz sicher, was Du mir mit deinem Posting sagen willst!?
Es soll auch Leute geben die nicht alles wissen!!.
Das es Datenbücher gibt weiss ich auch, diese Zeilen stimmen mich aber nicht grade freundlich!
Mit Sicherheit kann ich behaupten, daß ich auch nicht alles weiß, aber man sollte schon wissen, wo man nachschauen/nachschlagen kann! Wer zu faul ist, sich mit seiner Umgebung vertraut zu machen, wird nie über sich hinauswachsen. Also versuche ich es in der Regel mit Hilfe zur Selbsthilfe. Mein Wissen hat mir leider auch keiner beigebracht - ich habe mir alles selbst erarbeitet. Wer sich grundsätzlich auf die Hilfe anderer verläßt, ohne sich selbst auf den Arsch zu setzen, hat ein grundlegendes Einstellungsproblem und wird früher oder später auf der strecke bleiben!
Gruß,
Arne
@Florian (Dein Postfach ist voll! aber hier haben alle was davon...)
Hi Arne, bin jetzt zu folgendem Entschluss gekommen:
INCLUDE 89c52.mc
JMP init
(0003h):
IF BIT P3.0 THEN
INC R0
ELSE
DEC R0
END if
RETI
init:
MOV R0,#00h
SETB EA
SETB EX0
MOV TCON,#01h
start:
JMP start
Beim Debugger funktioniert es, mit der fallenden Flanke...Nur was mach ich, wenn beide Ausgänge auf Low liegen=?
Den zweiten Ausgang hänge ich an P3.0, aber das hast du eh wahrscheinlich gesehen...
Na, die 'fallende Flanke' macht dir wohl immer noch zu schaffen! Dabei hast Du doch alle Möglichkeiten berücksichtig!
Also nochmal: Der erste Ausgang deines 'Gebers' verrät durch HIGH oder LOW die Drehrichtung in dem Moment, wo der zweite Ausgang von HIGH auf LOW fällt (eben fallende Flanke!). Der MC reagiert nur in diesem Moment und ruft seine Intrrupt-Routine auf. Sobald diese beendet ist passiert gar nichts mehr, egal wie lange die beiden Ausgänge auf LOW liegen bleiben.
Schnapp Dir das von mir gepostete Diagramm nochmal und fahr es mal mit einem Lineal nach rechts und links(!) ab. So sehen die Signale aus, die Dein Geber vom Stapel läßt, wenn du ihn nach links oder rechts drehst. Beobachte 'DIR' immer nur wenn 'CLOCK' von HIGH auf NULL fällt. Genau das ist es was Dein Code auswertet!
Dein Code schaut schon sehr lecker aus! So in etwa hatte ich es mir vorgestellt, nur das ich es nicht in BASIC geschrieben hätte. ;)
Zwei Sachen habe ich da aber noch, die Du verbessern solltest.
1. das leidige Thema TCON:
mit dem Befehl 'MOV TCON,#01h' überschreibst Du die BITs der anderen Funktionen in diesem Register, wie:
TF1 (Timer1-Überlauf-Flag), TR1 (Timer1-Run-Flag) usw.
Um das zu verhindern, beschränke Dich in diesem Fall auf:
SETB IT0
2. Register (R0 bis R7) in Interrupts:
Der MCs-51er verfügt über 4 Registerbanke die mit R0 bis R7 angesprochen werden. Je nachdem welche RB (=Registerbank) also gewählt wurde (die Auswahl erfolgt über zwei Bits im PSW-Register), verändert Dein Programm die int. Ram-Adr. 00h, 08h, 10h oder 18h. Das kann also einen echt gemeinen Fehler geben, der sich schwer finden läßt. Nun hast Du zwei Möglichkeiten, dem entgegenzuwirken:
A: Beim Sprung in die Interrupt-Routine, die aktuelle RB-Wahl sichern, die richtige RB setzen und unmitelbar am Ende die RB-Wahl wiederherstellen oder
B: einfach eine Variable im 'höheren' Speicherbereich deffinieren (z.B. RadPos EQU 050h) und diese in der Interrupt-Routine mit DEC und INC verändern.
Die Registerbänke dienen eigentlich für komplexere Berechnungen oder der Übergabe mehrerer Werte zu Program-Funktionen. Sie verfügen über ein paar Sonderbefehle, die auf den Rest des Speichers nicht anwendbar sind. Solange also noch Platz im RAM ist, sollte man in den Registern keine banalen Variablen unterbringen. Grade R0 und R1 dienen zusätzlich noch als Pointer und sind deswegen besonders wertvoll!
Gruß,
Arne
P.S.
Es wundert mich schon etwas, daß dein Code grundlegend stimmt und es bei dir immer noch nicht 'klick' gemacht hat - kommt wohl noch... ;)
Peter Dannegger
01.01.2005, 17:24
Anbei mal meine Routine, die ich schon seit Jahren zuverlässig in vielen Projekten verwende.
Sie ist original darauf ausgelegt, Positionssensoren auszulesen.
Bei Drehknöpfen wird aber meist mehr als ein Signalwechsel pro Rastung gesendet, d.h. der Zählwert ist dann in 2-er bzw. 4-er Schritten, was aber leicht durch Rechtsschieben korrigiert werden kann.
Grundprinzip ist ein Timerinterrupt, z.B. T0 in Mode 2 oder 3 alle 256 Zyklen.
Es können beliebige Pins verwendet werden bzw. auch mehrere Drehgeber ausgelesen werden.
Die ersten Zeilen wandeln der Gray-Kode des Drehgebers in eine 2Bit-Binärzahl um.
Danach wird die Differenz zur vorherigen Binärzahl gebildet.
Somit ergeben sich die Werte 0 (keine Änderung) oder +1 (rechts) bzw. -1 (Linksdrehung) und damit wird ein Byte hoch bzw. runter gezählt.
Das ist schon alles.
Peter
Hi Arne, ich gebs auf. Zwei Taster sind einfacher zu programmieren...
Ich komm wirklich nicht drauf, worauf du hinaus willst.
Du schreibst, warum es bei mir noch nicht klick gemacht hat... Na ja..
Hab das Programm jetzt so getestet. Dabei ist mir das aufgefallen, was ich befürchtet hab, daß ich nämlich keine steigende Flanke abfragen kann.
Auf gut Deutsch muß ich den Drehimpulsgeber 2x in die gleiche Richtung drehen, damit das Register um eins erhöht wird und das A und B wieder auf High ist. Hab jetzt den ganzen Tag probiert, wie du es vielleicht noch meinen könntest, aber es hat keinen Sinn.
Gute Nacht.
Gruß Florian
Irgendwie versteh ich Dich grade nicht - so kurz vorm Ziel die Flinte ins Korn geworfen???
In den nächsten Tagen werde ich mir mal einen passenden Geber schnappen und dann nochmal detailliert Deinen Code in der Praxis testen. Dabei sollte er doch schon laufen, so wie er ist! Die Änderungen wären nur 'für die Zukunft' sinnvoll.
Vielleicht brauchst Du auch nur mal 'ne Weile Ablenkung - beschäftige Dich mal mit was anderem. Und dann schaun wir weiter!
Gruß,
Arne
Hi Arne. Du schreibst, der Code sollte schon so laufen? Das kann nicht funktionieren. Ich versuche es nochmal, es zu erklären:
Die 11 und die 00 in den Klammern sind die Rasterstellungen, die der Drehimpulsgeber einnimmt, wenn er in der Ruheposition ist. Wenn die Ausgänge A und B dann (11) sind und ich nach rechts drehe, dann geht A auf Low und B gibt mir die fallende Flanke. Wenn ich nach links drehe, dann gibt B die fallende flanke an und sofort ist der Interuppt, damit A auf High ist.
Gut, das funktioniert ja, aber wenn man jetzt nach links oder nach rechts gedreht hat, dann steht der DIG mit A und B auf (00). Wenn man nun nach links oder nach rechts dreht, dann geht der A auf High und B gibt eine Steigende Flanke an den Interuppt, es passiert also nichts, weil der Interuppt nur auf eine fallende Flanke reagiert. Verstehst du mich jetzt?
(00)---10---(11)---01---(00)---10---(11)---01---(00)---10---(11)
Dank der Schlußzeile wird klar, was Du meinst.
Es sind immer wieder solche Informationsdefizite, die zu Mißverständnissen führen. Nichts für ungut, aber Hellsehen kann ich leider nicht. Mit dieser Info hätte ich Dir gleich sagen können, daß mein erster Lösungsansatz hier nur die halbe Miete bringt, auch wenn er sehr einfach ist.
Nun brauchst du tatsächlig einen Timer, da mit den Vorraussetzungen der Hardware kein brauchbares Interupt-Signal erzeugt wird. So muß ständig der Geber auf Veränderung geprüft werden. Im Moment bin ich aber für genauere Ausführungen nicht zu haben....
Gruß,
Arne
wolfgang
08.01.2005, 23:25
Hallo, ich wollte auch schon lange was mit dem Drehgeber als Eingabe machen und habe es mit folgender Routine zum laufen gebracht.Absolut wichtig sind je ein 100nF kondens am Eingang um den Drehgeber zu entprellen.
encoder:
MOV p1,#255
MOV A,P1
ANL A,#000000011b ; restliche Eigänge eliminieren
JNZ encoder_end ; Kein Impuls vorhanden ende
encoder_einlesen:
MOV A,P1
ANL A,#00000011b ; restliche Eigänge eliminieren
JZ encoder_einlesen
JNB a.0,encoder_1
INC wolf
MOV A,wolf ; Dient der Anzeige
call byte ; Dient der Anzeige
call crlf ; Dient der Anzeige
RET
encoder_1:
JNB A.1,encoder_einlesen
DEC wolf
MOV A,wolf ; Dient der Anzeige
call byte ; Dient der Anzeige
call crlf ; Dient der Anzeige
RET
encoder_end:
RET
Die routine beinhaltet nur das risiko in einer Endlosschleife zu verharren.Es ist jedoch sehr schwierig den Drehgeber in Mittelstellung zu halten also bei normalen gebrauch bleibt niemand hängen
By Wolfgang
Powered by vBulletin® Version 4.1.12 Copyright ©2012 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.