Datum:
Angehängte Dateien:Die Encoder liefern einen Gray-Code. Anbei ein C-Programm. Für mittlere Geschwindigkeiten oder manuelle Bedienung ist das Abtasten im Timerinterrupt das Optimale. Damit umgeht man sämtliche Probleme mit der Flankenumschaltung beim externen Interrupt. Außerdem kann man auch mehrere Encoder anschließen. Der Rechenzeitaufwand ist vernachlässigbar. Die Funktion get_gray_delta() liefert die Anzahl der Impulse seit dem letzten Aufruf zurück. In Zeile 8 und 9 kann man auswählen, ob bis zu 127 oder 32767 Impulse seit der letzen Auswertung gespeichert werden sollen. Die Decodierroutine arbeitet mit einer Tabelle aus den 16 möglichen Kombinationen der 2 aktuellen und der 2 vorherigen Bits. Bei den Übergängen: 0->1->3->2->1 steht eine "+1" in der Tabelle und bei: 0->2->3->1->0 eine "-1". D.h. der Counter graycount wird dadurch um 1 erhöht oder erniedrigt. Diese Routine habe ich z.B. auch für die hochgenaue X-Y-Positionierung bei einer Steppermotorsteuerung verwendet (+/-50µm). Dabei wurden optische Encoder verwendet. Peter
Datum:
Angehängte Dateien:Anbei eine 2. Variante ohne Tabelle, die noch schneller und kleiner ist. Das Codebeispiel ist diesmal für den AVR geschrieben, die Änderungen für den 8051 sind aber nur minimal (Definition der Portpins, Timerinitialisierung). Funktionsweise: Das Einlesen der beiden Signale erfolgt mit: if( PHASE_A ) ... if( PHASE_B ) ... Dadurch kann man beliebige Pins von beliebigen Ports nehmen. Wenn man die beiden Encoder-Signale als Binärzahl darstellt, ergeben sich folgende Zustände: 00 - 01 - 11 - 10 -10 Dieser Code wird auch Gray-Code genannt. Das besondere Merkmal des Gray-Code ist, daß sich zwischen aufeinanderfolgende Werten immer nur ein Bit ändert. Dadurch können keine Fehldekodierungen auftreten. Würde man nun die Differenz zwischen zwei Codes bilden, käme nur Müll heraus, da die CPU ja im Binärcode rechnet. Eine Lösung ist die obige, wobei mittels einer Wertetabelle eine Gray-Code Subtraktion realisiert wird. Einfacher ist jedoch eine Umwandlung des Gray-Code nach Binär, wie sie in diesem 2.Programmbeispiel erfolgt: Gray-Code Binär-Code 00 00 (0) o.k. 01 01 (1) o.k. 11 10 (2) ändern 10 11 (3) ändern Wie man sieht, muß man also nur das niederwertige Bit umdrehen, sobald das höherwertige Bit gesetzt ist. Diese Anweisung: if( PHASE_B ) i ^= 3; setzt das höherwertige Bit und invertiert das niederwertige, fertig ist die Codeumwandlung. Danach kann man nun die Differenz zwischen 2 aufeinanderfolgenden Auslesungen bilden: i -= enc_last; Erfolgt keine Änderung, ist die Differenz 0. Erfolgt eine Änderung über 2 Schritte, ist die Differenz 2. Das kann aber nur bei Störungen passieren oder wenn die Abtastgeschwindigkeit zu langsam ist. Die Drehrichtung läßt sich dabei nicht bestimmen. Deshalb wird auch eine solche Änderung ignoriert: if( i & 1 ){ enc_last += i; Bei einer Änderung über einen Schritt, ergeben sich je nach Drehrichtung folgende Werte (in Klammern der 2-Bit Wert als Dezimalzahl): Vorwärts: 00 - 11 = 01 (1) 01 - 00 = 01 (1) 10 - 01 = 01 (1) 11 - 10 = 01 (1) Rückwärts: 00 - 01 = 11 (3) 01 - 10 = 11 (3) 10 - 11 = 11 (3) 11 - 00 = 11 (3) Maskiert man nun das höherwertige Bit (2) heraus und zieht 1 ab, ergeben sich die Byte-Werte +1 bzw. -1, die man zu dem Zählerwert addiert, um ihn rauf bzw. runter zählen zu lassen: enc_delta += (i & 2) - 1; Peter
Datum:
Naja, da fehlt noch Fehlerkorrektur, wie man merkt, wenn man einen Treiber für einen mechanischen Drehgeber macht. Die beiden Zähler für eine Flanke, die einer halben Raster-Drehung nach rechts/links entsprechen, resete ich deshalb wenn eine stationäre Position (d. h. input_l == input_r) erreicht ist. Damit kann man auch stark prellende Drehgeber gut entprellen, denn dadurch werden durch Prellen entstehende halbe Raster-Drehungen ignoriert (fehlerkorrigiert) ;-)
Datum:
@nobody0, also ich verstehe nur Bahnhof. Welche "beiden Zähler" meinst Du denn, da ist doch nur einer ? Prellungen werden nämlich durch den Gray-Code automatisch kompensiert. Wenn Du aber Zweifel an der Funktion hast, dann probiere es doch bitte erstmal aus, anstatt nur irgendwas zu vermuten. Bzw. erkläre bitte etwas genauer, was Du eigentlich meinst. Es ist natürlich möglich, daß man Schritte verliert, wenn man sehr schnell dreht. Dann muß man aber nur die Abtastzeit verkürzen und schon gehts wieder. Der Wert in meinem Beispiel (11,0592MHz 256 8 = 5,4kHz) sollte in der Regel ausreichend sein. Peter P.S.: Wenn man aber Drehgeber nimmt, die nur alle 2 oder 4 Phasen einrasten, muß man den Zählwert nach dem Auslesen /2 bzw. /4 teilen.
Datum:
Ich meine einfach einen Zähler für die halben Linksdrehungen und einen für die halben Rechtsdrehungen. Von einem zum anderen Rasterpunkt hat man ja zwei halbe Drehungen und am Rasterpunkt einen stationären Zustand (beide Adern 0 oder 1). Deshalb setze ich an einem Rasterpunkt beide Zähler auf 0 und logge die Fehler. Dadurch kann man diagnostizieren wie zuverlässig der Drehgeber ist und ihn austauchen bevor das Prellen so stark wird, dass es nicht mehr zu 99,9 % korrigierbar ist. Ich habe das in einer ISR gemacht und es funktioniert gut, wobei aber aus Kostengründen auf das Austauschen u. loggen verzichtet wird.
Datum:
"auf das Austauschen u. loggen verzichtet wird" Wenn Du sie nicht auswertest, dann streich sie gleich ganz aus Deinem Programm. Ist so doch nur toter Code. Wie gesagt, das Prellen stört bei meinem Code nicht. Wenn durch eine Störung mal zu weit gezählt wird, wird sofort in der nächsten Abtastung, wo die Störung vorbei ist, zurück gezählt und alles stimmt wieder. Deshalb nimmt man ja den Gray-Code. Peter
Datum:
Den toten Code sollte der Compiler wegoptimieren und wenn es eng wird, kann ich den betreffenden Code mit defines kapseln. Dass das Prellen bei mechanischen Drehgebern sehr wohl stören kann, merkt man wenn einige tausend Geräte produziert werden und einige reklamierte ein starkes Prellen des Drehgebers zeigen. Da zeigt sich dann der Unterschied zwischen Theorie und Praxis. Mit Fehlerkorrektur kann man da noch einiges machen. Übrigens hat der Gray-Code allein nichts mit Fehlertoleranz zu tun; der Gray-Code minimiert nur die Hamming-Distanz benachbarter Codeworte, aber beim Prellen hilft das nicht, weil der Gray-Code allein keine Fehlerkorrektur macht; er ist kein ECC-Code.
Datum:
"Übrigens hat der Gray-Code allein nichts mit Fehlertoleranz zu tun" Das ist falsch. Der Trick beim Gray-Code ist nämlich, daß sich immer nur ein Bit gleichzeitig ändert. D.h. es kann immer nur ein Signal prellen und das bewirkt nur das Hin- und Herzählen zwischen 2 aufeinanderfolgenden Zählwerten. Sobald das Prellen vorbei ist, liegt also immer der richtige Zählwert vor. Übrigends ist die Polling-Methode im Timerinterrupt automatisch viel sicherer, als die Flankeninterrupt-Methode. Beim Timerinterrupt muß nämlich die Störung zufällig auch noch gleichzeitig mit dem Abtastzeitpunkt zusammenfallen. Der Flankeninterrupt wartet dagegen geradezu sehnsüchtig auf jede Störung und kann dadurch auch auf jeden noch so kurzen Störimpuls (z.B. elektrostatisch aufgeladene Kleidung) fehlreagieren. Peter
Datum:
> Der Trick beim Gray-Code ist nämlich, daß sich immer nur ein Bit > gleichzeitig ändert. Ja, aber durch Prellen ändern sich kurz hintereinander mehrere Bits und wenn man die nicht fehhlerkorrigiert, hat man ein (unnötig) starkes Prellen. Praktisch sieht das so aus, dass eine Drehung des Drehgebers um ein Raster meist +/-=2 (statt +/-=1) bewirkt und machmal auch +/-0 (statt (+/-=1) bewirkt. Mit der Fehlerkorrektur bekommt man diese Fehler fast immer beseitigt. > D.h. es kann immer nur ein Signal prellen ... Falsch; es könen sehr wohl beide Adern gleichzeitig ein Prellen zeigen. Die Annahme, das zu einem Zeitpunkt nur ein Fehler auftreten kann, ist einfach falsch. Deshalb sind. z. B. in Kernkraftwerkten die wichtigen Teile mindestens doppelt redundant, damit zwei gleichzeitig auftretende Fehler nicht zum GAU führen. Aus Kosten- oder anderen Gründen wird aber meist mehr als ein Fehler außerhalb der Vorstellungskraft verlagert ... > Beim Timerinterrupt muß nämlich die Störung zufällig auch noch > gleichzeitig mit dem Abtastzeitpunkt zusammenfallen. Ich nehme natürlich keinen Timer-Interrupt; davon habe ich nix geschrieben. Ich verwende einen Port-Interrupt. > Der Flankeninterrupt wartet dagegen geradezu sehnsüchtig auf jede > Störung und kann dadurch auch auf jeden noch so kurzen Störimpuls > (z.B. > elektrostatisch aufgeladene Kleidung) fehlreagieren. Logischerweise ist vor jedem Eingang mit enabletem Interrupt ein Tiefpass, der sowas wie Elektrostatische Entladungen rausfiltert. Bei MCs ohne ausgeprägte Hysterese, wie dem Samsung S3C2410, verwende ich zwischen dem Tiefpass u. dem MC Schmitt-Trigger.
Datum:
Nachtrag: Hosted (z. B. unter embedded Linux) Polling zu betreiben wäre keine gut Idee; das benötigt einiges an CPU-Leistung und unterbricht andere wichitge Tasks. Mit einem eigenen Tastatur-Contoller ist Polling natürlich immer optimal, aber aus Kostengründen ist sowas ja selten und sowas wie einen Tiefpass zum Rausfiltern von elektrostatischen Entladungen kann man damit nicht komplett ersetzen.
Datum:
"das benötigt einiges an CPU-Leistung" In meinem Beispiel sind das maximal 5%, wobei die Abtastfrequenz sehr hoch angesetzt ist und bei Bedarf noch reichlich verringert werden kann. Ich habe allerdings kein embedded Linux laufen sondern nur nen schnöden AVR und dem machen die 5% nicht das geringste aus. Insbesondere, da dieser Timerinterrupt noch ne Menge anderer Aufgaben mit erledigt, relativiert sich das reine Abtasten auf etwa 2% CPU-Last. Bei Mikrokontrollern ist die Verarbeitungsgeschwindigkeit ja noch linear zur Taktfrequenz. Also ein 16MHz AVR mit 5% CPU-Grundlast ist exakt gleichschnell wie ein 15,2MHz AVR ohne Grundlast. Dagegen reagiert der Flankeninterrupt schon auf sehr kurze Impulse (AVR: wenige ns). Da reichts manchmal, daß man beide Signalleitungen wenige cm ungeschirmt nebeneinander führt und schon koppelt sich die Schaltflanke kapazitiv von einem zum anderen Signal über, d.h. beide Interrupts können auslösen. Du hast natürlich recht, daß bei absolut schrottigen Drehgebern, z.B. durch Verschmutzung, lockere Kontaktnieten usw. auch auch auf dem anderen gerade nicht betätigten Kontakt ein Impuls entstehen kann. Dagegen ist aber auch jede noch so komplizierte Fehlererkennung machtlos. Jede Kette ist nur so stark, wie ihr schwächstes Glied. Deshalb wird keiner auf die Idee kommen in einem KKW Schrott einzusetzen und dann an anderer Stelle das mit Software auszugleichen versuchen, d.h. dieses Beispiel ist einfach hirnrissig. In Low-Cost Konsumgütern aber zählt kein Mensch die Rastungen mit, sondern schaut aufs Display was dort angezeigt wird. Und wenn da nach einer kompletten Umdrehung nur 99 statt 100 angezeigt wird, wen störts, einfach einen Schritt weiter drehen. Ich benutze aber auch das gleiche Programm zur Positionsbestimmung, wo es auf absolute Genauigkeit ankommt. Allerdings werden dort grundsätzlich optische Positionsgeber verwendet, d.h. die prellen nicht. Auch habe ich den Code einfach 3* hintereinander geschrieben, da alle 3 Koordinaten ausgelesen werden müssen. Ich wüßte jetzt gerade keinen µC, der 6 Flankeninterrupts hat. Ich denke mal, weitere rein theoretische Vermutungen, daß mein Code fehleranfälliger sein müßte, nur weil er kürzer ist, sind überflüssig, solange Du ihn noch nicht einmal ausprobiert hast. Die Praxis ist doch immer noch der beste Test. Ich weiß, er ist nicht gerade einfach zu verstehen, aber dann sieht man, daß er sehr fehlertolerant ist. Peter
Datum:
Also die Kunden zählen schon mit und wenn die z. B. genau 200 einstellen wollen aber die Anzeige (mit Einheit 5) mal auf 210 springt oder auf 195 stehen bleibt dann nervt das schon; da kann man schon verstehen, dass deshalb ausgetauscht wird. Das mit den 6 Flanken-Interrupts verstehe ich nicht, denn z. B. ein MSP430F149 hat 16 Eingänge die flankengetriggert sind und der S3C2410 noch einige mehr. Und Koppeln von Eingängen habe ich noch nie gesehen; ich habe nur mal Leitungsreflektionen auf einem IIS-Bus gefunden, die aber mit Tiefpässen problemlos weggefiltert werden konnten.
Datum:
Ich würde mal sagen, das hängt wie immer vom speziellen Anwendungsfall ab :-) Für mich hat die Timerinterrupt-Abfragemethode den großen Vorteil, das ich mehrere Drehgeber multiplexen kann. So benötige ich z.B. für die Auswertung von 8 Drehgebern nur 5 I/O-Leitungen (und etwas Zusatzelektronik: 1aus8-Decoder, Dioden), mit einer weiteren Leitung (und einem weiteren 1aus8-Decoder) komme ich dann auf 16 Drehgeber.
Datum:
Für 8 Drehgeber und 5 Leitungen braucht man doch keine Zusatz-Elektronik, außer eine Diode pro Schalter. Mit 5 Leitungen kann man doch ganz einfach 4 + 3 + 2 + 1 = 9 Schalter einzeln abfragen.
Datum:
Hmmmm, dat versteh ich nicht ganz !? Andererseits haben 8 Drehgeber ja zusammen schon 16 Schalter, zumindest die, die ich verwende (den Drucktaster zähle ich da mal nicht mit, den brauch ich eh nicht, sonst wären es sogar drei :-). Kannst Du das bitte mal etwas näher erläutern. Danke!
Datum:
Achso; bei 16 statt 8 Schaltern ist es etwas anders. Also bei einer einfachen Matrix-Schaltung braucht man 4+4 Leitungen, aber es geht effizienter: Man kann ja einfach von der Leitung n zu den Leitungen n-1 ... 0 je einen Schalter (m. serieller Diode) anschließen, also insgesammt 0 + 1 + 2 + 3 ... + n-1. Bei 7 Leitungen kommt man so auf schon 6+5+4+3+2+1=21 Schalter; bei 8 zweiadrigen Drehgebern kann man also bei 7 Leitungen noch 5 Taster verwenden. Das ist natürlich nur für den einfachen Fall, dass die Dioden nur den Strom in eine globale Richtung durchlassen, also von Leitung k nach l > k oder umgekehrt; allgemein kann man natürlich (n-1)! Schalter abfragen, also bei n=7 kann man 6*5*4*3*2=720 Schalter abfragen. Natürlich kann man das auch noch ausbauen, indem man Schalter (mit Diode) nicht nur zwischen den Daten-Leitungen sondern auch noch +UB und GND sowie NC verwendet.
Datum:
Korrektur: Mit NC geht's bei Schaltern natürlich nicht ;-) Mit +UB und GND (über ausreichend hochohmige Widerstände), und weil man pro Verbindung 2 Schalter (mit antiparallelen Dioden) verwenden kann, kann man insges. 2*(n-1)! + 2*n Schalter abfragen, also mit 7 Leitungen 1454 Schalter. Zum Dekodieren brauch man aber mehr Rechenzeit als bei einer einfachen Matrix-Schaltung.
Datum:
Ich würde mal sagen, das hängt wie immer vom speziellen Anwendungsfall ab :-) Für mich hat die Zusatzelektronik-Methode den großen Vorteil, das ich die Teile bereits habe, die Schaltung nebst Software erprobt, übersichtlich und kompakt ist, und der Rechenleistungsbedarf in einem vertrebaren Rahmen bleibt. Mit einer weiteren Leitung (und einem weiteren 1aus8-Decoder) kann ich das ganze bei Bedarf mit nur kleinsten Änderungen der Abfrageroutine auf 16 Drehgeber erweitern (sofern ich mal eine wirklich günstige Quelle für die Teile finde sollte:-).
Datum:
Ja, eine Auswertung für 1454 Schalter (an 7 Leitungen (+UB u. +GND) habe ich bisher auch nur theoretisch gemacht und in der Firma wird bisher praktisch nur ein Schalter pro Eingang verwendet, obwohl es kaum ausgenutzt wird; Shortcuts gibt's bisher noch nicht. Nachtrag zur Grey-Dekodierung: Die einfachen Routinen, vom Anfang des Threads, habe ich so in vorhandener Software gefunden und durch meine Variante mit Fehlerkorrektur ersetzt; die ist also praxis-erprobt und wirksam.
Datum:
Andererseits hat das was, 1454 Schalter, das wären ja dann mehr als 700 Drehgeber (wenn ich jeweils zwei Kontakte pro Geber annehme). Ein unbestimmte Gefühl sagt mir aber auch, das es bestenfalls, wenn überhaupt, theoretisch funktionieren würde. Aus meiner Sicht kommt man mit 16 Drehgebern ganz gut hin, denkbar wäre noch eine Erweiterung auf 24 oder höchstens 32 (ja, dann bin ich schon bei 7 Leitungen + zwei weiteren 1aus8-Decodern). Es gibt zwar auch Geräte mit mehr Drehreglern (z.B. Drehbank mit 64), aber da wird das schon leicht unübersichtlich. Ich würde dann eher noch 8 Schieberegler und ein oder zwei Mini-Joysticks dazunehmen. Falls ich meine Gerät jemals fertig bekomme, kann ich es ja dann mal kurz hier vorstellen...
Datum:
"Die einfachen Routinen, vom Anfang des Threads" Ich muß gestehen, daß es zwischen beiden Varianten einen kleinen aber feinen Unterschied gibt: Die Tabellenversion (1.Beispiel) zählt nicht weiter, wenn ein Übergang über 2 Stufen erkannt wird, speichert ihn jedoch trotzdem ab. Dadurch kann es passieren, wenn es sich um ein Prellen beider Kontakte während eines Übergangs gehandelt hat, daß dann die nächste Abtastung einen Zähler in die falsche Richtung macht. Die Differenzmethode (2.Beispiel) ignoriert einen Übergang über 2 Schritte auch, aber speichert ihn nicht ab. Sie zählt also erst weiter, wenn nur ein einstufiger Übergang erkannt wurde, also die Prellung vorbei ist. Die obigen Aussagen bezüglich der Fehlerfestigkeit beziehen sich daher ausschließlich auf das 2.Programmbeispiel. Es liegt ja in der Natur der Sache, daß eine spätere Codevariante in der Regel weiter entwickelt und daher besser ist. Es würde auch keinen Sinn machen eine gleichartige Funktion zu veröffentlichen, wenn sie keinerlei Vorteile hätte. Es gibt im Prinzip folgende Drehgeberaufbauten: Billige Drehgeber arbeiten mit einer Scheibe mit metallisierten Segmenten, auf der 3 Schleifkontakte aufliegen. Dann ist es in der Tat möglich, daß durch Verschmutzungen auch der 2. Kontakt unterbrochen wird, während er auf der metallisierten Fläche gleitet. Etwas bessere Drehgeber arbeiten mit einer Art Nockenscheibe, die 2 Mikrotaster abwechselnd betätigt. Damit ist eine gleichzeitige Umschaltung beider Kontakte ausgeschlossen. Beide können zwar prellen aber eben nicht gleichzeitig. Das beste sind aber optische Drehgeber (Mausprinzip). Sie schalten nicht gleichzeitig und prellen auch nicht. Und wenn die Portpins nicht ausreichen, kann man an je einen 74HC165 je 4 Drehgeber anschließen und davon beliebig viele per SPI über insgesamt nur 3 Leitungen einlesen. Peter
Datum:
Ich habe festgestellt, das die "billigen", aber bei Conrad sehr teuren ;-), Drehgeber sehr stark prellen können, wie der ddm427, auch wenn man nicht all zu schnell dreht. Da gibs entweder nur die passenden Kondensatoren oder, wie Nobody0 meint, Hochpassfilter einzusetzen, oder per Software entprellen. Habe leider keine passenden Kondensatoren da gehabt (zu klein oder zu groß) und den Drehgeber per Pin Change IRQ ausgelesen und per Software entprellt. Hier der Ausschnitt aus dem Prog für nen Tiny12 mit Pin Change IRQ: PinIRQ: ..... rjmp Dreher ..... PinIRQ1: reti Dreher: in r16,pinb Neuen Wert von A und B auslesen andi r16,0b11000 A und B an PB5 und PB4 ausmaskieren cp r16,KeyAlt Hat sich was verändert? breq DrExit Wenn nicht, dann raus ldi r16,250 Ca. 1 ms warten, bis evtl. prellen weg ist Dreher1: nop dec r16 brne Dreher1 in r16,pinb Neuen Wert erneut einlesen andi r16,0b11000 und maskieren cp r16,KeyAlt Vielleicht doch nur ein prellen? breq DrExit Dann raus mov r17,r16 Neuen Wert kopieren lsr r17 2 mal nach rechts schieben lsr r17 or r17,KeyAlt und mit dem alten Wert verknüpfen mov KeyAlt,r16 Neuen AB-Wert sichern ldi r20,0b11110 XOR-Maske für ABAB sbrs r17,4 Ist Bit 4 bzw 3 gesetzt? eor r17,r20 Wenn nicht, letzen und vorigen AB-Wert invertieren cpi r17,0b10000 War die letzte Bit-Folge von ABAB 1000? breq DrLinks Dann wurde 1 Raster nach links gedreht cpi r17,0b10110 War es 1011? brne DrExit Wenn nicht, ein falscher Wert (prellen?) DrRechts: Ansonsten war es eine Rasterstelle nach rechts cpi VZeit,VZeitMax Abhandlung zur Rechts-Drehung breq DrExit ldi r16,VZeitStep add VZeit,r16 DrExit: rjmp PinIRQ1 DrLinks: cpi VZeit,VZeitMin Abhandlung zur Linksdrehung breq DrExit subi VZeit,VZeitStep rjmp PinIRQ1 Bin damit am besten zurecht gekommen und habe es in eine Pin Change Interruptroutine geschmissen. Da muß man schon sehr schnell drehen, ca. in 0,3 Sekunden einmal um die Achse, damit das Prog den Faden bzw. die Impulse oder Prellungen empfängt verliert. Und das trotz der Wartezeit von ca. 1 ms die ja als Entprellung dienen soll. Und wenn keiner am Geber dreht wird das Sub-Prog nicht ausgeführt. Gruß Andi
Datum:
Das Problem bei 700 drehgebern an 7 Leitungen wäre das Abfragen - es muß mit Pin-Wackeln (ein Pin high, alle anderen, bis auf den einen auf low usw.) geprüft werden ob der Schalter zwischen Leitung 0 u. 1 und der in umgekehrte Richtung geschlossen ist usw. - also 1400 einzelne Abfragen. Damit wäre ein Tastatur-Controller wohl voll ausgelastet. Aber man kann so viel Hardware sparen ...
Datum:
Ja wie denn? Ich check immer noch nicht, wie man an 7 Leitungen 700 Drehschalter oder 1400 Taster dranbekommen soll. Gruß Andi
Datum:
Ganz einfach: Ein Schalter mit eine Diode, so dass Strom nur von Leitung 0 nach 1 fließen kann, einer in entgegengesetzter Richtung usw.. Dann muß beim Abfragen ein Pin auf low gelegt werden und alle anderen, bis auf einen (Eingang mit pullup) auf high. Wenn der eine Eingang low ist, dann ist der Schalter von der Leitung auf low zu dem einen Eingang geschlossen. So komme ich nun je Eingang auf 2*(n-1) Schalter und insgesammt auf 2*n*(n-1) also 2n^2-2n; bei 7 also 35. Da ist mir wohl ein Flüchtigkeitsfehler unterlaufen ... Jedenfalls bekommt man so deutlich mehr als mit einer Matrix-Schaltung; bei 7 Leitungen wären mit einer Matrix-Schaltung nur maximal 3*4=12 Schalter anschließbar. Das fakultative Ansteigen, das ja stärker als ein exponentielles Ansteigen ist, bekommt man hin, wenn man n Leitungen mit n Leitungen verbindet, denn das entspricht einer Permuation von n Elementen und von denen gibt es bekanntlich n!. Das hatte ich mit Schaltern verwechselt, weil es verwandte Sachen sind.
Datum:
Naja, um diese Zeit stimmt das Beispiel nicht ganz; 2*n(n-1) ist mit n=7 natürlich 84. Gegenüber der einfachen Matrix-Schaltung hat man damit 7 mal mehr Schalter!
Datum:
Nachtrag: Je nach verwendeten Pegeln muß man die Dioden ggf. geeignet auswählen (höhere Schwellspannung), damit nicht Strom über mehrere Schalter (u. den seriellen Dioden) fließt. Bei sowas wie 1N4148 braucht man sonst einen MC mit einer Versorgungsspannung um 2 V, aber viele MCs sind ja bis 1,8 V spezifiziert.
Datum:
Also das Abfragen habe ich mir nochmal mit einem MC mit Pullups überlegt: Es muß Leitung m auf GND geschaltet werden, während alle als Eingänge mit Pullups geschaltet sind. Dann sind alle diejenigen Eingänge auf 0, bei denen der Schalter zw. m u. der Leitung geschlossen ist. So testet man insgesamt n mal durch. Bei einem 16-Bit-Port kann man so mit 16 Port-Abfragen 240 Schalter abfragen. Da fällt mir auch auf, dass es natürlich nur n*(n-1) Schalter sind (d. h. ohne Faktor 2), die man so abfragen kann ... Jedenfalls hat man so n^2-n gegenüber (maximal) (n/2)^2 gegenüber der Matrix-Schaltung, also bei n=7 schon 3,5 mal mehr Schalter.
Datum:
hmms könnte bitte einer mal das programm für nen 2313 umportieren ? und wenn an dreht das ein kurzer impuls für jede richtung an einem pin ausgegeben wird? währ ich echt dankbar für!!!! ich komme einfach nicht weiter
Datum:
schon mal danke, kannst du mir auch die pins duch sagen ? b1 zb oder b2 ... d etc.. das ich die pins weiss werd da net so ganz schlau raus
Datum:
An PORT D,0 und PORT D, eins kommt jeweils eine Led.
Ab PORT D... 4 und 3 den Drehgeber.. Ah ja, so solls ausehen:
.include "2313def.inc"
.set DIPGPin=PinB ;Port mit Drehimpulsgeber
.set DIPGChA=4 ;Pin mit Channel A
.set DIPGChB=3 ;Pin mit Channel B
.set DIPGBT=2 ;Pin mit Button
.def DIPGAlt=r4 ;Vorriger Zustand von Channel A
.def DIPG=r5 ;Drehimpulsgeber-Aktion. Nach Abfrage löschen
.def ButtonAlt=r6 ;Vorriger Zustand des Buttons
ldi r16, RAMEND ;Stackpointer initialisieren
out SPL, r16
ldi r24, 0xff
out DDRD, r24
ldi r24, 0xff
out PORTD, r24
ldi r24, 0xff
out DDRb, r24
main:
in r17,DIPGPin ;1 Drehimpulsgeber lesen
mov r18,r17 ;1 und in die Working-Register
mov r19,r17 ;1 kopieren
andi r18,1<<DIPGChA ;1 Channel A des Drehgebers ausmaskieren.
cp r18,DIPGAlt ;1 Hat es sich verändert?
breq DrButton ;1/2 Wenn nicht, dann Button prüfen.
mov DIPGAlt,r18 ;1 Aktuellen Zustand von Channel A sichern
lsl r19 ;1 Aus der Kopie des Drehgeberports
andi r19,1<<DIPGChA ;1 Channel B ausmaskieren.
cp r18,r19 ;1 Ist Channel A = Channel B?
breq DrLinks ;1/2 Wenn ja, dann wurde nach links gedreht
DrRechts:
rcall rechts
rjmp DrButton
DrLinks:
rcall links
rjmp DrButton
DrButton:
tst DIPG ;Wurde vorher abgeholt?
brne main ;Wenn nicht, dann Ende
mov DIPG,r16
rjmp main
links:
cbi PORTD,0
rcall pause
sbi PORTD,0
ret
rechts:
cbi PORTD,1
rcall pause
sbi PORTD,1
ret
pause:
ldi R21, 0x72
schleife1:ldi R22, 0xF2
schleife2:dec R22
brne schleife2
dec R21
brne schleife1
ret
Datum:
ich werde mal schnell die schlatung aufbauen und das ganze auf den avr laden, könntest du mir eventuell noch schnell die hex machen ? dann gehts schnell weiss net wo mein compiller is..
Datum:
ne danke hab 4 stück hier liegen, ne scho okay trozdem hab den compiler gefunden^^ werds gleich mal auf spielen such gerade noch widerstände...
Datum:
habs mal aufgebaut, aber so richtig funz es net... hmms auf wie viel mhz hast du es laufen ? ich hab derzeit nen 10mhz quarz dran...
Datum:
Angehängte Dateien:Hallo, habe versucht den zweiten Code von Peter zum laufen zu kriegen. Ich verwende einen AT90S2313 und den Drehgeber dessen Datenblatt im Anhang ist. Ich habe den gemeinsamen C - Anschluss auf 5V gelegt und A und B über 10k Widerstände gegen Masse. Dazwischen gehts jeweils zu einem Port-Pin (PD.0 und PD.1) vom µC. Habe am PortB LED's angeschlossen um zu schauen was die Variable enc_delta macht, aber es leuchtet dauernd nur die LED an PB.0 (auch keine Frequenz). Ich kann den Drehgeber drehen wie ich will, es tut sich nichts. Kann mir jemand weiterhelfen? Programmiere in CodevisionAVR. Hier mein Code: #include <90s2313.h> volatile char enc_delta; // -128 ... 127 interrupt [TIM0_OVF] void timer0_ovf_isr(void) { static char enc_last = 0x01; char i = 0; if( PORTD.0 ) i = 1; if( PORTD.1 ) i ^= 3; // convert gray to binary i -= enc_last; // difference new - last if( i & 1 ){ // bit 0 = value (1) enc_last += i; // store new as next last enc_delta += (i & 2) - 1; // bit 1 = direction (+/-) } } void main(void) { State7=0 PORTB=0x00; DDRB=0xFF; PORTD=0x00; DDRD=0x00; TCCR0=0x04; TCNT0=0x00; TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; OCR1H=0x00; OCR1L=0x00; GIMSK=0x00; MCUCR=0x03; GIFR=0x40; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x02; ACSR=0x80; // Global enable interrupts #asm("sei") while (1) { // Place your code here PORTB = enc_delta; }; } Gruß, Dominik
Datum:
Wenn ich nicht irre, ist der Code so ausgelegt, dass "C" an 0V liegt. Demzufolge werden die Pins dann wechselweise (Gray-Code) nach 0V gezogen. Probiers halt mal.
Datum:
if( PORTD.0 )
i = 1;
Da kannste lange warten.
Du must schon das Input-Register nehmen.
Peter
Datum:
AAAAAAAAARRRRGGGGGHHHH, sowas passiert mir immer wieder... Danke Peter!
Datum:
Funktioniert nun prima, allerdings wird die Variable bei jedem Schritt um 2 verändert, wie kann ich das ändern? Danke, Dominik
Datum:
Drehgeber für manuelle Bedienung machen oft 2 oder 4 Pegelwechsel je Rastung. Einfach dann den Wert vor der Auswertung 1* nach rechts schieben: int count; cli(); count += enc_delta >> 1; enc_delta = 0; sei(); Peter
Datum:
Drehgeber für manuelle Bedienung machen oft 2 oder 4 Pegelwechsel je Rastung. Einfach dann den Wert vor der Auswertung 1* nach rechts schieben: int count; cli(); count += enc_delta >> 1; enc_delta = 0; sei(); Peter angeblich schon? und ich hatte auch probleme mit dem programm die led ging nimma aus ?!
Datum:
Ich werte das ganz anders aus, lasse auch die Interupts an, da der Rest von meinem Programm sonst streikt.
Datum:
Üblicher Weise will man ja mit einem Drehgeber mehrere Parameter einstellen, je nach Menüpunkt. Und count ist hier nur stellvertretend für irgend einen Parameter in irgend einem Menü. Die Beispielroutine betrifft das nicht, sondern eben nur die Weiterverarbeitung. Ist ja nur ein Beispiel und keine komplette Anwendung. @Dominik Eine Interruptsperre ist immer notwendig, wenn man Variablen bearbeitet, die auch ein Interrupt in den Fingern hat. Im Beispiel ist das eine Sperre von etwa 1µs, kann also gar keinen Einfluß auf andere Programmteile haben. Peter
Datum:
kann einer das eventuell so umbauen, das ich bei ner endsprechenenden drehbewegung zb nach rechts nen kurzen impuls bekomme und nach links wieder einen auf nen bestimmten port´? so dasich von auß0en weiss das das teil gedreht wird endweder nach links oder nach rechts.... währ einer so nett?
Datum:
Geht nicht; so einen Drehgeber für Dummys gibt's nicht. Du mußt die aktuelle Flanke (steigentd/fallend) und dabei den Zustand der anderen Ader (high/low) auswerten. Wenn man alle Flanken auswertet, kommt man auf halbe Schritte, durch die man die meisten Fehler rausfiltern kann.
Datum:
ich habe eure unerhaltung -hoffentlich ganz - gelesen. sie wure mir von peter danegger empfohlen. Doch glaube ich nicht, sie in meinem fall anwnden zu können. Ich weiss zwar noch nicht welchen controller ich schussendlich verwenden werde, doch besteht meine aufgabe ... mein ziel... darin dieses signal über den controler mittels profi bus an eiene sps weiterzuschicken!! ich habe scho einmal ein reines empfang und anzeigeprogramm geschreiben, doch hier werden mehrere takte benötigt! so denke ich, dass ich zu langsam für einen impulsgeber werde. sollte das nicht stimmen bitte ich um antwort.
Datum:
Du solltest den Gray-Encoder in den Controller packen und den Status des Gray-Encoders über den Bus schicken, wenn sich der Status geändert hat. Je nach Anwendung sollte das limitiert sein, also z. B. nach jedem Datenpaket vom Controller eine Sendepause von mindestens 100 ms.
Datum:
soweit ich das mitbekommen habe, ist der grey code nichts anderes als die beiden signale, die ich vom impulsgeber bekomme, und aus denen ich die information über vor - rück und "stand" holen kann. was mache ich wenn ich ein signal übersehe, also wie ich meine zu langsam bin??? oder ist das direkt schicken abhilfe genug?
Datum:
Also entweder muß man die Flanken über Interrupts einlesen oder über eine Timer-ISR die Leitungen mit mindestens 10 kHz auslesen.
Datum:
aso jetzt verstehe ich: auswerten am controller (mittels tabelle) aber status nur bei änderung oder nur in bestimmten intervallen
Datum:
Ja, die Information, daß sich nichts geändert hat, braucht man ja normalerweise nicht übertragen. Sofern im System keine Daten verloren gehen, ist sowas komplett überflüssig.
Datum:
Angehängte Dateien:noch eine frage: ich habe eine schalturg empfhlen bekommen, die extern decoded und einen insgesamt 32 bit zähler enthält?? was soll ich davon halten? die schaltung (im .doc format ist von der hctl 2020 verbindung mit 051)
Datum:
bei dieser schaltung ist jedoch insgesamt 3x zu demultiplexen und das is nicht was ich mir unter sinnvoll und einfach vorstelle!!!!
Datum:
Nimm doch einfach einen AT89C2051 der den Drehgeber einliest und dann in den Profibus umsetzt. Dürfte wesentlich billiger sein als der HCTL2020. Ob Du dann 32 oder 64 Bit zählst ist auch egal. Ist der HCTL2020 nicht außerdem abgekündigt (last order 06/2005) ? Peter
Datum:
du meinst einen anderen controller??? ich hatte zuerst vor die 90er serie zu verwenden, da ich da das 200stk besitze! der externe zähler wäre wahrscheinlich wegen der geschwindigkeit! ich habe eben bedenken wegen der geschwindigkeit, wenn extern ein 32 bit zähler vorgeschlagen ist!!!!
Datum:
Das war nur ein Beispiel, ein ATTiny26 oder ähnliches geht natürlich auch. Für die Abtastgeschwindigkeit ist nur die maximale Drehgeschwindigkeit entscheidend, also wieviele Phasenwechsel pro Sekunde. Der Timerinterrupt sollte mindestens doppelt so oft kommen. Die Zählbreite ist uninteressant. Peter
Datum:
@Peter >Nimm doch einfach einen AT89C2051 der den Drehgeber einliest und >dann in >den Profibus umsetzt. auch wenn es etwas am Thema vorbei ist, aber was machst Du denn mit einem AT89C2051 am Profibus? Ich dachte bisher, dass da nur etwas vom Schlage eines SPC3 o.ä. zu finden ist. Die eigentliche Übertragung ist zwar nur RS485 und UART, aber das ganze Protokoll...? Sollte das wirklich in einen 2k-8051er passen? Jörg
Datum:
du meinst es ist von grund auf sinnlos?? also ist das projekt abzublasen???
Datum:
"du meinst es ist von grund auf sinnlos?? also ist das projekt abzublasen???" Aber wer wird denn gleich aufgeben. Die maximale Datenrate von 12MBaud schafft der zwar nicht, aber 93,75kBaud geht. Bzw. mit nem ATMega8 oder AT89LP4052 bis zu 500kBaud. Das Protokoll zu implementieren dürfte eher eine Frage Deiner Programmierkünste sein oder du kriegst irgendwo was fertiges. Oder Du nimmst irgendein fertiges Profibus-IO-Modul und der ATTiny26 (oder was auch immer) übergibt nur die Zählwerte (seriell oder parallel). Peter
Datum:
Danke für deine weiteren Bemühungen. ich habe jetzt eine Lösung
gefunden:
Ich lese das Signal mittels HCTL2032 aus und lese dann
alle x ms ein. Denn mit dem Profi BUS übertragen wird der Controller
genug zu tun haben.
Datum:
Scahue Dir mal den LS7366 von LSI/CSI an, hat einen Quadraturdecoder und wird über eine SPI angehängt. Distributor ist die Scantec GmbH in Germering. Der hat auch einen internen 32 Bit Counter sowie Carry/Borrow Ausgänge zur externen Kaskadierung. Ich habe hier auch so was vor, allerdings arbeite ich mit optischen Encodern mit 2500 Impulsen/Umdrehung und bis zu 80Khz Impulsfrequenz im 4x Mode. Ich muß mir dazu noch eine Regelung einer PWM mit AVR einfallen lassen. Momentan weiß ich da noch gar nicht recht wie ich da anfangen soll... 2 LS7366 habe ich als Samples bekommen. Gruß, Holm
Datum:
Angehängte Dateien:@Holm, das Problem dürfte aber sein, den LS7366 zu beschaffen und billig dürfte so ein Exot auch nicht gerade sein. Aber die 80kHz sind auch ohne weiteres auch mit einem µC zu schaffen. Wenn man mit 160kHz abtastet, hat der ATTiny bei 16MHz internem Clock immer noch massige 100 Zyklen Zeit. Und wenn man in Assembler optimiert, braucht man nur max 26 Zyklen im Interrupt. D.h. man kann ohne weiteres alle 32 Zyklen abtasten, also noch Signale bis 250kHz fehlerfrei einlesen. Anbei die Encoder-Routine in Assembler. Nur Timer Initialisierung und SPI fehlt noch. Auch 80kHz sind also noch lange kein Grund, teure und schwer beschaffbare Exoten zu nehmen. Peter
Datum:
währ einer bereit für die conrad drehimpuls potis be routint zu coden ? für einen S2313 ?avr ? das bit muster der 2 pins kann ich gerne raus geben.. was ich brauche ist ne ganz einfache schaltung die 2 bins jeweils auf high setzt und dann wieder auf low, so das ich nen kurzen impuls nur habe, für jede dreh richtung einen pin, sprich dreht man nach links -> pin 1 auf high, dreht man nach rechts -> pin 2 auf high,.... schalt plan kann ich gerne mit geben, wo die pins stehen und das bit muster was den avr vom dreh impuls geber erwartet... sind 2 leitungen vom impulsgeber... währ echt sehr sehr danbakar hab das teil seid 2 monaten und komme einfach nicht mit der software im avr klar, hab das www ach schon wie blöde durchsucht...
Datum:
@peter: Ja. Ich habe auch schon daran gedacht einen 2313, von denen hier einige herumliegen, für sowas zu mißbrauchen. Irgendwo gibt es auch eine Implementation mit einem 90S1200 in Assembler. Momentan habe ich den Decoder in ein GAL(16V8) gebrannt und da kommt ein Richtungssignal und ein Clock heraus. Die Mimik wird mit 1,8432 Mhz getaktet und der Ausgangsimpuls ist nur eine halbe Periode breit. Diese Mimik habe ich an einen AtMega16 gehängt und befeuere damit den externen Int0. Die ISR hat nicht mehr zu tun, als nach am Port nach der Richtung zu fragen und den 32 Bit Counter zu incrementieren oder zu decrementieren. In der Hauptschleife zeige ich auf einem LCD Drehzahl und sowas an. Das Ganze in C (gcc). Der mit 16Mhz getaktete AtMega16 verliert dabei aber Interrupts. (Die sind Flankengetriggert!) Ich habe die Clockimpulse mit einem 74LS74 aufgefangen und bestätige diese mit einer Art INTACK Signal um das FF wieder zurückzusetzten. Das geht besser, Allerdings gefiel es mir halt selber nicht. Dazu käme eigentlich noch ein digitales Filter für die A und B Phasensignale aus einem weiteren GAL und 2 74LS72. (oder halt CMOS, aber die GALs sind ja auch schon heftig mit der Stromaufnahme). An der Stelle habe ich mich umgesehen, was es sonst noch so gibt. Ich habe irgendwo mal 2 HCTL2016 ausgeschlachtet, aber deren Interner Zähler ist zu klein (16 Bit) und es gibt außen kein Signal das irgendwie Bescheid gibt, daß sich am Geber was getan hat. Man muß das Ding also pollen.... find ich doof. Ein HCTL2020 war mir zu teuer, ist aber dem LS7366 ähnlich und enthält wie dieser schon die digitalen Filter. In AVR Assembler bin ich überhaupt nicht firm, habe ich noch nicht gebraucht. Ich kann das Zeug zwar lesen, aber nicht schreiben :-) Ich kenne aber Assembler diverser anderer Micros, Z80 Maschine teilweise noch aus dem Kopf, auch Ekeldinger wie 8048 hatte ich schon mit teilweise selbst(um)gebauten Assemblern zwischen den Fingern aber auch 51er 68000er und 6809/11. Bei dieser speziellen Sache hier geht es mir um Nichts weiter, als die Steuerung meiner im Bau befindlichen 2. Trafowickelmaschine. (Ich mache auch noch mit Röhren rum und brauche ab und an Ausgangstrafos). Ich bräuchte da vielleicht mal ein paar Hinweise oder mal ein Beispiel in irgend einer Form, welche Algorithmen es gibt um einen Gleichstrommotor mittels Drehgeber und PWM bestimmte Positionen anfahren zu lassen. Ich habe aber keine PWM Brücke gebaut, sondern habe da ein Relais für die Drehrichtungsumkehr, einen 100W Getriebemotor und eine PWM Stufe mit einem IGBT, das Zeug klappt soweit ganz gut. Ich habe aber natürlich, weil das ein Bastelobjekt ist, keinerlei Daten über Massenträgheiten oder ähnlichen Kram, des noch nicht fertigen mechanischen Systems. Irgendwie soll das Ding mal "weich" die Drehzahl regeln, gegen Ende einer Wicklungslage langsamer werden und stehen bleiben damit man Lagenisolation einfügen kann usw. usf. Die Drahtverlegung soll ein Schrittmotor mit einer Spindelmimik machen, der mittels programmierbarem Teilerverhältnis von den Drehgeberimpulsen angesteuert wird, natürlich soll das Ding auch noch selber ausrechnen wie das Teilerverhältnis bei unterschiedlichen Drahtstärken auszusehen hat. Den Schrittmotor werde ich mit einem TA8345H Ansteuern, der ist programmierbar von Voll- bis Achtelschritt, sowas liegt hier gerade herum (fertige kleine Endstufen). Die Drahtspannung, und damit natürlich auch die Last des Motors soll natürlich auch variabel sein, also wo und wie fange ich an ....? Suggestions? Danke, Holm
Datum:
Hallo Holm Ich habe die 20xx (keinen!!!) bekommen. doch habe ich jetz eine Seite gefunden, wo ich 7366 kaufen(scantec schickt nicht nach Ö) kann. Was hast du mit deinen IC gemacht? Wie funktioniert deine Steuerung bzw Regelung? Könnte ich vielleicht die SPI Kommunikations Source haben? danke hermann
Datum:
Wo bekommt man denn diese Drehgeber? Hab in der Vergangenheit den DDM427 von Conrad verwendet, doch nun soll er angeblich nicht mehr lieferbar sein. Bei RS hab ich auch noch keinen gesichtet und bei Reichelt erst recht nicht. Noch ne Anmerkung zur Programmierung. Die DDM427 sind eigentlich nur im Interruptbetrieb einsetzbar, weil dieser Drehgeber im Vergleich zu anderen nicht statisch abfragbar ist. Nimmt man das im Datenblatt vorgeschlagene RC-Glied zum Entprellen, so geht das ganz wunderbar.
Datum:
"Die DDM427 sind eigentlich nur im Interruptbetrieb einsetzbar, weil dieser Drehgeber im Vergleich zu anderen nicht statisch abfragbar ist." So ein schmarrn! Ich setze den DDM427 sowohl im PKW im Pin Change Interrupt an einem Tiny26 mit RC-Glied und zu Hause im Polling-Modus ohne RC-Glied, wo der Geber aus dem Timer-Interrupt mit 10KHz abgefragt wird, ein. Beides geht wunderbar. MfG Andi
Datum:
Na, jetzt mal nicht so deftig dahergeplappert. Die Treffsicherheit im Pollingmodus ist deutlich geringer als wenn man Interrupts verwendet. Ich hab's ausprobiert. Wenn mann wenig Rechenzeit verbraten möchte, ist der Pollingbetrieb jedenfalls nicht optimal. Und wo krieg ich jetzt neue Drehgeber her?
Datum:
War das so heftig? Tschuldigung! Mal im Ernst. Im Polling-Modus, und vor allem ohne RC-Glied, sollte man natürlich eine Soft-Entprellung mit einbauen, welche man für den Button gleich mit verwenden kann, oder das Verfahren von Peter, hier ganz oben, verwenden. Auf jeden Fall, gehn tut das, habe ja beides erfolgreich ausprobiert. Und wenn man sowieso einen 10KHz-Timer wegen viele anderer Dinge im Einsatz hat ist das auch nicht mehr die Welt, zumindest in ASM. Das Conrad die nicht mehr hat verstehe ich nicht, immer hin haben die bei deren Preis wohl recht gut daran verdient. Wahrschinlich zu geringe Mengen davon verkauft und dann ausgemustert. Weis auch nicht, wo man den selben Typ her bekommt und Reichelt hat leider immer noch keine Geber. MfG Andi
Datum:
bei Neuhold Elektronik gibts einen guten und günstigen (5 Euro): http://www.neuhold-elektronik.at/catshop/default.p... der liefert hier auch ohne Entprellung gute Ergebnisse.
Datum:
Tach zusammen, ich hab grad auch eine Anwendung, wo ich ein Dreh-Encoder (auch Jog-Rad genannt) einsetze. Damit will ich in einem Menue rumdrehen und mit der Taste am Dreh-Encoder meine Auswahl treffen (Eigentlich wird nur ein Zähler auf- oder abwärts gezählt). Die Spur A ist auf einem Interrupt gelegt, Spur B liegt auf einem Port ohne Interrupt. Erfolgt eine Drehung, springt der Interrupt mit der Spur A an. Dann kommt eine Auswertung wie Spur A steht, gleichzeitig wie Spur B steht. Der Wert wird mit dem letzten Wert verglichen. Ist es unterschiedlich, wird entschieden, ob ein Zähler auf- oder abwärts zählt. Aber irgendwie ist das nicht das wahre: drehe ich langsam, kommt manchmal Mist raus, drehe ich zu schnell ebenso. Wie habt Ihr die Abfrage des Dreh-Encoders realisiert? Sollte ich anstatt des Interrupts einen Timer nutzen (wenn ja, wie)? Gruss, Ampel
Datum:
> Wie habt Ihr die Abfrage des Dreh-Encoders realisiert? Sollte ich > anstatt des Interrupts einen Timer nutzen (wenn ja, wie)? Schau dir mal den ersten Beitrag an. Funktioniert einwandfrei!
Datum:
Ich habe es mal auf MSP430 und ARM9 mit Fehlerkorrektur gemacht, da ja von einer Position zur nächsten zwei Interrupts kommen, und folglich jeder als ein halber Schritt gezählt werden sollte. Zählt man jeden Interrupt als halben Schritt, dann sind auch prellende Drehgeber kein Problem, wie auch Praxis-Tests zeigten. Das langsame Drehen bekommen man mit der Hand hin; das schnelle mit einer Bohrmaschine. Hier der Code für MSP430:
// Macro for setting the IES flags for the gray encoder consitent.
// E. g. BIT6 set -> set the associated IES (for IRQ on falling edge).
// Has to be called e. g. at the start of main.
#define mc_CONSISTENT_J \
{ \
if (P2IN & BIT6) \
P2IES |= BIT6; \
else \
P2IES &= ~BIT6; \
if (P2IN & BIT7) \
P2IES |= BIT7; \
else \
P2IES &= ~BIT7; \
}
signed char c_gc_c = 0; // grey code (interrupt) counter with
sign for direction: + means right
unsigned char uc_l = 0; // counter for the irqs from left
output (port2, Bit6) of grey encoder
unsigned char uc_r = 0; // right
(port2, Bit7)
uint32_t uli_errors = 0;
// macro for resetting the grey encoder variables (above)
// Has to be called e. g. at the start of main.
#define mc_RESET_J \
{ \
P2IFG &= ~(BIT6 | BIT7); \
c_gc_c = 0; \
uc_l = 0; \
uc_r = 0; \
}
#define mc_c_gc_cP {if (c_gc_c < 100) ++c_gc_c;} // one step with
direction, increment with saturation
#define mc_c_gc_cM {if (c_gc_c > -100) --c_gc_c;} // decrement
#define mc_uc_lP {if (c_gc_c < 100) ++uc_l;} // one step left;
increment with saturation
#define mc_uc_rP {if (c_gc_c < 100) ++uc_r;} // one step right
In der ISR:
switch (P2_IRQs & (BIT6 | BIT7)) // Mask for BIT6 and BIT7.
{
case 0: // no irq; should never happen
uli_errors++;
break;
case (BIT6 | BIT7): // 2 irqs; should never happen
mc_uc_lP;
mc_uc_rP;
uli_errors++; // error
break;
case BIT6:
mc_uc_lP;
switch (P2IES & (BIT6 | BIT7))
{
case 0: // 00 -> 01 (P2IN, bit6 = 0 and bit7 =
1), right
mc_c_gc_cP;
break;
case (BIT6): // 01 -> 00, left
mc_c_gc_cM;
break;
case (BIT7): // 10 -> 11
mc_c_gc_cM;
break;
case (BIT6 | BIT7): // 11 -> 10
mc_c_gc_cP;
break;
default: // can never happen
uli_errors++;
break;
}
break;
case BIT7:
mc_uc_rP;
switch (P2IES & (BIT6 | BIT7))
{
case 0: // 00 -> 10
mc_c_gc_cM;
break;
case (BIT6): // 01 -> 11
mc_c_gc_cP;
break;
case (BIT7): // 10 -> 00
mc_c_gc_cP;
break;
case (BIT6 | BIT7): // 11 -> 01
mc_c_gc_cM;
break;
default: // can never happen
uli_errors++;
break;
}
break;
default: // can never happen because only PIN6 and PIN7 are
interrupt enaled
uli_errors++;
break;
}
mc_CONSISTENT_J;
if (((P2IN & BIT6) >> 6 == (P2IN & BIT7) >> 7) // equal
inputs
&& (uc_l) // left irq
&& (uc_r) // right irq
) // stationary position
{
if (c_gc_c <= -2)
{
if (c_gc_c < -2)
uli_errors++;
KEYBOARD.key[KEYBOARD.start] = KEY_JOG1PLUS; // one step right
KEYBOARD.start++; // new input
mc_RESET_J;
}
else
{
if (c_gc_c >= 2)
{
if (c_gc_c > 2)
uli_errors++;
KEYBOARD.key[KEYBOARD.start] = KEY_JOG1MINUS; // one step
left
KEYBOARD.start++; // new input
mc_RESET_J;
}
}
}
|
Man kann es natürlich auch umschreiben auf einen Timer-Interrupt, der die Eingänge ausliest. Bei einem Prozessor, bei dem man die Eingänge zweifach flankengetriggert einstellen kann, ist der Code kleiner. Hierbei hat left u. right irq nichts mit der Drehrichtung zu tun; die beiden sind für die beiden Adern des Drehgebers; die Information der Drehrichtung ist zeitlich codiert (durch Phasenverschiebung). Bei einem 4-er-Drehgeber ist es etwas komplizierter, aber es können auch noch 3-Flanken-Fehler korrigiert werden. Durch den Fehler-Zähler kann man angeben wie zuverlässig der Drehgeber ist, indem man den Fehler-Zähler durch die Anzahl der Steps (Rechts- u. Links-Schritte) zählt.
Datum:
@Rolf, wirklich ein imposantes Codemonster, wenn ich doch bloß erkennen könnte, was daran besser sein soll. Warum probierst Du nicht mal mein kleines schnuckeliges Progrämmchen (Encode.c) aus ? Du wirst verblüfft sein, wie zuverlässig es entprellt und dekodiert. Für Ängstliche, die denken, ein Timer ist zu aufwendig, es muß auch nicht im Timerinterrupt aufgerufen werden. Man kann genausogut einen Pin-Change-Interrupt nehmen, Hauptsache der Interrupt reagiert auf alle 4 Flanken. Peter
Datum:
Hallo rote Ampel :-) Im ersten Beitrag von mir hier habe ich meinen ersten Versuch mit einem Drehgeber über IRQ von Kanal A (Pin Change IRQ) abgebildet. Ist zwar am Ende etwas anders geworden aber im Prinzip geht das über Pin Change IRQ wie folgt: Drehgeber ändert Kanal A -> IRQ wird ausgelöst. Kanal A und B auslesen. Kanal A und B mit zuvor gemerkten Kanal A und B vergleichen. Ist der aktuelle Wert von Kanal A und B anders als der vorige dann: Aktuellen AB-Wert merken (Variable). Ist Kanal A = Kanal B dann wurde nach links gedreht. Ist Kanal A <> Kanal B dann wurde nach rechts gedreht. Das ist alles. Entweder mit 10K und 10nF jeden Kanal und den Button entprellen oder per Timer-Software. MfG Andi
Datum:
Der Code von mir wird in einigen Geräten eingesetzt und der funktioniert sehr zuverlässig. Bei Drehgebern, bei denen es mit nur einfacher Flanken-Zählung (nur fallende oder steigende Flanken) deutliches Prellen gibt, funktioniert mein Code ohne Prellen. Die Fehlerzählung habe ich drinn für Features wie den extrapolierten Zeitpunkt des Totalausfalls oder Ferndiagnose, aber bisher ist es ungenutzt.
Datum:
@Rolf F: Es ist einfach nur irsinnig so viel Code zur Drehgeberauswertung zu machen. Ich habe Peters Code in ASM umgesetzt was ein paar Befehle sind und es funtzt ohne Probleme genauso wie die Version A = B ist links und A <> B ist rechts mit Soft-Entprellung per Timer (0,3ms). MfG Andi
Datum:
Ok, mit Ist Kanal A = Kanal B dann wurde nach links gedreht. Ist Kanal A <> Kanal B dann wurde nach rechts gedreht. kann man meinen Code noch optimieren. Beim MSP430 hat man etwas mehr Code als z. B. beim ARM9 dadurch, daß die Eingänge nicht doppelt flankengetriggert eingestellt werden können, so daß man das emulieren muß.
Datum:
>daß die Eingänge nicht doppelt flankengetriggert eingestellt werden >können Dann wäre ja gerade beim MSP430 ein Polling im Timer der beiden Kanäle sinnvoller. >Ok, mit > Ist Kanal A = Kanal B dann wurde nach links gedreht. > Ist Kanal A <> Kanal B dann wurde nach rechts gedreht. >kann man meinen Code noch optimieren. Du meinst wohl ersetzen. Oder mit Peters Methode welche komplett ohne Hard- oder Soft-Entprellung auskommt. MfG Andi
Datum:
Angehängte Dateien:ich hatte bevor ich hier die C-Variante gefunden habe auch mal eine asm Version mit Tabelle gebaut, d.h. die Schritte müssen wenn die zwei Bits binär codiert in der Reihenfolge 1,3,0,2 oder andersrum kommen. Wenn man prüft ob der neue Zustand genau einen davor oder dahinterliegt wird es auch einfacher als die bitweise Prüfung. In meinem Beispiel wird + oder - je nach Step ausgegeben. Zusätzlich gibt es noch ein paar Tasten die dann Ziffernausgaben machen (allerdings noch nicht ordentlich entprellt, nur über das delay durch serielle Ausgabe zwischen zwei Abtastungen). Das soll mal mein Drehgeber für einen CarPC werden.
Datum:
Hallo, ich habe gerade den Code von Peter mit einem Drehgeber von Conrad getestet (427), funktioniert auch sehr gut (besser als mein eigener mit Flankenwechsel im Interrupt). Jedoch ändert sich der Wert bei jeder Rasterstellung um zwei anstatt um eins. Peters Tip mit: > Einfach dann den Wert vor der Auswertung 1* nach rechts schieben: > int count; > cli(); > count += enc_delta >> 1; > enc_delta = 0; > sei(); funktioniert bei mir nicht. Was meiner Meinung nach daran liegt, dass wenn enc_delta negativ ist, und ich dieses Zweiekomplement nach rechts schiebe, mein Wert nicht mehr negativ ist. Beispiel: enc_delta = -2 0b 1111 1110 // -2 und um eine Stelle nach rechts verschoben: 0b 0111 1111 // +127 Oder habe ich irgendwo einen Denkfehler?
Datum:
@Thomas
Stimmt, ganz so einfach geht es nicht. Die Halbschritte gehen
verloren.
So sollte es gehen:
cli();
if( !(enc_delta & 1)){
count += enc_delta >> 1;
enc_delta = 0;
}
sei();
Das Schieben selber funktioniert auch mit negativen Zahlen, nennt sich
arithmetisches Shift (Befehl ASR).
Peter
Datum:
@Peter Dannegger: Du hast in einem Beitrag vom 17.03.2005 den AT89LP4052 erwähnt. Das Teil interessiert mich brennend. Hast du schon mit dem gearbeitet? Wenn ja, woher hast du ihn bekommen? Gruß Ralf
Datum:
Das Problem bei allen Softwarelösungen ist dass sie nicht alle Flanken auswerten und damit an Auflösung einbüßen. Die "Drehgeber" sind Quadraturencoder und liefern 4 Zustände von denen nur 2 zu Richtungsermittlung und 2 für den Weg benutzt werden können. Entweder werden nur 0 oder 1 ausgewertet. Steigende- und Fallende Flanken sind mit den üblichen Kontrollern nicht auswertbar zum anderen ist der Kontroller mächtig beschäftigt. Die eine arbeitet sehr zuverlässig und arbeitet mit 4 CMOS Gatter und ein paar R und C's. Sie wertet alle 4 Flanken aus und liefert Takt für den Weg und ein Bit für Rechts/Links-Lauf. ich benutze den Counter der 8051 Derivate zur Wegermittlung (Zählerstand) und ein Portbit für die Richtung. Von Hand habe ich es mit einem Incrementalgeber mit 200Ticks/-1 nicht geschafft Schrittverlusste zu erzeugen. Eine andere Lösung ist weniger Aufwändig jedoch muss man CPLD's von Xilinx Programmieren können. Etwas teuerer ist sie liefert aber sofort 6 Auswerter. Dazu wird ein XC9536 mit einem TTL-Takt Generator eingesetzt. Die Ausgangssignale sind ebenfalls Takt und Richtung. Evtl. will ich auch mal einen Zähler implementieren. Man könnte das Ding dann direkt an einen Bus koppeln und die Zähler via Register auslesen. Mal sehen. Wenn interesse kann ich das Zeug mal Posten Gruß Gerd
Datum:
das kommt eben darauf an wofür der Encoder eingesetzt wird: die meisten hier vorgeschlagenen Routinen sind für die digitalen Drehknöpfe wie sie z.B. an Audiogeräten zu finden sind und die werden nicht so schnell gedreht. Wenn der Encoder an einer drehenden Welle sitzt dann muss man rechnen ob man da noch schnell genug abtastet.
Datum:
"Das Problem bei allen Softwarelösungen ist dass sie nicht alle Flanken auswerten und damit an Auflösung einbüßen." Häää ??? Wenn man etwas zu einem Thread zu sagen zu haben meint, dann sollte man ihn doch auch bitteschön erst einmal lesen. Bzw. wenn man etwas nicht verstanden hat, dann kann man ja erst einmal fragen. "ich benutze den Counter der 8051 Derivate zur Wegermittlung (Zählerstand) und ein Portbit für die Richtung." Seit wann kann denn der internen Zähler vorwärts und rückwärts zählen ? Peter
Datum:
Ja, sehe ich auch so. Meinen obigen Code habe ich zwar nur für einen Drehschalter für Menüs gemacht, aber testweise auch mit einer Bohrmaschine angetrieben. Übrigens gibt's auch Drehgeber die von einer Raster-Position zur nächsten nicht zwei sondern vier Flanken liefern. Bei sehr hohen Drehzahlen muß man einen MC nehmen, der nichts weiter macht als nur den Drehgeber auswerten und das Ergebnis ohne IRQ, z. B. als Gray-Code parallel ausgibt. Damit kann man bis ca. eine Million Flanken pro Sekunde zählen.
Datum:
Hallo Gerd, das mit 'Steigende- und Fallende Flanken sind mit den üblichen Kontrollern nicht auswertbar zum anderen ist der Kontroller mächtig beschäftigt.' ist eher eine historische Betrachtung, oder ? Bei den ATTinys jedenfalls hast Du mit den PCINT natürlich die Möglichkeit auf alle Flanken zu triggern. Gruß Uli
Datum:
Hallo,
nach diesem ewig langen Thread blickt ja keiner mehr durch, daher poste
ich hier nocheinmal Peter's Code, angepasst für Drehgeber wie den von
Contrad Elektronik, d.h. die Rast-Stellung ist entweder bei 00 oder 11.
Dafür habe ich eine winzige Erweiterung eingebaut (variable tmp), so
dass der Zählerstand pro Raststellung nur um eins, nicht um zwei
weiterzählt.
Den ganzen quatsch mit cli() und shiften und murksen und sei() kann man
sich dann nämlich sparen.
Ich musste allerdings auch feststellen, dass Peters Code bzgl.
Entprellung nicht optimal ist. Es passiert leider häufiger, dass
Drehimpulse verloren gehen, besonders wenn man etwas vorsichtig dreht.
Das werde ich mir später mal genauer ansehen. Vielleicht hilf ja eine
externe Filterung.
Hier der Code: (Drehimpulsgeber ist angeschlossen an PE4 und PE3)
---- globaler Speicher des Drehwertes
volatile int8_t enc_delta=0; // -128 ... 127
---- innerhalb der Timer Routinte ----
static int8_t enc_last = 0x01;
int8_t i;
uint8_t tmp;
i=0;
// digiswitch polling
tmp=PINE;
if( (tmp & _BV(PINE4)) )
i = 1;
if( (tmp & _BV(PINE3)) )
i ^= 3; // convert gray to binary 00->11, 01->10
tmp=i; // save value in binary code for test of increment
i -= enc_last; // difference new - last
if( i & 1 ) // bit 0 = value (1)
{
enc_last += i; // store new as next last
if (!(tmp & 1)) // change only for 00/10 in binary code
enc_delta += (i & 2) - 1; // bit 1 = direction (+/-)
}
------------ end ---------------
Datum:
@Christian "Den ganzen quatsch mit cli() und shiften und murksen und sei() kann man sich dann nämlich sparen. ... Es passiert leider häufiger, dass Drehimpulse verloren gehen" Ja das kommt davon. Ich hab mir nämlich bei dem "ganzen Quatsch" schon was gedacht. Und das cli/sei kann man erst recht nicht sparen, da man ja die Variable gleichzeitig lesen und löschen muß (atomar). Peter
Datum:
Hallo Peter, ich verändere/lösche die Variable enc_delta nicht. Warum sollte ich auch, ich brauche sie absolut. Trotzdem gehen Impulse verloren, im ungüstigsten Fall zählt er sogar mal in die falsche Richtung. Die Conrad Drehgeber scheinen wahre Prell-Wunder zu sein. Im Moment fehlt mir die Zeit, aber bei Gelegenzeit werde ich mir die Signale mal mit dem Speicher-Osci. anschauen was da so los ist und ob eine SW Entprellung Sinn macht. Grüße Christian P.S: (Wenn man enc_delta ausserhalb des Interrupts verändert, muss man natürlich die Interrupts blockieren, ich denke das ist klar.)
Datum:
Das Prellen des Conrad rotary switch bekommt man übrigens recht gut in den Griff, wenn man den Timer Tick stark reduziert. Ich habe den jetzt auf 100Hz eingestellt (waren bisher 1000Hz). Damit ist das Prellen ziemlich stark reduziert. (laut Datenblatt ist die Prellzeit 2ms und die Pulsezeit 6ms bei 60rpm! (d.h. 30pulse/sec)) Natürlich gehen - wenn man schnell dreht - Impulse verloren, aber bei meiner Anwendung stört das nicht, Genauigkeit beim langsamen drehen ist mir wichtiger. Grüße Christian Wenn man Lust hat, könnte man natürlich die Pulsedichte (Pulse/sec) auswerten und die Sample-Zeit dynamisch anpassen...
Datum:
Bei dem Drehgeber von Conrad kommt von einer Raster-Position zur nächsten nur einen Puls; besser ist einer der zwei Flanken (statt einer) ausgibt, bei dem man also halbe Schritte zählen kann.
Datum:
Seltsam. Wenn Du den ddm427 meinst, den habe ich mit Peters Code, in ASM umgeschrieben, und auch mit eigenem Code bei 10KHz Timer erfolgreich betrieben. Bei dem eigenen Code brauchte ich zum Entprellen für alle 3 Signale, A, B und Button, nur 1 Filterung von 2 Timer-Ticks. MfG Andi
Datum:
@Christian, daß eine geringere Abtastung helfen soll, klingt äußerst merkwürdig. Hast Du denn die Variante mit dem Schieben überhaupt probiert ? Ich hab jetzt Deine Code nicht in allen Einzelheiten überprüft, würde aber sagen, daß er die Entprellfunktion aushebelt. Auch ist ein ASR wesentlich weniger Code, als ein zusätzliches Register im Interrupt (+PUSH/POP). Peter
Datum:
@Andi, ja laut Conrad Datenblatt heisst er ddm421. Ich betreibe ihn auch erfolgreich mit Peters Code, nur halt nicht 100% ohne Prellen, ich benutze aber auch keinerlei zusätzlicher Entprellung so wie du. Und er ist nagelneu. Das Prellen ist übrigens nur bei wenigen der 30-Raststellungen festzustellen. Ist vielleicht auch ein Montagsgerät... @Peter, der Code ist 99.5% identisch mit deinem. Änderungen: - Samplen des Inputregisters nur einmal (vmtl. irrelevant) - Berechnen des Ausgangswertes nur wenn Zustand 00/11 vorliegt, Das sind die Raststellungen des Drehgebers (bei dir wurde er immer berechnet d.h. bei 00/01/11/10 - darum zählt er doppelt) Die Graycode Entprellung wird dadurch aber nicht beeinflusst. Das Prellverhalten war mit 100% Peter genauso wie mit 99.5% Peter. Performance: Eine tmp Variable habe ich sowieso in meiner Timer Tick Routine, aber darauf kam es mir ja auch nicht an, ich möchte mir das Rechnen im Hauptprogram sparen. Warum bei langsamen Timer-Tick weniger prellen? Die Wahrscheinlichkeit, dass man die 2ms Prellzeit trifft, nimmt natürlich ab je weniger schnell man sampled. Mit 1kHz (1ms) treffe ich zwei mal den undefinierten Zustand während der Prellzeit, mit 10ms nur noch mit Wahrscheinlichkeit 1:5. (Die Prellzeit sollte dabei natürlich nicht stark von der Drehgeschwindigkeit abhängen...) Grüße Christian
Datum:
"Die Graycode Entprellung wird dadurch aber nicht beeinflusst. Das Prellverhalten war mit 100% Peter genauso wie mit 99.5% Peter." Gibs doch zu, Du hast es garnicht erst probiert. Deine 0,5% setzen nämlich die Entprellung außer Kraft: Du zählst bei 00->10 rauf aber bei 11->10 runter. D.h. ein Preller 00->10->00 zählt nur rauf und damit falsch. Prinzipbedingt kann mein Code erst dann ein Prellen nicht mehr korrigieren, wenn beide Signale gleichzeitig prellen, d.h. kein Graycode mehr rauskommt (nur ein Signal ändert sich). Eventuell gibt es ja ein Übersprechen, probier doch mal kleinere Pullup Widerstände. Peter
Datum:
Asche auf mein Haupt, ich ziehe alle vorherigen Postings zurück und behaupte das Gegenteil.... Der Conrad Drehgeber scheint sehr wenig zu Prellen, ansonsten hätte ich wohl doppelte Zählungen sehen müssen. Komischerweise habe ich nur fehlende Pulse beobachtet... > Gibs doch zu, Du hast es garnicht erst probiert. Doch und das ist genau das Problem, einfach mal eben in der Hardware geändert... läuft und gut ist. Solche Dinge sollte man u.U. doch besser erst am PC simulieren....
Datum:
"Der Conrad Drehgeber scheint sehr wenig zu Prellen, ansonsten hätte ich wohl doppelte Zählungen sehen müssen. Komischerweise habe ich nur fehlende Pulse beobachtet..." Ob der Geber prellt, kann man mit meinem Code nicht feststellen, da er ja entprellt. Fehlende Pulse deuten auf eine zu langsame Abtastung hin. Eventuell sind ja andere Interrupts zu lange beschäftigt. Peter
Datum:
@Peter Ich plane auch gerade mal diese Drehgeber zu verbauen. Ist bei deiner Routine die Benutzung externer RC-Glieder ueberfluessig oder hilfreich (bei manueller Geber-Betaetigung) ? Koente mir moeglicherweise ne Menge Bauteile und Platinenflaeche sparen.
Datum:
Also die Drehgeber, die ich programmiert habe, liefen beim MSP430 ohne Tiefpass, aber beim ARM9 mussten Tiefpässe genommen werden (und es wurden freiliegende Schmitt-Trigger verwendet); das hängt vom Prozessor und Drehgeber ab.
Datum:
@The Daz die Routine ist entprellend, Du brauchst also keine extra Tiefpässe. Peter
Datum:
Hallo zusammen,
wir stellen alle Arten von Drehgebern her (auch die vom Conrad).
Das Problem mit der Entprellung ist vor allem dann ein echtes wenn man
1/2 Schritt vor und dann wieder zurück dreht. Für einen echten Schritt
müssen 2 (4) Zustandswechsel (gepollt oder per IRQ) ausgewertet werden.
Dann klappt's auch.
Dazu ein bissl Source Code:
void lesen()
{
const signed int table[16] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
// 16 erlaubte Bit-codes
old=old<<2; // die alten Daten 2 nach links schieben
if (input(PIN_B4)) // Spur /A abfragen (A0)//B4
bit_set(new,0);
else
bit_clear(new,0);
if (input(PIN_B5)) // Spur /B abfragen (A2)//B5
bit_set(new,1);
else
bit_clear(new,1);
old |=(new & 0x3); // alte und neue bits verodern
angle_1 += table [(old & 0xf)]; // aktion aus dem Feld auswählen
}
Dann etweder durch 2 oder durch 4 teilen:
void teiler_4()
{
if (angle_1>7) // unterlauf?
{
angle++;
if (angle > 99) angle = 0; // Überlauf abfangen
angle_1=4;
}
if (angle_1<1)
{
angle--;
if (angle > 250) angle = 99; // Unterlauf abfangen
angle_1=4;
}
}
/****************************************************************/
void teiler_2()
{
if (angle_1>5) // unterlauf?
{
angle++;
if (angle > 99) angle = 0; // Überlauf abfangen
angle_1=4;
}
if (angle_1<3)
{
angle--;
if (angle > 250) angle = 99; // Unterlauf abfangen
angle_1=4;
}
}
Alle anderen Methoden funktionieren eigentlich nicht wirklich.
Zur Umwandlung von Qudratursignalen in Impuls-Richtungssignale gibt es
ICs oder GALs. Viel Erfolg!
www.ebe-gmbh.de
Datum:
Wie schnell sollte man so ein Drehgeber einlesen wenn man ihn für die Bedienung eines Gerätes verwenden will? Ich habe die vom Conrad. Ich meine die Funktion lesen() ==> die muss man ja Zeitgesteurert ausführen oder? mfg mathias
Datum:
Für Drehgeber zur Geräte-Bedienung (z.B. der von Conrad) welche in den Stellungen AB=00, AB=11 einrasten funktioniert auch dieser Code http://www.mikrocontroller.net/forum/read-4-250095.html#new einwandfrei - auch beim Zurückdrehen aus halben Stellungen. Er zählt aber - was normalerweise auch so gewünscht ist - nur die Raststellungen. Die Pollgeschwindigkeit hängt von der Applikation ab. Wenn man viele Feineinstellungen braucht (+/- ein paar Stellungen) reicht z.B. 500 mal pro Sek. pollen aus. Muss viel gekurbelt werden (d.h. grosse Schritte), muss man schneller samplen da sonst je schneller man dreht weniger Pulse gezählt werden. Wer sicher gehen will und sich das leisten kann nimmt Interrupts.
Datum:
>Wer sicher gehen will und sich das leisten kann nimmt Interrupts.
Eben nicht!
Datum:
Interrupts sind am besten, wenn die CPU hauptsächlich anderes machen soll, aber zum Entprellen per Software ist Polling etwas besser. In der Regel ist der Unterschied aber nur marginal; es ist also hauptsächlich Geschmackssache.
Datum:
Hallo ich benutze am Atmel 8515 die beiden Interrupt-Eingänge: ExtInt0: push Temp1 ; save Temp1 in Temp1,SREG ; save flag register push Temp1 in Temp1,MCUCR ; Int0 _/~ or ~\_ ? sbrc Temp1,0 ; skip next line if ~\_ rjmp UpA ; was _/~ so jump to UpA ori Temp1,$01 ; MCUCR-bit0 = 1 out MCUCR,Temp1 ; Int0 next change will be _/~ sbic PinD,3 ; skip next line if channel B=0 rjmp DecRot ; if B=1 and A=~\_ -> decrement rjmp IncRot ; if B=0 and A=~\_ -> increment UpA: andi Temp1,$FE ; MCUCR-bit0 = 0 out MCUCR,Temp1 ; Int0 next change will be ~\_ sbic PinD,3 ; skip next line if channel B=0 rjmp IncRot ; if B=1 and A=_/~ -> increment rjmp DecRot ; if B=0 and A=_/~ -> decrement ExtInt1: push Temp1 ; save Temp1 in Temp1,SREG ; save flag register push Temp1 in Temp1,MCUCR ; Int1 _/~ or ~\_ ? sbrc Temp1,2 ; skip next line when ~\_ rjmp UpB ; was _/~ so jump to UpB ori Temp1,$04 ; MCUCR-bit2 = 1 out MCUCR,Temp1 ; Int1 next change will be _/~ sbic PinD,2 ; skip next line if channel A=0 rjmp IncRot ; if A=1 and B=~\_ -> increment rjmp DecRot ; if A=0 and B=~\_ -> decrement UpB: andi Temp1,$FB ; MCUCR-bit2 = 0 out MCUCR,Temp1 ; Int1 next change will be ~\_ sbic PinD,2 ; skip next line if channel A=0 rjmp DecRot ; if A=1 and B=_/~ -> decrement rjmp IncRot ; if A=0 and B=_/~ -> increment IncRot: mov Temp1,RotVal ; max limit = +127 reached ? cpi Temp1,$7F ; breq Exit ; yes, so don't increment inc RotVal ; no, increment rjmp Exit ; DecRot: mov Temp1,RotVal ; min limit = -128 reached ? cpi Temp1,$80 ; breq Exit ; yes, so don't decrement dec RotVal ; no, decrement Exit: pop Temp1 ; restore Flag register out SREG,Temp1 ; pop Temp1 ; restore Temp1 reti das ganze muß natürlich noch gestartet werden Das Hauptprogramm fragt gelegentlich die Variable RotVal auf Werte ungleich Null ab Durch die schnelle Antwortzeit des Interrupt habe ich keine Problem mit Prellen, vermutlich zählt die Interruptroutine auch alle Preller vor und zurück mit. Ich benutze auch die Conrad-Drehgeber DDM427 von hopt-schuler.com ,der leider nur auf jeder zweiten Flanke rastet 73 Christoph
Datum:
Ja, bei dem Auswerten der Interrupts sollten natürlich auch die Preller komplett ausgewertet werden; ansonsten hat man ja wieder das Prellen drinn. Durch die Preller wird der Wert aber nur für ein paar Mikrosekunden geändert. Wenn das unerwünscht ist, kommt man um Polling nicht herum, braucht dafür aber mehr CPU-Zeit und kann schnelles Drehen des Drehgebers nicht mehr auswerten. Optimal wäre natürlich ein Drehgeber mit mehr als zwei Adern, beispielsweise mit 8-Bit-Gray-Code-Ausgabe (256 Schritte/Vollkreis) und einem Inkrementieren/Dekrementieren alle N>2 Schritte, denn dann werden alle Preller automatisch exakt eleminiert und man braucht weder Interrupts noch Polling. Nur bei mehr als 360 Grad bräuchte man einen Timer-IRQ um die Nulldurchgänge zu zählen. Der Nachteil ist natürlich die teurere Hardware.
Datum:
Ähm... Eine Interrupt Auswertung sollte sich eigentlich grundlegend von der Polling Implementierung unterscheiden. Ich halte es für risikoreich darauf zu hoffen, dass der Interrupt schon alle Preller mitbekommt... Z.B. so (noch nicht getestet mit Drehgeber): a) wir reagieren auf die erste Änderung mit b) b) wir stellen uns blind für die erwartete Prellzeit c) nach deren Ablauf lesen wir den derzeitigen Zustand und entscheiden was zu tun ist d) wir warten auf die nächste Änderung (Prellzeit für DDM427 z.B. 3ms nach Datasheet)
Datum:
Das ist aber empfindlich auf Preller. Ich mache es beim Polling so, dass der aktuelle Wert derjenige ist, der zuletzt 30x in Folge (konstant) eingelesen wurde.
Datum:
Hallo Ich habe auch so einen Drehgeber mit 8Bit-Absolutcodierung von Bourns. Leider gibt es nicht nur DEN Graycode, sondern viele verschiedene. Den von Bourns kann man soweit ich sehe nur mit einer Tabelle in Dualzahlen umcodieren. Es gibt eine speziellen Graycode beliebiger Breite, der systematisch mit EXOR-Gattern hin- und zurück codiert werden kann ( wenn man mal von der Laufzeit in den hintereinandergeschalteten Gattern absieht, die den Vorteil des Gray-Codes zunichte macht, dass sich nur ein Bit pro Stufe ändert - die Glitches müssen wieder berücksichtigt werden) 73 Christoph
Datum:
Ja, man kann den Gray-Code natürlich auch genau anders rum verwenden, also z. B. in der ersten Stufe so kodieren: 0 -> 0 1 -> 0xff 2 -> 0xfe ... ohne die grundsätzlichen Eigenschaften zu ändern, aber die Variante mit den Gattern ist das zu 99,9 % verwendete auch in den Lehrbüchern. Die Glitches kann man mit einem Mikrocontroller vermeiden. Man kann dafür auch den Parallelport am PC nehmen.
Datum:
@Christoph "Leider gibt es nicht nur DEN Graycode" Kannst Du mir denn einen anderen zeigen ? Ich habe noch nirgends einen anderen Gray-Code gefunden. Die Bedingung ist ja, daß sich nur ein Bit ändern darf und das geht eben nur mit der bekannten Bildungsregel, jedes nächste Bit spiegelt alle darunter liegende Bits (EXOR). Und der Gray-Code muß natürlich vollständig sein, d.h. 256 Werte bei 8 Bit. Peter
Datum:
http://www.bourns.com/pdfs/ace.pdf das ist ein absoluter Drehgeber mit total wirrem Graycode, auch Bourns empfiehlt eine Tabelle zu verwenden
Datum:
Naja, da hat man einiges Abzutippen. Ungewöhnlich ist ja schon die Bezeichnung p1..p8 bei den Adern, denn normalerweise wird statt p1 stattdessen p0 (etspr. für n*2^0) verwendet. Aber man findet ja schon im Datenblatt vom Conrad einen Algorithmus, der nur eine Sorte Flanken auswertet und entsprechend viele Preller gibt.
Datum:
Abtippen bei PDF kann man ja sparen, besser kopieren und in openoffice-calc einlesen und umformen aber der Graycode ist hier auch unvollständig, 128 Stufen mit 8 Bit ist eines zuviel, scheint aber kein Korrekturbit zu sein, das wenigstens nützlich wäre So einen Schalter hat mir mal ein Vertreter auf einer Spoerle- Regionalausstellung geschenkt, ich habe dann irgendwann an ein Eprom angeschlossen, um ihn als Kanalwähler für eine PLL zu benutzen, da spielen Glitches keine Rolle.
Datum:
Tatsächlich, 8 Adern für nur 127 Positionen; das ist ja richtig pervers! Dabei ist der übliche Gray-Code ganz einfach: http://www.peg.si/electro/angle.html
Datum:
ja genau das meinte ich mit den hintereinadergeschalteten EXORs, das ist wie beim ripple-counter, die Bits ändern sich alle nacheinander um je eine Gatterlaufzeit verzögert, also genau was man mit dem Graycode vermeiden wollte, glitches von einigen Nanosekunden
Datum:
Ja, stimmt; eigentlich muss man dafür einen Mikrocontroller-Port nehmen und per Software dekodieren, also mittels x ^= (x >> 4); x ^= (x >> 2); x ^= (x >> 1); Weil unter dem Link nur eine LED-Anzeige ist, sind die Glitcher aber egal, weil nicht sichtbar.
Datum:
Hallo Peter!
Damit ich vom Conrad-Drehgeber nur bei jeder vollen Rasterstellung den
Wert aktualisiere, habe ich deinen Code ein bischen erweitert!
_______________________
// 3. Drehimpulsgeber auswerten
static int DIG_enc_last = 0x01;
char DIG_i = 0;
if( PHASE_A ) { DIG_i = 1; }
if( PHASE_B ) { DIG_i ^= 3; } // convert gray to binary
DIG_i -= DIG_enc_last; // difference new - last
if( DIG_i & 1 ) // bit 0 = value (1)
{
DIG_enc_last += DIG_i; // store new as next last
DIG_enc_delta += (DIG_i & 2) - 1; //Halbschrittzähler
if ((DIG_enc_delta - DIG_enc_delta2) > 1) { DIG_value++;
DIG_enc_delta2 = 0; DIG_enc_delta = 0; }
if ((DIG_enc_delta2 - DIG_enc_delta) > 1) { DIG_value--;
DIG_enc_delta2 = 0; DIG_enc_delta = 0; }
}
_______________________
Im Prinzip wird der Zähler aus deinem Code mit einem 2. Zählerwert
verglichen (Startwert von DIG_enc_delta2 = 1). Weicht der
Halbschrittzähler mehr als 1 ab, so wird der aktelle Vollschritt
übernommen (DIG_value) und beide delta-Zähler wieder zurückgesetzt.
Der Code funktioniert, bin aber für Verbesserungsvorschläge -wie immer-
dankbar! (z.B. Code minimieren..)
Gruß,
Techniker
Datum:
Hallo!
Hab gerade festgestellt, dass ich oben einen alten Code eingefügt
hatte! ;)
Hier der richtige:
_____________________
// 3. Drehimpulsgeber auswerten
static signed int DIG_enc_last = 0x01;
static signed char DIG_enc_delta = 0, DIG_enc_delta2 = 1;
char DIG_i = 0;
if( PHASE_A ) { DIG_i = 1; }
if( PHASE_B ) { DIG_i ^= 3; } // convert gray to binary
DIG_i -= DIG_enc_last; // difference new - last
if( DIG_i & 1 ) // bit 0 = value (1)
{
DIG_enc_last += DIG_i; // store new as next last
DIG_enc_delta += (DIG_i & 2) - 1; //Halbschrittzähler
if ((DIG_enc_delta - DIG_enc_delta2) > 1) { DIG_value++;
DIG_enc_delta -= 2; DIG_enc_delta2 = DIG_enc_delta; }
if ((DIG_enc_delta2 - DIG_enc_delta) > 1) { DIG_value--;
DIG_enc_delta += 2; DIG_enc_delta2 = DIG_enc_delta; }
}
_____________________
Datum:
n' bisschen einfacher (und leichter zu verstehen...) http://www.mikrocontroller.net/forum/read-4-250095.html#new
Datum:
@SuperUser: Den hatte ich schnomal probiert, hatte aber nicht funktioniert... Nun habe ich es nochmal ausprobiert und er funktioniert auf anhieb einwandfrei. :) Keine Ahnung, was damals schiefgelaufen ist. Gebe mich damit geschlagen... ;) (muß mir jetzt mal den Code vom Christian genau vornehmen, weil ich noch nicht ganz über den Funktionsablauf dahintergekommen bin..) Gruß, Techniker
Datum:
Kann mir jemand sagen, wie ich einen Drehgeber mit der C-Control von Conrad in Basic auslesen kann. Die Idee von peter dannegger (oberster Beitrag dieser Seite) klingt für mich eigentlich logisch, nur kann ich mit C nichts anfangen. Kann das Jemand für mich in Worte oder Flussdiagramm übersetzen, damit ich es verstehe und dann in Basic++ programmieren kann? MfG Philipp
Datum:
Hi! Ich probiere gerade den 2. Code von Peter Dannegger. Drehgeber ist ein Poti-ähnliches Ding von Alps aus einer alten Maus. Die Erkennung funktioniert soweit, allerdings muss man sehr langsam drehen. Der Drehgeber ist aber auch sehr fein und ohne Rasterung. Wie kann ich den Code ändern, dass nur z.B. alle 10 oder alle 100 Impulse ausgewertet wird? Danke! Kersten
Datum:
Jetzt dachte ich in meinem jugendlichen Leichtsinn, hier in dem Forum etwas über: "wie lese ich einen Absolutwertgeber aus" zu erfahren. Das es mit Clock, und Data und n Bits geht, ist klar, ... nur suche in nach einem Sourcecode.... Wer ne Idee hat, melden. Danke
Datum:
@Thomas "Jetzt dachte ich in meinem jugendlichen Leichtsinn ..." ... es gibt weltweit nur einen einzigen Absolutwertgeber. Nein, es gibt natürlich viele verschiedene. Und keiner kann hellsehen, welchen Du gerade meinst. Du mußt also schon nach Deinem bestimmten Typ suchen bzw. ein Blick ins Datenblatt könnte auch nicht schaden. Manchmal enthalten Datenblätter sogar Beispielcode. Peter P.S.: In der sozialistischen Staatengemeinschaft gab es von einigen Geräten wirklich nur einen einzigen Typ, aber das ist doch schon über 15 Jahre her.
Datum:
Hallo peter dannegger, Es mag sein, dass in der Planwirtschaft, so was möglich war.... Scherz beiseite, die Drehgeber mit Synchron Seriellem Interface oder kurz SSI. haben eine relativ klare Vorschrift, was die Datenblätter angeht ;-) die habe ich schon durch, sei es von dem Maxe Stegmann, oder von T&R um hier nur 2 stellvertretend zu nennen, da ist kein Beispielcode daargestellt. Den C-Quelltext könntest Du , wenn Du gewillt bist ihn mir zu schreiben, auch variabel halten, (12 Bit... 31 Bit) Denke aber ich kriege das selber hin, dachte ich geh nur den Weg des kleinsten Wiederstandes, (Elektrokermentalität eben) Also, lass es gut sein, lg, Tommy
Datum:
"Also, lass es gut sein" Wird mir wohl nichts anderes übrig bleiben, wenn Du keine Lust hast, eine genaue Typenbezeichnung und einen Link aufs Datenblatt zu geben. Als Elektroniker sollte man eigentlich in der Lage sein, seine Fragen präzise zu stellen. Keiner kann in Deinen Kopf schauen. Es ist ja Dein Bier, wenn Du kein Interesse an Hilfe hast. Peter P.S.: Was ist ein "Elektroker" ? Ein Elektroniker kennt jedenfalls keine "Wiederstände".
Datum:
Es handelt sich um einen Siemens Geber :6FX2001-5FS12 oder um ein optisches Absolutwertmesssystem, der Firma Leuze electronic, welches sich BPS37 nennt. Hier ist die Anzahl der auszutaktenden Bits, sehr variabel, kann frei konfiguriert werden (ab 12 Bit, bis 31 Bits, je nach Auflösung). Die Taktrate kann zwischen 90kHz und 1 MHz liegen. Die Totzeit nach dem LSB (least signifcant bit = letztes oder niederwertigstes, auszutaktendede Bit) Und Du hast recht, eine Elektroniker kennt keine Wiederstände, nur Widerstände. (Wuste nicht, dass wir hier ein Genie in Sachen deutsche orthographie haben - danke für die Belehrung, hab wohl wirklich 1 Bier zu viel gehabt). Aber ich denke Du kannst mir nicht helfen, nicht weil das ein Ding der Unmöglichkeit wäre, sondern, weil Du nicht willst, oder nict in der Lage bist. (Sorry für meine offenen Worte) Ich habe mir eien Ansatz zusammengereimt, wie ich den Geber austakte: Port 1.2 udn Port 1.3 aös Daten udn Taktleitungen (Optokoppler und RS485-Transceiver nachgeschaltet) Akku löschen, Clockbit setzen, Timer freigeben, nach abgelaufener Zeit Portpin für die Daten abfragen und in Ziel schieben, Zähler um 1 dekrementieren, wenn Zähler 0, dann die Zahl von Gray in Binaer wandeln, danach in Hexzahl wandeln, und via UART an PC senden. Also Danke nochmals. (Und entschuldige, über eventuelle Rechtschreibfehler die Dir im AUge wehtun ;-)
Datum:
"Aber ich denke Du kannst mir nicht helfen, nicht weil das ein Ding der Unmöglichkeit wäre, sondern, weil Du nicht willst, oder nict in der Lage bist. (Sorry für meine offenen Worte)" Da bist Du völlig auf dem Holzweg. Das einzige Hindernis bist Du selber, der einen blöde anmacht, wenn man ihm versucht mehr Informationen aus der Nase zu ziehen. Google findet jedenfalls einen Treffer, ist zwar 8051-Code, aber als Anregung bestimmt gut zu gebrauchen. Der Autor gibt nämlich den Typ an, weil er nicht denkt, daß es nur einen Typ gibt und jeder gleich Bescheid wissen muß. In der Regel läßt man ungenaue Fragen einfach links liegen und ich werde es das nächste mal besser auch so machen. Peter
Datum:
Danke für die Hilfe, es läuft. werde morgen (jetzt ist es eh zu spät, mal nen Absolutgeber mit 24 Bit anschliesen, und wenn es läuft, dann nur noch die Fehlerauswertung) warst ne echte Hilfe, also nochmals vielen Dank.... Thomas
Datum:
@Peter: Ich habe ein komisches Problem: Wenn ich meinen Zählerstand verändere mache ich das mit
rot_pos += tmp; |
Dabei zählt er zwei weiter. Soweit so gut, hatten wir ja oben schon. Nach deinem Lösungsvorschlag müsste das so aussehen:
rot_pos += tmp>>1; |
Problem: Der Compiler übersetzt das (nachvollziehbarerweise) so:
rot_pos += tmp>>1;
c8: 86 95 lsr r24
ca: 90 91 6a 00 lds r25, 0x006A
ce: 89 0f add r24, r25
d0: 80 93 6a 00 sts 0x006A, r24
|
Der Knackpunkt ist aber, dass tmp eine char (signed!) Variable ist. Das Vorzeichen-bit geht somit flöten. Und dementsprechend gibt das Drehen in die Eine Richtung Stuss, und in die andere Richtung garnichts. Was hast du dir dabei gedacht? Oder habe ich einen Denkfehler? Komischerweise übersetzt er bei signed aber
rot_pos += tmp/2; |
exakt genauso. Hilfe! :-)
Datum:
Hm, kaum eine Minute geschrieben, schon habe ich die Lösung: char ist komischerweise (Wahrscheinlich mit den vielen Parametern hinter dem gcc.exe) ein unsigned char. Blöderweise widern mich die Parameter an, weil das so viele sind. Deswegen beschäftige ich mich damit nur ungern ;)
Datum:
PS: Jetzt übersetzt er es so
rot_pos += tmp>>1;
c8: 85 95 asr r24
ca: 90 91 6a 00 lds r25, 0x006A
ce: 89 0f add r24, r25
d0: 80 93 6a 00 sts 0x006A, r24 |
Also alles Klar!
Datum:
Hm, zu früh gefreut. Verhält sich genau gleich der Mikrocontroller. @Peter oder jemand anders :-): Kannst du mal kurz über meinen Code sehen? Ich hänge dir mal die relevanten Dateien an.
Datum:
Sorry, habe mir deinen Code nicht angesehen, aber wenn dich das doppelt zählen stört kannst du auch mal dort nachsehen: http://www.mikrocontroller.net/forum/read-4-250095.html#new
Datum:
@simon, nein, so kann es nicht gehen. Wenn Du das Bit 0 nicht auswertest, darf es auch nicht gelöscht werden, sonst funktioniert das Entprellen nicht. Du mußt also die Auslesefunktion so ändern:
signed char rot_getdelta(void) { signed char tmp; cli(); tmp = rot_delta; rot_delta = tmp & 1; // bit 0 needed for debounce ! sei(); return tmp >> 1; // pulse / 2 } |
Peter
Datum:
Hallo Simon, Schweigen im Walde ? Wäre schon interessant, ob es nun funktioniert. Theoretisch müßte es. Ich habe leider keinen solchen Drehgeber, um es zu testen. Peter
Datum:
Hi Peter, ich hab direkt den Code von SuperUser genommen. Schlimm dass ich dein Codeschnipsel nicht mehr ausprobieren konnte? Das von SuperUser klappt jedenfalls mit meinem Encoder von Pollin sehr gut.
Datum:
Sorry fürs ausbuddeln. @Peter Wollte nur mal melden, dass die Anpassung auf den Drehgeber der nur alle 2 Schritte einrastet (Pollin-teil) funktioniert. gruß
Datum:
Hallo P E T E R D A N N E G G E R ? ich benutze: - deinen Codeschnipsel mit der Differenzmethode aus "encoder.c" - optischen Drehencoder Grayhill-62A (1 Flanke pro Rastung) - Auswertung durch Polling per Timer-Interrupt auf MSP430 Problem: Beim Drehen funktioniert die Auswertung tadellos. Allerdings macht mir der Anfangszustand der Zählvariable "enc_delta" zu schaffen. Je nach Position des Drehencoders wird "enc_delta" um 1 inkrementiert / dekrementiert wenn die Funktion das erste mal gestartet wird und zwar bevor ich überhaupt gedreht habe. Wenn ich mir den Code anschaue, sehe ich, dass nach der Differenzbildung "i-=enc_last" eine Zahl zwischen 0 und 3 entsteht und diese im Schritt "if (i & 1)" auf jeden Fall ausgewertet wird (i=1, i=3), also auch wenn die Funktion das erste mal gestartet wird und "enc_last=1" ist. Wie löse ich dieses Problem? Eventuell A und B schon vorher einlesen und dann "enc_last" auf diesen Wert und nicht auf 1 setzen? Oder gibt es einen anderen Weg? Bitte, bitte helft mir! hg
Datum:
Autsch Peter Danegger scheint heir einem Denkfehler auferlegen zu sein. wenn ich nun einen Sin/cos-geber habe, wie werde ich damit glücklich. Ich kann zwar einen Quadraturencoderchip verwenden um damit klare rechecksignale auzubereiten und diese damit dem µcontroller zur Verfügung stellen, aber das ist nur die halbe Miete. Wenn ich schon ne fast unendlich hohe Auflösung habe sollte ich die doch auch verwenden und mich nicht mit schlappen 1024 oder 2048-Inkrementen zufrieden geben, oder was meint Ihr dazu ? Natürlichist die Auflösung beschrenkt, durch die Reckenleistung des µC´s. Also Fakt ist, dass hier nicht ein Billigheimergeber eingesetzt werden soll sondern ein hochwertiger, der dann bei einem Motor mit hoher Achslast nicht zu Microtorsion neigt udn damit bei eienm sagen wir mal 500 Inc. Geber zum Nachregeln und aufschwingen neigt. Ja ich weis... jeder Regler bedarf einer Regelabweichung... aber sollte diese nicht so klein wie möglich sein ? Also. P.Danekker, wie ist die Erfahrung mit Präzisionsgebern. Einsatzgebiet. Switched Reluktanzmotor, Achlast nach Getriebe 240/12/2 Umsetzung, udn einem Supergenialen Sin/Cos-Geber, wie er auf dem Markt erhältlich ist auf die Lastabgewandte Seite (also nicht auf der Getriebeseite und nicht nach dem Getriebe) Den Assemblercode für den Geber (Absolutwertgeber) habe ich, die Grobauswertung kann ich a la den Beispielen hier super gestalten, nur die 65535-wertige Feinauflösung bekomme ich nicht gebacken. Wenn jemand was weis, bitte kurz Datenblatt oder Sourcecode anhängen .. nun gut für das erste mal, eine Super Newsgroup (was für ein grässliches neudeutsches Wort) und richtig schöne Beiträge hier.
Datum:
the_absolute_trough_blicker ;-) wrote: > Autsch Peter Danegger scheint heir einem Denkfehler auferlegen zu sein. > Verfügung stellen, aber das ist nur die halbe Miete. Wenn ich schon ne > fast unendlich hohe Auflösung habe sollte ich die doch auch verwenden > und mich nicht mit schlappen 1024 oder 2048-Inkrementen zufrieden geben, > oder was meint Ihr dazu ? Natürlichist die Auflösung beschrenkt, durch > die Reckenleistung des µC´s. Der Denkfehler liegt eindeutig bei Dir Die Rechenleistung ist völlig schnurz. Analogsignale kann man nicht unendlich gut auflösen. Außerdem machen Dir Nichlineritäten, Störspannungen, Vibrationen, Rauschen usw. einen Strich durch die Rechnung. Es stimmt schon, es gibt auch Drehgeber mit Analogausgang. Allerdings macht man dann möglichst nahe eine Umwandlung in Gray-Code, weil sich das viel leichter weiterleiten und verarbeiten läßt. Wir haben sie auf eine Auflösung von 16 Teilschritten gesetzt, weil es darüber instabil wird. Peter
Datum:
Hallo Peter Danegger, meine etwas scharfe Provokation hat genutzt. Ich habe Deine vollste Aufmerksamkeit erregt. Ja, ich gebe Dir vollkommen Recht, einen Positionsgeber auf mehr als 16 Bit aufzulösen ist für die meisten Anwendungen mumpitz ;-) aber die Feinauflösung (Sin/Cos-Geber welche mit Arg-Tan vermostet werden) ist dennoch von Berechtigung. So ist es in der Lageregelung von Bedeutung, dass heir eine möglich hohe Auflösung erreicht wird. In der Drehzahlregelung ist das eher von geringerer Bedeutung, und somit reichen bei der Regelung gar die Spuren A und B aus. Anwenungsfall Aufzug hast Du vollkommen Recht Anwendungfall µ-Positionierung bin ich im Recht. Aber um hier zu schlichten wird denke ich kein Schlichter oder Anwalt benötigt ;-) Deine Forumsbeiträge sind eien Bereicherung. Absolutwertgeber mit Serial-Synchon-Interface oder gar BISS werden von mir eher wenniger eingesetzt, da die vonDir erwähnten EMV-Probleme bei dieser differentiellen Schnittstelle ein großes Problem darstellen. Wir verwenden eher die für Feldbus aufbereiten Systeme (hier ist es egal ob Lichtlaufzeit (linear) Barcodepositioniersysteme von Leuze oder Drehgeber von Stegmann für die rotatorische Auswertung zum Einsatz kommen. Gray-Code o.k. hat den Vorteil, dass der Wechsel von 2 Zuständen immer nur 1 Bitsprung bewirkt, aber wenn das diff-Signal madig ist (zu viele Störungen) dann kann es zu Bitdrehern kommen und so der Positionsistwert frei nach dem Motto "Cat down the River" oder schwäbisch "d´Katz da Bach na" bedeutet. Hier habe ich inder Vergangenheit immer (für mich aufwendig erscheinende) Plausibilitätsprüfungen durchführen müssen. Das hat dann in Abhängigkeit von Geschwindigkeit zu geschehen. grüßle und ich hab es total verschwitzt. ein gutes Neues Jahr. (wer Rechtschreibfehler findet darf sie behalten)
Datum:
@nur sich selbst dafür haltenden "the_absolute_trough_blicker" Also wir benutzen gekaufte Lineargeber mit Analogausgang und dazu gehörige Wandler in Gray-Code, womit wir dann Piezomotoren <=50µm positionieren. Die Graycodeauswertung erfolgt mit dem obigen Programm einwandfrei. Die Analogleitungen sind höllisch empfindlich und so kurz wie möglich zu halten. Mit 16 Stufen meinte ich, sie interpolieren noch weitere 4 Bits je Viertelwelle. Aber 16 Bits halte ich für völlig unmöglich, da ist ja das Husten von Flöhen viel leichter zu zählen. Mit Aufzügen habe ich absolut nichts zu tun. Ich hab nur mal gesagt, daß die Aufzugsfirma in unserem Gebäude unfähig ist, die Ruftasten zu entprellen (Es gehen immer beide Lampen an, wenn man über den Teppich geht). Ich verlasse auch immer schnell die Tür, wenn sie sich bewegt, denn ob die Lichtschranke richtig entstört ist, weiß man dann ja auch nicht. Peter
Datum:
@ Peter ich kenn mich nicht mehr so ultragut mit den Aufzugssteuerungen aus, aber sei versichert, dass der Sicherheitskreis in europäischen Aufzügen funktioniert. Ob es eine KOllmorgen oder eine LISA oder eine Schindlersteuerung oder eine von Liftequip... egal sie tun. Wenn man(n) und frau bedenkt dass die LISA noch in Pascal programmiert wurde (igit) entweder Assembler oder ne ordentzliche Hochsprache ich mochte Pascal noch nie (ist denek ich was persönliches) (Ebensowennig Cobol) und schon weitaus mehr als 15 Jahre auf dem Buckel hat ist sie für den Anwender "easy 2 use". die Feinauflösung bei den Sin/Cos-Gebern finde ich immer noch brillant, aber da scheiden sich unsere Geister ein wennig. Für Analoge "Geschichten" in der Nähe von Servomotoren oder anderen Motoren, welche mit Umrichtern gefahren werden ist es höchst Brisant, wie Du schon geschrieben hast. Da ist nicht die kleinen Störspitzen der Verursacher sondern das irre hohe dU/dt (mehrere KV/µs werden hier bei sogenannten IGBT´s geschaltet - auch wenn der Zwischenkreis bei den Reglern sprich FU´s lediglich schlappe 680V- hat. ooops das ist falsch, wenn der Motor in den Generatorischen Zustand geht und Energie zurückgibt ist es ein wennig mehr). Also hier helfen nur Motordrosselön um die Oberwellen zu fixen und dann noch um das Geberkabel Wunderkerne. Die sind im allgemeinen als Ferritkerne erhältlich und lassen sich auf das Kabel aufklipsen. Ich bin immer noch verwundert, wie die wirken. wenn mann bedenkt, dass solche Ferrite lediglich aus gesintertem gekraktem und wieder gepresstem Material besteht. Also ich wünsch noch was, und freu mich auf weitere rege Beiträge. liebe Grüße t_a_t_b-;-)
Datum:
So, habe mir beide Varianten mal angesehen. Variante 1 habe ich um einen Pulscount mit Vorteiler erweitert. Die Abtastrate beträgt ~ 400 Hz und die Routine funktioniert einwandfrei. Durch die Vorteilung ist auch noch der genannte Fehler ausgemerzt. Variante 2 ist zwar schön kurz führt aber bei mir zu Fehlern. enc_delta sollte ja +/- 1 liefern, zeitweise bekomme ich allerdings auch andere Werte zurück z.B. 3/4 etc, so als ob sich der Nullpunkt verschiebt. Bin mir nicht sicher ob es mein Fehler ist oder ob der Algorithmus einen Fehler erzeugen kann. @ Peter, hast du ne Idee hierzu.
Datum:
Joe wrote: > enc_delta sollte ja +/- 1 liefern, zeitweise bekomme ich allerdings auch > andere Werte zurück z.B. 3/4 etc Nö, der Wert kann -128 ... +127 betragen, je nachdem, wieviel Pulse seit dem letzten Lesen gezählt wurden. Wichtig ist, daß das Lesen und Löschen atomar erfolgen muß. Was bedeutet denn Vorteilung ? Wenn Du die Pulse auf 2 Teiler gibst, sind sie doch nicht mehr um 90° phasenverschoben. 400Hz scheint mir etwas langsam. Peter
Datum:
Ja, 400 Hz ist zu langsam, habe nun die 2te Routine auch begriffen, hat ne Weile gedauert. Danke für den Hinweis.
Datum:
hallo ich habe ein kleines problem... ich habe einen ATmega8 mit dem pollin Encoder PANASONIC EVEQDBRL416B datenblatt: http://www.pollin.de/shop/downloads/D240313D.PDF er hat also in den rastungen entweder 00 oder 11 01 und 10 sind nur während der drehung dynamisch vorhanden habe nun mittlerweile verschiedene codes getestet einer funktioniert recht gut .. ABER er bleibt manchmal einfach hängen auch wenn er fast alleine läuft kann mir jemand dabei helfen ? das mit dem graycode ist gut , nur bn ich noch nicht SO in C bewandert das ich das komplett durchblick ... oder etwas genauer erklären ... vielen Dank grüße Dirk
Datum:
Dirk Frerichs
Teste mal das hier:
// ---- include Dateien ----
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
//
**************************************************************************************
// ---- function prototypes ----
void wait_until_key_pressed(void);
//
**************************************************************************************
// ---- constant definitions ----
#define Schalter_A PIND1 // Schalter A im Drehgeber
#define Schalter_B PIND0 // Schalter B im Drehgeber
#define Taster_P PIND2 // Taster im Drehgeber
#define Geber PIND // Drehgeber Port
#define Ausgabe PORTB // Ausgabe Port zum Testen
volatile unsigned char richtung = 0; // 0 ... 255
//
**************************************************************************************
ISR(TIMER0_OVF_vect)
{
static unsigned char alter_status = 0,step = 0;
unsigned char neuer_status;
neuer_status = Geber & (_BV(Schalter_A) | _BV(Schalter_B)); //
Änderung einlesen
if ((neuer_status ^ step)==(_BV(Schalter_A) | _BV(Schalter_B)))
{
if ((neuer_status ^ alter_status)==_BV(Schalter_A))
richtung +=1; // Es war eins nach rechts
else
richtung -=1; // Es war eins nach links
step = neuer_status;
}
alter_status = neuer_status;
}
Datum:
hi hab dank aber ich habe es mit der ursprünglichen routine hinbekommen es läuft auch sehr gut... da der regler aber entweder in 00 oder 11 rastet habe ich den delta-wert nochmal geteilt grüße werd es mal heute abend reinstellen
Datum:
Hallo!! Ich hätte eine Frage zur Routine und deren Anwendung: Ich möchte eine Wetterfahne (Windrichtung) mit einem Drehgeber auswerten. Ich habe hierfür die Routine von Peter Dannegger verwendet und durchaus gute Ergebnisse erzielt. Nun habe ich aber ein kleines Problem: die Messung soll längere Zeit unbeaufsichtigt betrieben werden, das heißt das Teil wird einmal zu Beginn der Messung genau nach Norden ausgerichtet. Der MC soll nun aus den erhalteten Pulsen über einen Umrechungsfaktor die Abweichung von Norden bestimmen. Also eine Pulsändereung nach rechts -> +3,6° usw. (Überlauf wird berücksichtigt) Ist das oben beschriebene Vorgehen für eine Langzeitmessung sinnvoll? Wenn ich nun einen Puls pro Woche oder Tag, keine Ahnung, verliere (der Encoder gibt 100Pulse/Um) wären das ja 3,6° Fehler!! Gibt es für solche speziellen Anwendungen eine besondere Art von Encodern? Oder brauche ich mir um den Verlust von Pulsen keine Gedanken machen? Vielen Dank und schöne Grüße Philipp
Datum:
@Phillip solange die Wetterfahne sich nicht im Zentrum eines Tornados befindet, dürfte die Windrichtung sich nicht so schnell ändern, daß Schritte verloren gehen. 50kHz Abtastrate und 100 Schritte bedeuten max 15000 Upm. Peter
Datum:
Super, so was habe ich gehofft!! UNd wenn es zu einem Tornado kommt, ist der Verlust von ein paar Schritten garantiert mein kleinstes Problem!! Danke und schöne Grüße Philipp
Datum:
Relative Drehgeber sind dafür nicht gut geeignet; dass aus irgend einem Grund (Schwingung, ruckartige Bewegung, mechanische/optische Probleme im Drehgeber) alle paar Tage/Wochen mal ein Schritt verloren geht kann man nicht ausschließen. Ein Encoder der einen Absolutwert ausgibt wäre sinnvoller. Alternativ dazu könnte man den Drehgeber regelmäßig automatisch kalibrieren, z.B. durch eine Lichtschranke oder einen Mikroschalter an einer bestimmten Position.
Datum:
Andreas Schwarz wrote: > Relative Drehgeber sind dafür nicht gut geeignet; dass aus irgend einem > Grund (Schwingung, ruckartige Bewegung, mechanische/optische Probleme im > Drehgeber) alle paar Tage/Wochen mal ein Schritt verloren geht kann man > nicht ausschließen. Nein, man kann es ausschließen ! Das ist ja gerade der Witz am Graycode, daß sich immer nur ein Bit ändern kann. Wenn also mal ein kurzer Störimpuls gezählt wird, ist er ja bei der nächsten Abtastung vorbei und wird wieder abgezogen. Es kann also nur temporär ein Fehler von +-1 Impuls auftreten, aber nie akkumulierend. Das trifft allerdings nur für entprellende Algorithmen wie dem obigen zu, die im Timerinterrupt abtasten. Algorithmen mit Flankeninterrupt können dagegen Pulse verlieren, wenn die Störungen zu schnell kommen. Und auch alle Algorithmen, die im Interrupt mehrmals den selben Pin einlesen, lassen sich durch Störungen leicht aus dem Tritt bringen. Peter
Datum:
Peter Dannegger wrote: > Andreas Schwarz wrote: >> Relative Drehgeber sind dafür nicht gut geeignet; dass aus irgend einem >> Grund (Schwingung, ruckartige Bewegung, mechanische/optische Probleme im >> Drehgeber) alle paar Tage/Wochen mal ein Schritt verloren geht kann man >> nicht ausschließen. > > Nein, man kann es ausschließen ! Du würdest also guten Gewissens ein Signal von einem relativen Drehgeber mit 4 Zuständen über mehrere Wochen hinweg aufintegrieren? Das ist sehr mutig.
Datum:
Andreas Schwarz wrote: > Du würdest also guten Gewissens ein Signal von einem relativen Drehgeber > mit 4 Zuständen über mehrere Wochen hinweg aufintegrieren? Das ist sehr > mutig. Daran ist überhaupt nichts mutig, wenn der Drehgeber mechanisch und elektrisch in Ordnung ist und die Software auch in Ordnng ist. Und ob 4 Sekunden, 4 Wochen oder 4 Jahre spielt überhaupt keine Rolle. Relative Drehgeber werden sehr häufig eingesetzt und ich habe noch nie gehört, daß sie schlechter als absolute Drehgeber sein sollen. Natürlich braucht man noch einen Referenzkontakt, um die Software nach einem Reset zu nullen. Peter
Datum:
Also bei sowas wäre ich sehr vorsichtig. Synchronisationsverluste jedweder Art können immer vorkommen. Man kan jedoch einen Kompromiss eingehen. Indem man für einen evtl. Referenzlauf an irgendeiner Stelle einen sozusagen Nullungskontakt einbaut (optisch, mechanich etc). Gibt diesem Rad (oder was auch immer es ist) einen Schwung um die eigene Achse. Spätestens am Nullungkontakt baut er eine Referenzposition auf. Zum einlernen dreht er das Rad bis es z.B. auf Norden zeigt, drückt ne Taste und speichert intern die Anzahl der Steps bis zur 0 Referenz. Es ist anzunehmen, daß dieser Kontakt aller Zeitperiode X dort mal vorbeikommt und sich referenziert. Anhand der Steps von Norden bis 0 Punkt weiss er wo er steht. Wenn die Elektronik mal ausfallen sollte oder ein kurzer Reset das System lahm legt, erkennt er, das noch keine Nullung durch den Kontakt stattgefunden hat und wartet zumindest, bis der Wind sein nötigstes getan hat. Sollte natürlich ein Erdbeben auftreten und die Erdplatten verschieben oder Nord und Südpol plötzlich umswappen, hat man halt Pech.
Datum:
Hallo!! Danke erstmal für die Lösungsvorschläge! @Dirk Dein Vorschlag kling ziemlich gut, nur verstehe ich den im Moment nicht so ganz. Ich stelle also meine Windfahne irgenwie auf. Wohin der Pfeil zeigt ist Wurscht? Unter der Fahne habe ich irgendwo einen Kontakt Um die Fahne zu refenzieren drücke ich am MC eine Taste um dem MC zu sagen, jetzt kommt der Refernezwert Nun drehe ich die Fahne bis auf Norden hin, lasse die Taste zb. los (oder drücke sie nochmals, je nach dem wie ichs programmiere) Die bisher gezählten Schritte vom Puls des 0-Pkt's bis zum Nordpol speichere ich im EEp. Liege ich bisher richtig?? Nur wie komme ich von diesem refenezwert auf meine Richtung? Das verstehe ich noch nicht ganz! Kannst Du mir das vielleicht ein wenig genauer erklären? Vielen Danke und schöne Grüße Philipp
Datum:
Philipp Putzer wrote: > Hallo!! > > Danke erstmal für die Lösungsvorschläge! > > > @Dirk > Dein Vorschlag kling ziemlich gut, nur verstehe ich den im Moment nicht > so ganz. > @Philipp OK. Du hast eine Wetterfahne oder nen Wetterhahn. Das ganze hängt an einer drehbaren Welle bzw. Stange. Unten an der Stange ist ein Drehimpulsgeber montiert. Sagen wir mal mit 100 Schritten und damit einer Auflösung von 3.6°. Nun gibt es mehrere Möglichkeiten: (Drehimpulsgeber mit eingebauter Referenzspur lassen wir mal weg) Ich erkläre es nur mal als Beispiel zum Verständniss. Du kannst es dann auch anders lösen. Du montierst auf die Welle, auf der auch der Drehgeber sitzt eine (z.B) Kunststoffscheibe oder Metallscheibe mit angemessenem Durchmesser. Bohrst in diese Scheibe ziemlich weit aussen 1 (!!!) kleines (!!!) Loch. Dann nimmst Du ne Gabellichtschranke und montierst Sie so, das Sie nen Impuls abgibt, wenn Sie am Loch vorbei kommt. Der Reaktionsbereich sollte ziemlich eng sein. Die Scheibe dreht sich natürlich mit der Welle. Soweit so gut. Du kannst diese einmalige Position natürlich auch anders detektieren. Beim Einlernen drehst Du die Fahne oder den Hahn (;-)) mind. ein mal von Hand um die eigene Achse. Die Software erkennt jetzt anhand des Impulses von der Lichtschranke einen Referenzpunkt, der hat aber noch garnichts mit der Himmelsrichtung zu tun. Du musst hier auch keine Taste drücken, da der Referenzpunkt durch das Drehen der Scheibe automatisch gefunden wurde. Die Software setzt den internen Zählwert auf null und zählt ab jetzt die Steps vom Drehgeber in beide Richtungen. Jetzt nimmst Du Deine Fahne oder Deinen Wetterhahn noch mal in die Hand und richtest Ihn nach Norden aus (nehme an mit Kompass) und drückst kurz eine Taste. Den Wert musst Du dann intern abspeichern. Jetzt weiss Dein µC, wieviele Schritte es vom 0 Punkt bis Norden sind. Aufgrund dieser Werte kann er alles andere berechnen. Du könntest Dir zum Beispiel noch 2 LEDs hinbauen. Die eine zeigt an, wenn das System nach dem Einschalten zum ersten mal den Referenzpunkt gefunden hat und die andere ob der NORD-Wert eingelernt wurde. Wenn beide LEDs an sind, arbeitet das System einwandfrei, es sei denn, Du hast beim einlernen Norden mit Süden verwechselt. Die Referenzierung findet dann immer wieder automatisch statt, weil anzunehmen ist, daß der Wind die Fahne oder den Hahn irgendwann mal um die eigene Achse bewegt. Die Software synchronisiert sich sozusagen immer neu, wenn Sie an dieser Lichtschranke (nur Beispiel) vorbeikommt. Und jetzt noch eine Möglichkeit, die alles obige unnötig macht. Schau mal auf die Website von www.austriamicrosystems.com AS5040 AS5043 AS5045 AS5140 So gehts auch.
Datum:
<Offtopic> Beim lesen bin ich auf ein anderes Problem gestoßen. Wie wird die Windrichtung an den Polen bestimmt? Am Nordpol herrscht immer Südwind? Am Südpol immer Nordwind? Von der puren Logik her stimmt das doch. </Offtopic>
Datum:
Werner B. wrote: > <Offtopic> > Beim lesen bin ich auf ein anderes Problem gestoßen. > > Wie wird die Windrichtung an den Polen bestimmt? > > Am Nordpol herrscht immer Südwind? > Am Südpol immer Nordwind? > Von der puren Logik her stimmt das doch. > </Offtopic> Da wo die Fahne oder der Hahn hinzeigt, kommt aus der Gegenrichtung der Wind. Ist ja nur eine Softwaredefinition wie man das dann auswertet. Dirk
Datum:
Super, werde das mal testen. Ich habe gesehen, dass mein Enecoder einen Z-Ausgang besitzt, könnte das so ein Refenzpunkt sein, der beretis im encoder drin eingebaut ist?? wenn ja, würde ich natürlich den nehmen grüße philipp
Datum:
Philipp Putzer wrote: > Super, werde das mal testen. > > Ich habe gesehen, dass mein Enecoder einen Z-Ausgang besitzt, könnte das > so ein Refenzpunkt sein, der beretis im encoder drin eingebaut ist?? > > wenn ja, würde ich natürlich den nehmen > > > > grüße > > philipp Z ist leider keine Referenzposition sondern nur eine UND Verknüpfung von Signal A & B Daher, wenn A=1 + B=1 so ist Z auch =1 Dirk
Datum:
Hi! Habe gerade den Encoder ausgemessen, dieser liefert am Z-Ausgang an EINER einzigen Position einen High-Pegel. Deshalb denke ich, der Z-Ausgang wird dann auch als refenzierungspunkt gedacht sein. werde das mal in absehbarer zeit testen! vielen dank für die Hilfe und schöne grüße philipp
Datum:
Als Nullimpuls oder Referenzimpuls wird ein einzelner Impuls je Umdrehung der Geberwelle bezeichnet. Er dient insbesondere zur exakten Feststellung einer Null- oder Referenzposition. Um den Nullimpuls drehrichtungsunabhängig exakt auswerten zu können, wird er als Standard mit dem High-Pegel der beiden Kanäle A und B verknüpft. Durch den Phasenversatz der Kanäle ist der Nullimpuls nur halb so lang wie ein Impuls A oder B. Die Auswerte-Elektronik muß für den Nullimpuls in der Lage sein, die doppelte Eingangsfrequenz zu verarbeiten. Für den Fall, daß dies nicht möglich ist, oder wenn aus anderen Gründen ein längerer Nullimpuls benötigt wird, kann er für viele Typen auch unverknüpft und mit nahezu beliebiger Länge geliefert werden. Quelle: http://www.wachendorff.de/Drehgeber/Signalverarbeitung.php
Datum:
Hallo, kann jemand das Beispiel von Hr. Dannegger mal in CCS Code darstellen. Ich kriege den Encoder einfach nicht abgefragt,bzw. den Code portiert... Danke
Datum:
sepp wrote:
> Was ist ein CCS Code?
Wüßte ich auch gern.
Muß jedenfalls etwas total anderes als C sein, wenn selbst 8 Zeilen
C-Code zuviel sind :-)
Peter
Datum:
Dirk Frerichs wrote: > glaube code composer studio Code Composer Studio ist eine Software und keine Programmiersprache. Für die ARM Controller TMS470 von TI aber hauptsächlich für alle DSP Familien TMS320-------- 24xx 28xx 5000 6000 etc.
Datum:
@ Peter Man kann genausogut einen Pin-Change-Interrupt nehmen, Hauptsache der Interrupt reagiert auf alle 4 Flanken. Hallo Peter Wie ist das gemeint? Der gleiche Code geht auch mit PinChange Interrupt? Natürlich auf beide Pins (A und B) oder. Zudem muss man aber auch auf alle Flanken reagieren also steigende und fallende oder?. danke
Datum:
Ja, geht auch mit Pin-Change Interrupt. Hatte es mit einem ATTiny26 gemacht und sicherheitshalber doch kleine Kondensatoren (10µF glaube ich) drangehängt. Ob jetzt beide Pins oder nur einer für die Kanäle auf Pinchange gesetzt werden müssen weis ich nicht mehr genau, schon lange her. Aber im Prinzip wird primär erst nur ein Pin auf Veränderung abgefragt, also müsste einer reichen. Bei Veränderung kommt dann die weitere Auswertung. Der Pinchange muss auf "toggle" gesetzt werden, also steigend UND fallend. Aber auf was Peter eigentlich hinaus wollte ist, das man sich mit seiner Art der Timer-Abfrage und Auswertung die Kondensatoren sparen kann da gewisses "flimmer" ausgefiltert wird. Hatte mir das für nen anderes Projekt in AVR-ASM umgesetzt und es geht wunderbar. Natürlich, je schneller der Timer je weniger bzw. keine Fehler gibt es. Der Timer sollte, denke ich, mind. 5 mal so hoch sein wie es Raststellungen je Umdrehung gibt um auch schnell drehen zu können. MfG Andi
Datum:
Hallo zusammen, ich bin noch recht neu hier, und versuche schon eine Weile den 2ten Code von Peter für die Einstellung der Uhrzeit zu verwenden. Jedoch ist mir leider noch immer nicht klar geworden wie ich den Drehgeber richtig auswerte. Im Moment gebe ich nur enc_delta auf einem LCD aus. Der Wert läuft auch wenn ich am Drehgeber Drehe von -128 bis +127. Ich bekomm es leider nicht hin das mir nur die Änderung seit dem letzten Interrupt angezeigt wird. Gruß Michael
Datum:
In ca. 2 Beiträgen oben steht die Lösung auf Dein Problem mit zusätzlicher Info: enc_delta bei der auswertung auf null setzen. Evtl. auch noch durch 2 teilen (besser um ein Bit verschieben).
Datum:
Ich habe aber auch eine Frage: Ein Komparator macht aus den durch Drehen entstehenden Wechselspannungsimpulsen eines Schrittmotors ein 5-V Rechtecksignal (Beitrag "bürstenloser motor als quadraturencoder, störungen beheben"). Leider ist aber der Normalzustand 11, daher gibt es beim Drehen immer erst ein low-Impuls auf einer der Leitungen, bevor dann schöner Gray-Code kommt. Ich benutze den Algorithmus von Peter in einem Pin-Change Interrupt, der auf beide Leitungen anspricht. Ich hatte gehofft, dass der Algorithmus den Anfangsimpuls ignoriert, bekomme aber keine entsprechendes Ergebnis (enc_delta chaotisch auf 2 oder 3). Schöner wäre es sowieso, wenn gleich der erste Impuls (ein (Halb-?)Schritt des Motors) ausgewertet werden könnte, aber ich sehe nicht, wie das mit P.D.s Logik vereinbar ist. Hier noch Codeausschnitte für einen tiny2313 @ 8MHz, 'Encoder' ist an PB1 u. PB0
// ENCODER #define PHASE_A (PINB & 1<<PB0) #define PHASE_B (PINB & 1<<PB1) volatile int8_t enc_delta; // -128 ... 127 |
// pin change interrupts GIMSK = 1<<PCIE; PCMSK = 1<<PCINT0 | 1<<PCINT1; sei(); |
ISR(PCINT_vect)
{
static int8_t enc_last = 0x01;
int8_t i = 0;
if( PHASE_A )
i = 1;
if( PHASE_B )
i ^= 3; // convert gray to binary
i -= enc_last; // difference new - last
if( i & 1 ){ // bit 0 = value (1)
enc_last += i; // store new as next last
enc_delta += (i & 2) - 1; // bit 1 = direction (+/-)
}
}
|
enc_delta lasse ich mir mit 1Hz ausgeben.
Datum:
Angehängte Dateien:Hallo und guten Morgen, gestern Abend brauchte ich eine Routine für einen Rotgeber und bin dann bei der Suche hier gelandet. Dann habe ich auch einiges hier heruntergeladen um den Rotgeber zum Leben zu erwecken. Lief alles nicht wirklich und mit AT´s und mit C (HILFE) kenne ich mich noch ganz schlecht aus. So. Es läuft. Und ich weiss auch warum. Und weil ich da vielleicht was anderes habe möchte ich es Euch zeigen. Die Überlegung: A ist der Takt bei dem mich nur die steigende Flanke interessiert und Bist das Datum, das mir sagt ob rechts oder links gedreht wurde. Damit und mit der Info aus meiner Krikelei (Anlage) ist dann die kleine Interruptroutine entstanden die wunderbar läuft. Euch allen hier danke ich für die Vorarbeit. Mit Eurer Hilfe weiss ich jetzt wie diese kleinen Dinger funktionieren. So, jetzt kommt das Programm. Interessant ist ja nur die Interruptroutine. Hoffenlich kann es jemand gebrauchen. #include <avr/io.h> #include <avr/interrupt.h> // #MCU ATmega16 #define Schalter_A PINA1 // Schalter A im Drehgeber #define Schalter_B PINA0 // Schalter B im Drehgeber #define Taster_P PINA2 // Taster im Drehgeber #define Geber PORTA // Drehgeber Port #define Ausgabe PORTC // Ausgabe Port zum Testen volatile unsigned char richtung = 0; // 0 ... 255 unsigned char neuer_status; #define PHASE_A (PINA & 1<<PINA0) // RotaryEncoder #define PHASE_B (PINA & 1<<PINA1) // RotaryEncoder volatile uint8_t enc_delta; // RotaryEncoder // ************************************************************************************** // WICHTIG: Die Frequenz der Interrupts muss möglichst hoch sein. // Sonst gibt es so mekwürdigkeiten dass man denken könnte die Tasten // prellen wie doll und verrückt. Wie hoch die Frequenz hier ist // weiss ich nicht. Wie könnte man das herausbekommen? SIGNAL (SIG_OVERFLOW2) { //Interrupt, wenn T2 überläuft wird der RotaryEncoder abgefragt // PHASE_A und PHASE_B sind die Spuren A und B // A ist jetzt die Taktspur und B die Datenspur. static char A_alt; if (PHASE_A != A_alt) // es gab zumindest einen Flankenwechsel {if (PHASE_A) // wenn das auch noch WAHR ist war die Flanke steigend {if (PHASE_B) // wenn jetzt B HIGH ist enc_delta++; // dann ist das eine Rechtsdrehung else // wenn nicht, enc_delta--; // dann ist es eben eine Linksdrehung } // fertig } // aaaaaH, fast vergessen: A_alt = PHASE_A; // jetzt aber: Fertig. } // ************************************************************************************** int main(void) { // Drehgeber Anschluß DDRA &= ~(_BV(PA1) | _BV(PA0)); // Pin's als Eingang // PORTA = (_BV(PA1) | _BV(PA0)); // PullUp's ein DDRC = 0xFF; // Port als Ausgang // Timer2 einstellen TCCR2 |= (1<<CS22)| (0<<CS21) | (1<<CS20); TIMSK = 1<<TOIE2; //enable timer2 interrupt OVERFLOW sei(); for(;;) // Hauptschleife Ausgabe = enc_delta; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Datum:
@ Thomas Salewsky (thomas55) >Dateianhang: gekrikel.jpg (210,2 KB, 11 Downloads) Nomen est Omen. >Die Überlegung: A ist der Takt bei dem mich nur die steigende Flanke >interessiert und Bist das Datum, das mir sagt ob rechts oder links >gedreht wurde. Die "Idee" ist nicht neu, aber leider schlecht. Siehe Drehgeber. MFG Falk
Datum:
@ Falk Brunner (falk) Hallo Falk, Deinem Rat bin ich gefolgt und habe den Artikel Drehgeber gelesen. In dem Artikel wird genau meine Lösung empfohlen "Absatz Signalauswertung". Leider steht dort auch im ersten Absatz richtiger Unsinn über Entprellen und den Vorteil der Gray-Codierung. Aber der Autor wiederspricht sich ja dann noch bei seinem Gemecker über die Auswirkungen des Prellens. Jedenfalls sollte meine Lösung für jeden Rastpunkt nur eie Stelle zählen und klein sein. Das ist keine Auswertung von Motordrehgebersignalen - ausser wenn Motoren Seeeehr langsam laufen (ab Drehzahl > 600 wird es kritisch). Vielleicht bin ich aber auch zu sehr Anfänger. Deine Kritik kann ich jedenfalls nicht nachvollziehen. Gruss Thomas
Datum:
@ Thomas Salewsky (thomas55) >In dem Artikel wird genau meine Lösung empfohlen "Absatz >Signalauswertung". ??? Das Verstehen von Sachtexten müssen wir wohl noch ein wenig üben . . . >Leider steht dort auch im ersten Absatz richtiger Unsinn über Entprellen >und den Vorteil der Gray-Codierung. Aber der Autor wiederspricht sich ja >dann noch bei seinem Gemecker über die Auswirkungen des Prellens. Ach ja? >Vielleicht bin ich aber auch zu sehr Anfänger. Sieht wohl so aus. >Deine Kritik kann ich jedenfalls nicht nachvollziehen. Siehe oben. MFG Falk
Datum:
Hier kurzer Erfahrungsbericht: Habe einen STEC12E06 :: ALPS STEC12E Drehimpulsg., 24/24, horiz., MT an zwei pins mit internem pull-up liefert das Ding gerastet 11. Peters Code erkennt auch die Schritte zwischen den Rastungen einwandfrei (pin change interrupt). Man muss daher aufpassen, dass man den Schrittzähler erst vierteilt, wenn das auch Sinn macht. Sonst wundert man sich.
Datum:
Hallo Zusammen... Ich benuzte für ein kleines Projekt den im 2ten Beitrag vorgestellten Code um einen Drehgeber auszulesen... Nun habe ich die Frage, wie ich die Zahl in enc_delta begrenzen kann? Ich will diese auf meinen PWM Ausgang geben. die enc_delta variable soll nur von 0 bis 1000 zählen können. Wenn ich das ganze mit einer if abfrage im Hauptprogramm (nicht in der Interrupt Routine) mache...
if (enc_delta >= 1000) { enc_delta=1000; } |
funktioniert es jedoch wenn ich...
if (enc_delta <=0) { enc_delta=0; } |
habe ich das Problem, dass meine Variable nie kleiner als 0 wird. Diese geht danach wieder auf 65536 (16Bit Zahl) weil diese Zahl grösser als 1000 ist geht er mir in die erste if abfrage was kann ich dagegen tun? mittels abspeichern der Zahl in einen OLD_Value hatte ich auch keine erfolge, da ich ja den Timerinterrupt verwende kann es aber irgendwie vorkommen, dass er mir einzelne punkte überspringt... von 1 gerade auf 3 und nicht auf 2... Hoffe es kann mir jemand helfen... Chrislight
Datum:
Das Problem für mich ist, dass die Abfrage ja im Timer Interrupt passiert... Somit weis ich nie wann die Abfrage durchgeführt wird...
Datum:
Ich denke, dass es am besten ist wenn du diese Abfrage auch in der ISR machst. Dort ändert sich der Wert immer nur um +/- 1 und deswegen kannst du auf x==1000+1 und x==0-1 abfragen. Wenn du die Abfrage in der main machst, kann es sein, dass du auf 1000 stehst, um 2 erhöhst, diesen Wert (1002) für deine PWM verwendest und anschließend erst die Abfrage (x>1000) und ggf. Korrektur erfolgt. Oder du lässt die Abfrage in der main, "denkst dir eine Grenze" und fragst auf diese ab, z.B. 65535-1000=64535; 64535/2=32267; 32267+1000=33267. Dann die Abfrage ob x>1000 && x<33267 => 1000 und x>=33267 => 0 Wobei: x=enc_delta Auf die letzte Weise kann allerdings der im 2. Absatz beschriebene Fall eintreten.
Datum:
Hallo Chrislight Bei mir sieht das Ganze so aus:
ISR (TIMER0_OVF_vect)
{
static uint8_t last_state = 0,last_cnt = 0;
uint8_t new_state;
new_state=PIND & (_BV(PIND4) | _BV(PIND3));
if ((new_state^last_cnt)==(_BV(PIND4) | _BV(PIND3)) )
{
if ((new_state ^ last_state)==_BV(PIND4))
{
if(enc_delta < 100) enc_delta++;
}
else
{
if (enc_delta > 0) enc_delta--;
}
last_cnt=new_state;
}
last_state=new_state;
//
// PWM
//
if (pwm_counter++ > 100)
{
PORTA = 0x00;
pwm_counter = 0;
}
}
|
Ich zähle dabei von 0 bis 100. enc_delta ist folgendermassen deklariert: volatile uint8_t enc_delta=0; Gruß Boris
Datum:
Ey Super! Die oben erwähnte Antwort von Michael K. hat mir sehr geholfen! So funktionietrt es Bestens und ich habe auch keine grösseren Probleme, da ich die Variable enc_delta immer auf den höchswert (1000) oder auf null setze bei der jeweiligen abfrage. Besten Dank Chrislight
Datum:
Ich habs so gelöst bei meinem optischen Drehgeber: (PEC11 von Bourns)
while (1) { if(((PINA & 0x01) == 0) && ((PINA & 0x02) == 0)) { j=1; } if(((PINA & 0x01) == 0) && ((PINA & 0x02) != 0)) { j=2; } if(((PINA & 0x01) != 0) && ((PINA & 0x02) != 0)) { j=3; } if(((PINA & 0x01) != 0) && ((PINA & 0x02) == 0)) { j=0; } if(j != last) { if((j+1) % 4 == last) i--; if((last+1) % 4 == j) i++; last=j; } if(i>=5) { i=i-5; //Drehrichtung 1 } if(i<=-5) { i=i+5; //Drehrichtung 2 } } |
/Edit: Bevor jemand meckert... Natürlich kann man die Pin-Abfrage auch kompakter gestalten, aber so denke ich sieht selbst ein Anfänger recht gut was passiert :)
Datum:
Hallo, ich scheine irgendwie auf dem Schlauch zu stehen. Ich habe den Code aus dem 2. Posting in die Timer0 Interrupt Routine eingefügt und verwende folgenden Drehencoder http://www3.alps.com/WebObjects/catalog.woa/E/HTML... Es scheint das der Encoder nur jede 2. Rastung zählt. Jetzt die Frage ... ich habe das so verstanden, das in der variable enc_delta der Wert +1 oder -1 steht richtig? Ich habe dann in meinem Hauptprogramm einfach die Variable die ich hoch oder runterzählen will mit der Variable enc_delta addiert (Y += enc_delta;). Doch leider funktioniert das nicht. Es wird nicht gezählt. Habe ich da was falsch verstanden? Gruss Nils
Datum:
> Habe ich da was falsch verstanden?
Ja hast du. In enc_delta steht dein Wert (-128 ... 127). Du musst nichts
mehr rechnen, sondern kannst enc_delta so verwenden.
Lass doch mal das Beispiel-Programm so laufen wie es ist. Dann wird dir
auf Port B der aktuelle Wert ausgegeben. Und dieser sollte erniedrigt
oder erhöht werden, je nachdem in welche Richtung du drehst.
Datum:
Vielen Dank, das war der entscheidende Hinweis. Jetzt zählt er auf und ab. Das Problem ist jetzt noch das er mit jeder Rastung 2 hoch oder runterzählt. Gibts da auch noch einen kleinen Tipp?
Datum:
Ach so ... ein Problem war auch noch das ich die internen Pullups benutzt hatte. Erst als ich extern Pullups angeschlossen hatte und die internen deaktiviert habe funktionierte es. Den Common habe ich auf GND gelegt. Funktioniert das bei euch mit den internen Pullups und dem Code von Peter Danegger?
Datum:
OK, ich habe die Lösung in einem anderen Beitrag gefunden. Da wurde es so gelöst:
ISR(TIMER0_OVF_vect)
{
static char enc_last = 0x01;
char i = 0;
if( PHASE_A )
i = 1;
if( PHASE_B )
i ^= 3; // convert gray to binary
i -= enc_last; // difference new - last
if( i & 1 ) // bit 0 = value (1)
{
enc_last += i; // store new as next last
enc_delta += (i & 2) - 1; // bit 1 = direction (+/-)
if (!(enc_delta % 2)) // nur jeden 2. Schritt zählen
{
if ((i & 2)) // prüfen ob auf oder ab
{
ms++; // Variable die hochgezählt werden soll
}
else
{
ms--; // Variable die runtergezählt werden soll
}
}
}
}
|
Eine Frage bleibt jetzt noch ... warum brauche ich externe Pullups damit es läuft. Hängt es mit PORTA zusammen? Gruss
Datum:
Es sollte egtl. auch mit den internen funktionieren. Wobei ich den Code allerdings noch nicht auf einem AVR laufen hatte. Bei meinen derzeitigen Encodern werden 2,2k-Pullups empfohlen und damit klappt es. Vielleicht sind die internen zu hochohmig...
Datum:
Hallo, die manuelle Eingabe von größeren Werten ist mit groben Encodern ja etwas mühselig. Hat sich da schonmal jemand Gedanken zu einer "Beschleunigung" gemacht? Also z.B. dass die Schrittweite proportional zur Zeit zwischen zwei Impulsen ist?
Datum:
Ich habs mal mittels dem (im Drehgeber integrierten) Taster zwischen 1, 10 und 100 umschaltbar gemacht. Klappt ganz gut und lässt sich auch gut bedienen, finde ich.
Datum:
Ich hatte das mal ganz einfach mit einer Potenzierung gemacht...das klappte sehr gut: Beim langsamen Drehen konnte man die Werte genau einstellen, wenn man schnell drehte, kam man schnell in die richtige Region... Das war aber vom Programmierstil her eine ziemlich unschöne Lösung.
Datum:
Sowas lässt sich bestimmt in P.D.s Code mit ein, zwei zusätzlichen Variablen und ein bisschen Bit-Trickserei integrieren...? ;-)
Datum:
Hab da auch mal ne Frage:
enc_delta gibt mir Zahlen zwischen -128 ... 127 aus. Wenn ich mir diese
Variable über itoa(); umwandle und am LCD ausgebe, bekomme ich Werte von
0..127. Negative Zahlen kann die Funktion wahrscheinlich nicht - egal.
Ich bräuchte jetzt aber inkrementale Werte.
Habs zum Testen so versucht
unsigned char Zaehler;
Zaehler = 100;
for(;;)
{
cli();
Zaehler = Zaehler + enc_delta/2;
enc_delta = 0;
sei();
Zaehler ausgeben();
}
Problem: Beim Hochzaehler wird manchmal eine Rasterung ausgelassen und
beim Runterzaehler werden Werte um ca. 128 Werte nach unten gesprungen.
Der Compiler kann doch mit negativen Zahlen umgehen...
Ich befürchte, dass ich einen ganz dummen Fehler eingebaut habe.
Kann mir jemand weiter helfen?
Datum:
@ Igor Metwet (bastel-wastel) >Variable über itoa(); umwandle und am LCD ausgebe, bekomme ich Werte von >0..127. Negative Zahlen kann die Funktion wahrscheinlich nicht - egal. Doch, eigentlich schon, heisst ja I (wie Integer) to ASCII. >for(;;) >{ >cli(); >Zaehler = Zaehler + enc_delta/2; Kein gute Idee, damit werden Pulse verschluckt >enc_delta = 0; >sei(); >Zaehler ausgeben(); >} Besser so.
uint16_t; Zaehler = 100 for(;;) { cli(); Zaehler = Zaehler + enc_delta; enc_delta = 0; sei(); ausgeben(Zaehler/2); } |
>beim Runterzaehler werden Werte um ca. 128 Werte nach unten gesprungen. >Der Compiler kann doch mit negativen Zahlen umgehen... Ja, aber möglicherweise hast du Variablen falsch deklariert. Poste VOLLSTÄNDIGEN Quelltext als ANHANG. MfG Falk
Datum:
Schau dir mal den Unterschied zwischen signed char und unsigned char an!
Datum:
Angehängte Dateien:> Kein gute Idee, damit werden Pulse verschluckt Danke! Jetzt kann ich hoch- und runterzählen ;-) >>Variable über itoa(); umwandle und am LCD ausgebe, bekomme ich Werte von >>0..127. Negative Zahlen kann die Funktion wahrscheinlich nicht - egal. > > Doch, eigentlich schon, heisst ja I (wie Integer) to ASCII. Wenn ich runterdrehe bis auf null und dann noch einen Puls Richtung negative gebe, werden am Display "127" ausgegeben. Ich habe aber allerdings die Variable "Zaehler" als char und nichts als int deklariert. Da wären wir schon beim nächsten Effekt: Wird "Zaehler" als int deklariert, dann zählt er hoch aber anstatt runter zu zählen, zählt er pro Schritt 127 oder 255 hoch.
Datum:
while (1){
cli();
encoder += enc_delta;
enc_delta = 0;
sei();
uint8_t s[3];
sprintf (s, "encoder: %3d", encoder);
vfd_cstring(2,s);
}
Hi!
Ich benutze auch den Drehgeber-Code von Peter Dannegger ( Code ganz
oben, die zweite!)
wie in dem letzten Beispiel wird auch die enc_delta benutzt um den
zähler ("uint8_t encoder = 0;") hoch bzw. runter zu zählen.
leider springt der wert aber nur zw. 0 und 255 bei linksdrehung und
zwischen 0 und 1 bei rechtsdrehung.
ich habe mir nun schon einige beispiele hier angesehen und beiträge
gelesen, stehe aber leider auf dem schlauch. kann mir jemand helfen bzw.
einen tip geben?? (ps. ich benutze einen drehgeber OHNE rastung)
Danke, Christoph
Datum:
Micha wrote:
> Hast du mal versuchtenc_delta |
direkt zu verwenden? enc_delta springt zw. 0/ 1 (rechts) bzw. 0/ -1 (links)
Datum:
Hallo, Wie intigriere ich das in mein Programm??? In meiner main-Funktion steht eigentlich dass ganze Programm drinne, Wenn ich das mit der Abtastung(
for(;;) // main loop PORTB = enc_delta; |
) mache, dann läuft mein Programm doch nicht mehr in der while(1)-Schleife??? Würde es gehen, wenn ich das
PORTB = enc_delta; |
in die while-Schleife packe???
Datum:
T. S. wrote:
> Würde es gehen, wenn ich dasPORTB = enc_delta; |
in die
> while-Schleife packe???
PORTB = enc_delta; |
-> das gibt nur das enc_delta auf die LED's aus (angenommen die sitzen hier wie beim STK500 an Port B) enc_delta sollte eigentlich die Anzahl an schritten enthalten die der Interrupt vom Drehgeber eingelesen hat. (Sehe ich doch richtig?!) Sieh doch mal weiter oben, da steht eigentlich alles was man braucht. mein Problem besteht übrigens noch immer... siehe Beitrag "Problem mit Drehgeber"
Datum:
> mein Problem besteht übrigens noch immer... > siehe Beitrag "Problem mit Drehgeber" Richtig angeschlossen ist alles? Bleibt das Problem wenn du enc_delta auf einen Port ausgibst? So verkehrt sieht das nicht aus - die Werte würden passen. Falsch ist halt dass es nur 1 Schritt tut...
Datum:
Micha wrote: > Richtig angeschlossen ist alles? Ja. siehe auch im anderen Forum, habe den Beitrag mal da rein gestellt, gehört ja hier eig. nicht hin! >Bleibt das Problem wenn du enc_delta auf einen Port ausgibst? hm, wie genau meinst du das ? > So verkehrt sieht das nicht aus - die Werte würden passen. Falsch ist > halt dass es nur 1 Schritt tut... eben. denke ich bin ganz nah dran (oder meilenweit entfernt...) habe grade nochwas interessantes festgestellt: wenn ich GANZ schnell drehe (so schnell wie normalerweise niemand an dem ding drehen würde) dann kommen auch vernünftige schritte raus. nur halt zu schnell. ist mir irgendwie rätselhaft... naja, ich warte noch ne weile, vielleicht kann mir jemand den entscheidenden Tip geben. ansonsten besorg ich mir (leider) nen neuen Geber...
Datum:
> hm, wie genau meinst du das ?
Naja du schreibst deine Werte jetzt ja auf ein Display, oder? Ich meine
du sollst mal enc_delta direkt auf einen Port ausgeben.
Und poste wenn möglich mal deinen gesamten Source-Code.
Datum:
Ich habe die Drehencoder Funktionen benutzt die hier beschrieben sind: http://www.mikrocontroller.net/articles/Drehgeber Nachdem ich ewig rumgemacht habe und nichts funktioniert hat, aber eigentlich funktionieren hätte sollen hab ich festgestellt dass die enc_delta außerhalb der ISR nicht vorhanden ist, obwohl es eine globale Variable ist. Bin leider nicht sehr erfahren mit C und µC, hatte aber was von volatile im Hinterkopf. Nachdem ich die Variable volatil deklariert hab hat alles funktioniert. Jetzt frag ich mich: Was ist beim Author anders dass es bei ihm ohne volatile funktioniert und bei mir nicht? So wie ich das verstanden habe muss man als volatile deklarieren wenn eine Variable nicht vom angetastet werden darf weil sie z.B. von Ports oder ISRs verändert werden kann, was ja bei dem Code der Fall ist.
Datum:
> Jetzt frag ich mich: Was ist beim Author anders dass es bei ihm ohne > volatile funktioniert und bei mir nicht? Ich denke hier http://www.mikrocontroller.net/articles/Drehgeber wurde das volatile einfach vergessen, weil hier Beitrag "Re: Drehgeber auslesen" ist es ja mit drin (und das funktioniert auch).
Datum:
Ja verlinkt ist dieser Thread, aber hier kann ich keine Infos finden zu den Funktionen von dem Artikel. Und wo ich schon dabei bin: Hat jemand eine Lösung wie man verhindern kann dass das erste mal Drehen nicht funktioniert? Beim 4-fach Schalter sollte das doch möglich sein eine eindeutige Aussage zu treffen in welche Richtung es geht weil man ja auch ohne bekannte Vorbedingung davon ausgehen kann dass die Vorbedingung so aussieht dass bei beiden Phasen eine Null war. Ich denke das ist vielleicht auch der Grund warum es solche Schalter überhaupt gibt.
Datum:
Stephan S. wrote: > Jetzt frag ich mich: Was ist beim Author anders dass es bei ihm ohne > volatile funktioniert und bei mir nicht? Ja, das sind so die kleinen Gemeinheiten des GCC. Er will unbedingt auch Funktionen inlinen, die nicht static sind und dadurch ergeben sich unschöne Seiteneffekte: Einer Funktion, die eine Variable nur einmal benötigt, ist es egal, ob sie volatile ist oder nicht, sie muß sie einlesen. Volatile und der damit verbundene größere Code ist dann unnötig. Wird nun allerdings diese Funktion im gleichen Modul aufgerufen, kann es sein, daß der Compiler sie inlined und damit optimiert er sie weg, wenn die Variable nicht volatile ist. Hier im Listing sieht man schön, daß die Funktion komplett fehlt:
int8_t encode_read1( void ) { int8_t val; cli(); 118: f8 94 cli val = enc_delta; enc_delta = 0; sei(); 11a: 78 94 sei |
Diese unschöne Disoptimierung kann man aber abschalten mit folgender Compileroption: -fno-inline-small-functions Peter
Datum:
Wow, das ist mal echt eine gute Antwort... Wenn ich das aber nicht wüsste und die Variable doch als volatile deklariere, handle ich mir damit irgendwelche nennenswerten Nachteile ein? Und was ist mit dem Problem dass der erste Schritt beim Drehen nicht richtig erkannt wird?
Datum:
> Wenn ich das aber nicht wüsste und die Variable doch als volatile > deklariere, handle ich mir damit irgendwelche nennenswerten Nachteile ein? Würde mich auch interessieren. > Und was ist mit dem Problem dass der erste Schritt beim Drehen nicht > richtig erkannt wird? Ich habe das so gelöst:
static char enc_last = 0; SIGNAL (SIG_OVERFLOW0) { char i = 0; if... (siehe oben, 2. Beitrag) } void init_rot_enc(void) { if( PHASE_A ) enc_last = 1; if( PHASE_B ) enc_last ^= 3; } |
Während der Initialisierung einmal init_rot_enc aufrufen und es sollte funktionieren.
Datum:
Stephan S. wrote: > Und was ist mit dem Problem dass der erste Schritt beim Drehen nicht > richtig erkannt wird? Michael hats ja schon erklärt. Ich hab das Beispiel korrigiert: http://www.mikrocontroller.net/articles/Drehgeber#... Peter
Datum:
@ Peter Hat es einen bestimmten Grund dass du aus
if( PHASE_A ) i = 1; if( PHASE_B ) i ^= 3; |
folgendes gemacht
if( PHASE_A ) new = 3; if( PHASE_B ) new ^= 1; |
also ...= 3; und ...= 1; getauscht hast?
Datum:
Michael K. wrote: > @ Peter > Hat es einen bestimmten Grund dass du > ...= 3; und ...= 1; getauscht hast? Ja, hat es. Der AVR-GCC erzeugt äußerst umständlichen Code, wenn ein Bit abhängig von einem anderen gesetzt wird. Er expandiert erstmal zu 16Bit und schiebt dann entsprechend oft bis an die richtige Bitposition. Peter
Datum:
Hallo, bin Quereinsteiger mit meinem optischen encoder GP1A038 von Sharp. Ich beziehe mich auf den Code der unten noch einmal kurz aufgeführt ist: An PortD,3 schließe ich Kanal A an und an PortD,4 Kanal B, oder? Ich verstehe nicht diese 4 ".set directiven". Sind die Werte 4,3 und 2 die Binärwerte, die von Kanal A und B generiert werden? uND WAS IST DER bUTTONß Bitte mal jemand um eine Hilfestellung. Ich werfe sehr wahrscheinlich noch etwas durcheinander. Gruß Udo Autor: avusgalaxy (Gast) Datum: 02.02.2005 20:33 An PORT D,0 und PORT D, eins kommt jeweils eine Led. Ab PORT D... 4 und 3 den Drehgeber.. Ah ja, so solls ausehen: .include "2313def.inc" .set DIPGPin=PinB ;Port mit Drehimpulsgeber .set DIPGChA=4 ;Pin mit Channel A .set DIPGChB=3 ;Pin mit Channel B .set DIPGBT=2 ;Pin mit Button .def DIPGAlt=r4 ;Vorriger Zustand von Channel A .def DIPG=r5 ;Drehimpulsgeber-Aktion. Nach Abfrage löschen .def ButtonAlt=r6 ;Vorriger Zustand des Buttons
Datum:
Hallo! Ich möchte gerne einen Drehgeber mit einem Atmega 8 auswerten und auf eine LED Zeile ausgeben. Leider kann ich peter dannegger "C" Code nicht nachvollziehen. Gibt es diesen Code auch in Assembler und somit auch für mich nachvollziebar? Danke für eure Hilfe Otto.
Datum:
Angehängte Dateien:Ich hab die hier noch. Läuft auf einen ATtiny2313. Ergebnisse werden im RAM gespeichert. Gruß Steffen
Datum:
Steffen H schrieb:
> Ich hab die hier noch. Läuft auf einen ATtiny2313.
Ooch nöö, das ist ja ein Monstercode.
In Assembler kann man Register für Interrupts reservieren bzw. auch
Variablen in Registern halten. Spart ne Menge Code.
Hier mal mein Code in Assembler (enc_delta = 16-bittig):.include "tn261def.inc" .def save_SREG = r14 ; for general interrupt usage .def int_i = r15 ; for general interrupt usage .def int_val3 = r16 ; for encoder interrupt only .def enc_last = r13 ; for encoder interrupt only .def count0 = r18 ; encoder value low .def count1 = r19 ; encoder valeu high .equ GRAY_IN = PINA .equ PHASE_A = PA0 .equ PHASE_B = PA1 rjmp init .org OC1Aaddr in save_SREG, SREG clr int_i sbic GRAY_IN, PHASE_A ; if( PIND & 1 ) inc int_i ; i++; sbic GRAY_IN, PHASE_B ; if( PIND & 2 ) eor int_i, int_val3 ; i ^= 3; sub int_i, enc_last ; i -= enc_last; sbrs int_i, 0 ; if( i & 1 ){ rjmp _ioc1a1 add enc_last, int_i ; enc_last += i; sbrs int_i, 1 ; if( i & 2 ) rjmp _ioc1a2 subi count0, byte1(1) ; enc_delta--; sbci count1, byte2(1) out SREG, save_SREG reti _ioc1a2: ; else subi count0, byte1(-1) ; enc_delta++; sbci count1, byte2(-1) _ioc1a1: ; } out SREG, save_SREG reti ; 24 cycle init: ldi int_val3, 3 ; for usage in interupt main: ; hier T1 starten und SPI-Slave bearbeiten rjmp main |
Peter
Datum:
Angehängte Dateien:Hallo Peter! Ich habe mal eine Lösung für das vieldiskutierte Thema Dein Peda-Drehgeber-Code aus dem Wiki ( http://www.mikrocontroller.net/articles/Drehgeber ) und der Pollin Drehencoder (Panasonic) ausgetüftelt. Bekanntlich läuft der Pollin Encoder asymmetrisch. Nur Signal A ist bei jeder Raste stabil. Signal B kann in jeder zweiten Raste zwei Zustände einnehmen. (siehe Bild) (1) Da bei dem Pollin "two step encoder" der Ausgabewert halbiert wird, muss bei der Initialisierung von enc_delta berücksichtigt werden, dass die instabilen Zwischenstufen bei (2*n) und (2*n+1) liegen, damit beim rechts shiften das letzte Bit keinen Übertrag erzeugt und das Ergebnis flattert. (2) Falls mit internen Pullups gearbeitet wird, muss nach der Portinitialisierung und dem Einlesen der Port-Pegel in der Funktion encode_init() eine kleine Pause eingelegt werden, damit ggf. offene Leitungen auf High gezogen werden (Leitungskapazitäten) (3) Der Pollin Encoder dreht gegenüber dem PeDa-Code falsch herum. Ich habe die Anschlüsse von A und B vertauscht. Das ergibt dann folgende minimale Codeanpassung und der Pollin Drehgeber arbeitet absolut bullet proof.
void encode_init( void ) { int8_t new; _delay_ms(1); //Verzögerung nach Initial. interner Pullups erforderlich new = 0; if( PHASE_A ) new = 3; if( PHASE_B ) new ^= 1; // convert gray to binary last = new; // power on state //enc_delta = 0; enc_delta = (new&1?0:1); //Pollin Encoder-Zählwerk auf stabile Startposition 0/1 setzen TCCR0 = 1<<WGM01^1<<CS01^1<<CS00; // CTC, XTAL / 64 OCR0 = (uint8_t)(F_CPU / 64.0 * 1e-3 - 0.5); // 1ms TIMSK |= 1<<OCIE0; } |
der restl. Code wie in http://www.mikrocontroller.net/articles/Drehgeber
Datum:
Hallo, hat jemand von euch sein Programm bei einem Motor mit ca. 1500 U/min oder auch mehr zum laufen bekommen??? Habe erst Peters genommen und danach eins mit Interrupt Flankenauswertung geschrieben, klappen jedoch beide bei dieser Drehzahl nicht :-( Ich wäre für Programmbeispiele sehr dankbar. Gruß Klaus
Datum:
Hallo Klaus, es sind doch bei 1500 U/min nur 25 U/sec. Da würde ich mit 250 Interrupts anfangen. Welche Art Geber hast Du angeschlossen? Möglich, dass es bei Gebern mit normalen Kontakten zu Schwierigkeiten kommt. Willst Du damit eine Maschine positionieren? Gruß Thomas
Datum:
thomas55 schrieb: > Hallo Klaus, > > es sind doch bei 1500 U/min nur 25 U/sec. > > Da würde ich mit 250 Interrupts anfangen. > > Welche Art Geber hast Du angeschlossen? > Möglich, dass es bei Gebern mit normalen Kontakten zu Schwierigkeiten > kommt. > > Willst Du damit eine Maschine positionieren? > > Gruß Thomas ??? Wirklich?? Wie viele Impulse / Schritte gibt der Geber denn pro Umdrehung? 16? Dann sind es 4000 pro Sekunde, ein ordentliches Oversampling von 10 eribt schon 40000 Timeraufrufe pro Sekunde oder ein Timerinterrupt alle 25 mikrosekunden. Das ist sportlich....
Datum:
Bernhard M. schrieb: > Wie viele Impulse / Schritte gibt der Geber denn pro Umdrehung? 16? > Dann sind es 4000 pro Sekunde, ein ordentliches Oversampling von 10 > eribt schon 40000 Timeraufrufe pro Sekunde oder ein Timerinterrupt alle > 25 mikrosekunden. Das ist sportlich.... Ob da ein mechanischer Encoder überhaupt mitmacht? Bei hohen Impulsraten würde ich die Zählung in nen extra ATtiny oder CPLD machen und den per SPI oder I2C vom Master auslesen. Peter
Datum:
> Wie viele Impulse / Schritte gibt der Geber denn pro Umdrehung? 16? > Dann sind es 4000 pro Sekunde, ein ordentliches Oversampling von 10 > eribt schon 40000 Timeraufrufe pro Sekunde oder ein Timerinterrupt alle > 25 mikrosekunden. Das ist sportlich.... ich habe das mit einem Arduino und 20usec Timerrate brauchbar hingekriegt, ohne Assembler, und optional mit Peter's Entprellung der A/B/Indexsignale ; da bleibt noch Luft für serielle I/O und einen einfachen Kommandointerpreter siehe http://mah.priv.at/cgi-bin/viewvc.cgi/arduino-rota... - das war ein Debug-Vehikel von mir und ist daher kein als solches brauchbares Projekt hatte folgendes Problem: CNC-Fräse mit EMC2; selbstgebauter Drehgeber mit 360 Impulsen/Umdrehung und Indexpuls auf einer Spindel mit bis zu 5000 U/min zu erfassen und so runterzuteilen, so dass EMC2 mit einem Parallelport-Input "mitkommt" habe das schlussendlich aber mit einer FPGA-basierten Lösung gemacht (Mesatech 5i20) und einem Heidenhain-Drehgeber mit 3600 Pulse/U; Grund war meine mangelhafte mechanische Präzision beim Drehgeber, und Störungen des Signals - manche Sachen kauft man besser und ein Drehstromumrichter müllt ganz schön falls jemand dazu Anregungen braucht - der VHDL-Code und EMC2 selbst sind Open Source -Michael
Datum:
Hallo zusammen, ich habe gerade ihre Kommentare alle gelesen.Ich bion ganz neu hier.Ich mach gerade meine Technikerarbeit und ich soll auch einen Encoder ( inkremental)von der Firma Wachendorff verwenden.kann ich dafür auch den LS7366 Decoder nehmen? Und woher weiß ich welches Modell ich nehmen sollte,bezüglich der Anzahl der Impulse des Drehgebers????Ich soll nämlich die geschwindigkeit ermitteln eines Förderbands.Auch bei Geschwindigkeitänderungen. damit ich immer die perfekte position für ein Bauteil berechnen kann, um ein Foto mit ner Camera auszulösen.Die Position des Bauteils darf maximal 1mm +/- unter der Camera vom optimalen Punkt versetzt sein.Wisst ihr was ich meine???? Ich würde mich über eine Antwort sehr freuen. Mfg Maurice
Datum:
ein sogenannter triggersensor ist selbstverständlich vorhanden dieser kann aber aufgrund von baulichen gegebenheiten nicht direkt an der kamera positioniert werden desweiteren ist die geschwindigkeit des förderbandes nicht immer 100 prozent konstant.
Datum:
Ist denn das Förderband an einer Steuerung angeschlossen, wenn ja kann man den Encoder mit der verbinden. Je langsamer das Band läuft desto mehr Impulse müssen es sein. D.h. läuft das Band mit einer sehr hohen Drehzahl, brauchst du ja nicht soviele Impulse. Wie schnell läuft denn das Band so im Minimum und Maximum?
Datum:
Angehängte Dateien:heyhey, hier mal mein Mockup, was auf der 2. Version von oben aufbaut. Ich verwende externe Interrupts, um die Auslastung so gering wie möglich zu halten. Der hohen Sensitivität was das bouncing angeht begegne ich mit einem kleinen Kniff: Das Bouniving ist ja im Prizp nichts anderes als das Hin- und Herpendeln zwischen zwei Zahlen. Wenn man jetzt nur weiterzählen lässt, wenn der aktuelle Schritt in die selbe Richtung gegangen ist, wie der vorherige, wir das Pendeln quasi ausgeblendet. Das ganze funktioniert, weil der erste Kontakt mit der neuen Stufe eines Schrittes in die selbe Richtung geht wie der letzte beim Bouncing. Die Richtung des vorherigen Schrittes wird durch die Variable Rtg_pos angegeben. Beim Testen läufts bei mir in der Praxis sehr stabil, bin gespannt auf eure Meinungen. VG, Dawn
Datum:
@ Dawn (Gast) >Beim Testen läufts bei mir in der Praxis sehr stabil, bin gespannt auf >eure Meinungen. Wirklich? OK! Du bist ebenso auf dem Holzweg wie Tausende vor dir. Ein funktionierndes Einzelexemplar ist kein Beweis. Das könnte bestenfalls ein Stresstest bringen. Wird er aber nicht. Warum? Siehe Artikel Drehgeber. MfG Falk P S Kein "Aber . . ."
Datum:
...das schöne an so einem Forum ist doch, dass man abers bringen kann so viel wie man möchte :) Wer bin ich denn, dass ich hier einen Beweis erbringen möchte, ich sage blos,dass das ganze für interupts sehr stabil läuft. Für meine Anwendung, wo die Drehgeber nur selten verwendet werden ist pollen ziemlich überzogen. Einer Überlastung beuge ich durch Ausschalten der Interruots während der Routine vor. Zudem, was tun, wenn die Timer anderweitig gebraucht werden?
Datum:
Hi, ich habe im Rahmen eines Projekts in der Uni die Aufgabe mit Hilfe eines Heidenhain Inkrementaldrehgebers und einem ATmega2561 den Drehwinkel bzw. die Winkelgeschwindigkeit eines Motors zu messen. Der Motor läuft mit maximal 2000 U/min und der Drehgeber hat 3000 Striche, das wäre also eine maximale Signalfrequenz von 100 KHz. Zu welcher Methode würdet ihr mir da raten? Eigentlich wollte ich das mit den externen Interrupts machen, aber ich habe jetzt hier öfter gelesen, dass es mit Timerinterrupts sicherer ist. Kommt der Mikrocontroller überhaupt mit dieser hohen Frequenz klar? Vielen Dank!
Datum:
Hallo BMJ! Du musst einfach die Eingänge schnell genug abfragen. Um mit einem AVR 100kHz noch sicher handeln zu können sollte die entsprechende Routine aber in Assembler geschrieben werden und beim Aufruf aus einem Timer möglichst wenig auf dem Stack zwischengelagert werden. Mit freundlichen Grüßen Thorsten Ostermann
Datum:
ATmega2561 klingt so, als ob dieser Bolide noch vieles andere machen soll. Daher würde ich nen extra ATtiny25 nehmen und per SPI oder I2C auslesen. Es gibt zwar noch alte Encoder-ICs, aber die sind exorbitant teuer (Museumszuschlag). Peter
Datum:
Hallo, danke schon mal für die Antworten. Also ich möchte eigentlich keine zusätzlichen IC's benutzen. Ich habe von der Uni diesen fertigen Sensorknoten mit dem ATmega2561 bekommen und der muss dann auch nichts anderes mehr machen als die Daten aufzunehmen und auf dem PC in LabView darzustellen. Wie groß müsste den die Abtastfrequenz sein, wenn ich das mit Timerinterrupts mache? (Die maximale Signalfrequenz sind doch "nur" 75 kHz, da der Motor mit max 1500 U/min läuft) Der ATmega läuft mit etwas weniger als 8 MHz, ich habe da etwas bedenken, dass ich nicht mehr genug Rechenzyklen zur Verfügung habe, weil ich auch nur im Notfall auf Assembler zurückgreifen möchte. Der Drehgeber hat außerdem auch ein Referenzsignal bei jeder Umdrehung. Vielleicht würde es ausreichen, wenn ich bei jeder vollen Umdrehung eine Korrektur durchführe (Zähler auf Null setzen) und es doch mit den externen Interrupts mache. Wenn bei 3000 Strichen bei einer Umdrehung ein Paar nicht erkannt werden, wäre das nicht so schlimm denke ich. Was meint ihr? Viele Grüße! BMJ
Datum:
peter dannegger schrieb: > Bei einer Änderung über einen Schritt, ergeben sich je nach > Drehrichtung folgende Werte (in Klammern der 2-Bit Wert als > Dezimalzahl): > > Vorwärts: > 00 - 11 = 01 (1) > 01 - 00 = 01 (1) > 10 - 01 = 01 (1) > 11 - 10 = 01 (1) > > Rückwärts: > 00 - 01 = 11 (3) > 01 - 10 = 11 (3) > 10 - 11 = 11 (3) Hallo, ich verstehe nicht, wie diese Tabelle zu Stande kommt. Kann mir das einer bitte erklären? LG
Datum:
Die Tabelle ist meiner Meinung nach falsch. Encoder geben einen Graycode aus, d.h. es ändert sich pro Schritt immer nur eine der beiden Leitungen: 00 -> 01 01 -> 11 11 -> 10 10 -> 00 In Pfeilrichtung wäre dann vorwärts, gegen die Pfeilrichtung rückwärts. Bei den anderen 8 möglichen Zustandsänderungen hätten sich beide Signale geändert, was auf einen Fehler hindeutet (Zustandswechsel verpasst da Encoder zu schnell dreht oder Auswertung zu langsam ist). Mit freundlichen Grüßen Thorsten Ostermann
Datum:
Hallo, ich bin auch relativ neu auf diesem Gebiet und soll mithilfe eines magnetischen Drehgebers einen Schrittmotor regeln. Soweit habe ich mich in das Programm von Herrn Dannegger eingelesen und vieles verstanden ;) Was ich z.B. nicht verstehe ist die Diskussion um die Rastpunkte. Blöd gesagt was ist das? Mein magnetischer Encoder bietet eine Auflösung von 1024 Impulsen/Umdrehung und arbeitet eben mit den Kanälen A & B (& Z, aber das scheint ja egal zu sein). Das dieser in irgendeiner Einstellung "spürbar" einrastet kann ich nicht bestätigten.... Vielen Dank schon einmal! Frank
Datum:
Hallo Frank, die 'Rastpunkte' sind für die mechanischen Drehgeber. Die haben auch nur 8-32 Flanken. Für magnetische Drehgeber spielt das Ganze keine Rolle. Und bei 1024 Pulsen wird wohl auch niemand von Hand an der Achse drehen :-) Gruß Ralf
Datum:
Ach cool, danke Ralf für die schnelle Antwort! Ich kann also blöd gesagt, einfach das (erste) Programm von Herrn Dannegger verwenden (http://www.mikrocontroller.net/articles/Drehgeber)? Denn bei meinen bisherigen Versuch (lasse mir die Gesamtzahl an Schritten an einem angeschlossenen LCD anzeigen) habe ich folgende 2 Probleme: 1. Ich brauch für die bisher manuelle Betätigung des Drehgebers (--> ca. 2 Umdrehungen/s :D ) schon eine Auslesefrequenz von 100kHz was ja schon enorm ist 2.Ich denke es ist ein Variablenspeicherproblem: Sobald ich a) einen Overflow habe (Also bei ca. 32k Schritten) oder b) erst in die eine Richtung drehe (z.B. bis 11000) und dann in die andere bis es <10000 Schritte sind, bleibt die letzte Ziffer "einfach" stehen, also z.B. 99994 statt 9999... und ab dann springen die Schritte auf dem LCD absolut zufällig.... Erneut, vielen Dank schon einmal :) Frank
Datum:
Hallo, bei der Pulsfrequenz die dein Drehgeber liefert wirst Du wahrscheinlich nicht glücklich mit einer Software Lösung. Kommt auf ein MC System an ob der das schafft. Da wirst Du mit spez. IC's oder nem CPLD arbeiten müssen. Von den spez. IC's fällt mir aber grade nicht mehr die Bezeichnung ein. gruß, Bjoern
Datum:
>2.Ich denke es ist ein Variablenspeicherproblem: Sobald ich a) einen >Overflow habe (Also bei ca. 32k Schritten) oder b) erst in die eine >Richtung drehe (z.B. bis 11000) und dann in die andere bis es <10000 >Schritte sind, bleibt die letzte Ziffer "einfach" stehen, also z.B. >99994 statt 9999... und ab dann springen die Schritte auf dem LCD >absolut zufällig.... Versuch mal den Datentyp zu erweitern, z.b. auf int32_t. Gruß Jonas
Datum:
Frank schrieb: > 1. Ich brauch für die bisher manuelle Betätigung des Drehgebers (--> ca. > 2 Umdrehungen/s :D ) schon eine Auslesefrequenz von 100kHz was ja schon > enorm ist Bei 2 Umdrehungen/s reichen 5kHz. Frank schrieb: > 2.Ich denke es ist ein Variablenspeicherproblem: Sobald ich a) einen > Overflow habe (Also bei ca. 32k Schritten) oder b) erst in die eine > Richtung drehe (z.B. bis 11000) und dann in die andere bis es <10000 > Schritte sind, bleibt die letzte Ziffer "einfach" stehen, also z.B. > 99994 statt 9999... und ab dann springen die Schritte auf dem LCD > absolut zufällig.... Nö, ein Darstellungsproblem. Vermutlich erweiterst Du nicht mit Leerzeichen und alte Ziffern bleiben bei kürzeren Zahlen stehen. Peter
Datum:
Peter Dannegger schrieb: > Nö, ein Darstellungsproblem. Vermutlich erweiterst Du nicht mit > Leerzeichen und alte Ziffern bleiben bei kürzeren Zahlen stehen. Danke für die schnelle Antwort. Das stimmt, das macht Sinn :). Weiß zwar noch nicht ganz wie das zu bewerkstelligen ist, da ich bisher auf eine vorgefertigte Header Datei für das LCD zurückgreife aber wird schon irgendwie :). Kommst du auf die 5 kHz über: 2 Umdrehungen/s *1024*2= 4100 Hz? Bei der Frequenz funktionierts aber leider nicht zuverlässig... Hab glaub auf rn-wissen mal gelesen dass es das 20-fache der Grundfrequenz sein soll... Noch eine Verständnisfrage: Soweit ich das Programm verstanden habe ist in enc_delta je nach Richtung entweder 10 oder 01 gespeichert oder? Warum ist es denn enc_delta += und nicht nur =? Denn angenommen ich würde es in der Abtastfrequenz wirklich schaffen 2 Impulse weiterzudrehen, also 01+01= 10, dann interpretiert es doch der µC als 1 Schritt in die andere Richtung.. Wenn ich das richtig verstanden habe ist die Auswertung eines Drehgebers mit Interrupts die durch Flanken ausgelöst worden sind nur wegen den prellenden (mechanischen) Tastern ungeeignet/schlechter. Wäre es aber nicht für meinen magnetischen bzw. später optischen Drehgeber nicht sogar besser? Oder tritt auch hier Prellen auf? Ich hoffe es ist ok dass ich soviele Fragen gestellt habe. Freu mich auf jeden Fall über eure Antworten. Danke! Frank
Datum:
@ Frank (Gast) >Frequenz funktionierts aber leider nicht zuverlässig... Hab glaub auf >rn-wissen mal gelesen dass es das 20-fache der Grundfrequenz sein >soll... Ist hier falsch. >Richtung entweder 10 oder 01 gespeichert oder? Warum ist es denn >enc_delta += und nicht nur =? Weil die Differenz (delta) addiert werden muss. >Wenn ich das richtig verstanden habe ist die Auswertung eines Drehgebers >mit Interrupts die durch Flanken ausgelöst worden sind nur wegen den >prellenden (mechanischen) Tastern ungeeignet/schlechter. u.a. > Wäre es aber >nicht für meinen magnetischen bzw. später optischen Drehgeber nicht >sogar besser? Oder tritt auch hier Prellen auf? Kann sein, muss nicht. Ist aber für dein Problem egal. Dein Ansatz ist falsch. Für eine einfach Drehzahlmessung braucht man die echte Dekodierung nicht. Man nutzt einfach eine Spur, A oder B, und macht einen stinknormalen Frequenzzähler. Das macht der AVR mit links und gähnt dabei. Ein Timer zählt die Pulse am Eingang, ein zweiter generiert die Messzeit. Das passiert alles in Hardware. Die CPU muss nur ab und an die Zähler auslesen und daraus die Drehzahl berechnen. MFG Falk
Datum:
Falk Brunner schrieb: > für eine einfach Drehzahlmessung braucht man die > echte Dekodierung nicht. Hey danke Falk für deine Antwort. Da habe ich mich wohl missverständlich ausgedrückt. Ich brauche im Endeffekt eigentlich keine Drehzahlmessung, sondern soll einen Schlitten der über einen Schrittmotor angetrieben wird regeln. Also eine Positionsbestimmung / -regelung. Deshalb benötige ich schon die Anzahl zurückgelegter Schritte. Welches Verfahren ist denn dann deiner Meinung nach am Sinnvollsten? Viele Grüße Frank P.S: Warum Ist die Abtastfrequenz als 20-faches der Grundfrequenz falsch?
Datum:
Weil du hier kein sinusförmiges Signal hast, was noch rekonstruierbar sein soll, sondern ein einfaches Rechtecksignal. Mit freundlichen Grüßen Thorsten Ostermann
Datum:
Ich bin es nochmal :) Es wäre schön wenn mir jemand weiterhelfen würde und mir sagt, welches Verfahren (zur Debatte stehen ja wohl nur Timer und Flankeninterrupts, oder?) für die Auswertung eines optischen Drehgebers mit 350 Impulsen/U in Bezug auf Zuverlässigkeit und Belastung des µC geeigneter ist. Wie in einem vorigen Beitrag erwähnt handelt es sich bei der Auswertung um die Positionsbestimmung, ich muss also schon die Schritte mitzählen, insofern sollte es schon sehr genau sein. Vielen Dank, Grüße, Frank
Datum:
Frank schrieb: > rehgebers mit 350 Impulsen/U Eine Umdrehung pro Minute/Sekunde/Millisekunde? Da musst du schon etwas genauer werden.
Datum:
Albert ... schrieb: > Frank schrieb: >> rehgebers mit 350 Impulsen/U > Eine Umdrehung pro Minute/Sekunde/Millisekunde? Da musst du schon etwas > genauer werden. Stimmt da fehlt n halber Satz. Der Drehgeber gibt 350 Impulse / U aus, der Schrittmotor dreht mit max. 300U/min
Datum:
Die neueren AVRs haben ja nen Pin-Change-Interrupt. Da kann man diesen nehmen anstelle eines Timerinterrupts. Also für beide Eingänge den Pin-Change-Interrupt aktivieren. Damit ist die max CPU-Last für hohe Drehzahlen geringer. Peter
Datum:
Vielleicht habe ich ja was nicht mitbekommen, aber in der Überschrift steht Drehgeber und im Beitrag von Frank erwähnt er magnetische Drehgeber, ich geh also mal davon aus, daß es um Drehgeber geht. Und da empfiehlt ein Peter Dannegger auf die Frage "zur Debatte stehen ja wohl nur Timer und Flankeninterrupts" allen Ernstes die komplett untauglichen Flankeninterrupts, auch nicht mit der vollkommen falschen Begründung "Damit ist die max CPU-Last für hohe Drehzahlen geringer." (es wäre natürlich umgeklehrt). Wahnsinn, das kann ja wohl nicht sein, Drehgeber liest man NIE mit Flankeninterrupts aus, das wäre als ob man Tastendrücke per pin change Interrupt zählen wollte (egal ob es jetzt um Inkrementposition, Drehzahl oder Positionsbestimmung geht) Gerade ein Peter Dannegger sollte das nach seine Entprellroutine für Tasteneingabe verstanden haben. Zu Drehgebern ist eigentlich alles gesagt: http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29 Auch magnetische Drehgeber prellen, elektrische Störungen im Übergang können das bewirken. Die Probleme (100kHz, falsche Ausgabe) sind ja schon versucht worden zu erklären und beantworten, leider ohne Rückmeldung.
Datum:
Du hast schon richtig gelesen. Der Pin-Change-Interrupt funktioniert sehr gut. Besonders, wenn einem Leute mit schnellem Drehen beweisen wollen, daß die Software sich verzählt. Man muß also nicht ständig eine hohe Interruptlast erzeugen, sondern nur, wenn wirklich schnell gedreht wird. Es gibt natürlich bei Positionsgebern an vibrierenden Maschinen die seltene Möglichkeit, daß eine hohe Impulszahl entsteht und die CPU verlangsamt (nur ein Main-Loop Befehl zwischen den Interrupts). Aber dagegen kann man einfach in dem Pin-Change-Interrupt einen Zähler einbauen, der bei einem Maximalwert den Interrupt disabled und einen Fehler meldet. Ansonsten setzt ein Timerinterrupt diesen Zähler zyklisch zurück. Auch eine Möglickeit wäre, der Pin-change-Interrupt disabled sich, setzt einen Timer-Compare-Interrupt auf 10µs und dieser enabled ihn wieder. Man hat dann max 100kHz Abtastrate, aber nur bei Bedarf. Peter
Datum:
Puh, jetzt bin ich leicht verwirrt. Ist also für (letztendlich) optische Drehgeber der Flankeninterrupt das sinnvollere? Ich denke mal in Verbindung mit einem Zustandsvergleich durch eine Gray Code Tabelle oder? Die Idee mit der Fehlermeldung bzw. dem switchen auf Timer-interrupt hört sich gut an (ich hoff ich schaff es gscheit zu implementieren), danke Peter! Frank
Datum:
MaWin schrieb: > Die Probleme (100kHz, falsche Ausgabe) sind ja schon versucht > worden zu erklären und beantworten, leider ohne Rückmeldung. Hab erst beim zweiten Mal erkannt, dass das an mich gerichtet war. 100 kHz sind bei mir "komischerweise" tasächlich noch notwendig und sogar da kommt es zu Fehlern wenn man sehr schnell mit der Hand dreht. Da ich aber letztendlich einen optischen Drehgeber mit 360 Impulsen/U verwenden werde statt den magnetischen mit 1000 Imp/U hoffe ich dass sich das Problem von "allein löst", ich melde mich ggf. nochmal :) Die falsche Ausgabe lag tatsächlich am LCD und wurde von mir "behoben" indem ich die Werte per RS232 an den Computer ausgebe. Möchte mir vllt noch jemand verraten ob denn nun Flanken oder doch Timer ISRs für meine Auswertung von optischen Drehgebern sinnvoll ist? Grüße, Frank
Datum:
Hallo, ich muß demnächst einen optischen Incrementalgeber (5000 Impulse pro Drehung) Auslesen und würde gerne die ENCODE.C variante wählen, nun muß ich um die Hardware anpassung vorzubehmen eine parametriebare Drehreichtungsumkehr mit einbauen, dazu kann ich ja entweder PHASE A mit PHASE B Vertauschen oder woanders ansetzen, nur sehe ich nicht genau wo ich das am besten im Code bewerkstellige, kann mit jemand da mal einen Denkanstoß geben, hab leider die Hardware noch nicht fertig um damit rumzuspielen, aber dieses Problem geistert mir die ganze Zeit durch den Kopf. Was ich möchte das die Drehrichtung durch einen Port PIN umschaltbar ist, dies muß ich machen der der Incremantalgeber entweder von links oder von rechts ans Band geschraubt wird. mfg, Bjoern
Datum:
Hallo, nach dem x mal ansehen des codes, fällt mir grade etwas auf. langt es einfach von der varibale i bit 1 zu invertieren um das zu erreichen was ich möchte ? mfg, Bjoern
Datum:
Hallo an alle,
ich versuche schon seit Tagen den zweiten Code zu entschlüsseln. Für
meinen optischen Impulsgeber brauche ich die Richtung. Also ob er Rechts
oder Links herum dreht.
Kann mir vielleicht jemand erklären, wie sich die Variable enc_delta für
die beiden Richtungen verhält? Damit kann ich dann schauen, welche
Ausgänge am PortB freigeschaltet werden.
Momentan habe ich für einen Richtungssinn den Code : 1111 -> 1110 ->
1101 -> 1100. Dieser Code müsste nacheinander dann am Ausgang PB0 und
PB1 zu erkennen sein. Oder sehe ich hier irgendetwas falsch.
#include <io.h>
#include <interrupt.h>
#include <signal.h>
#define PHASE_A (PINC & 1<<PINC0) // PINC.0
#define PHASE_B (PINC & 1<<PINC1) // PINC.1
volatile char enc_delta; // -128 ... 127
int main( void )
{
TCCR0 = 1<<CS01; //divide by 8 * 256
TIMSK = 1<<TOIE0; //enable timer interrupt
DDRB = 0xFF;
sei();
for(;;) // main loop
PORTB = enc_delta;
}
SIGNAL (SIG_OVERFLOW0)
{
static char enc_last = 0x01;
char i = 0;
if( PHASE_A )
i = 1;
if( PHASE_B )
i ^= 3; // convert gray to binary
i -= enc_last; // difference new - last
if( i & 1 ){ // bit 0 = value (1)
enc_last += i; // store new as next last
enc_delta += (i & 2) - 1; // bit 1 = direction (+/-)
}
}
Datum:
Kann mir jemand erklären, wie ich aus der variable enc_delta eine Drehrichtungserkennung machen kann? Mich interessieren ja nur die ersten beiden Bits?, oder nicht? Momentan zerbreche ich mir den Kopf darüber. Weiterhin, möchte ich gerne wissen, wann der Drehgeber eine volle Umdrehung gemacht hat. Der Geber hat 500 Impulse. Vielleicht kann ich das ja über die For Schleife in der mainloop realisieren? Aber irgendwie komme ich da nicht weiter....
Datum:
obbedaja schrieb: > Kann mir jemand erklären, wie ich aus der variable enc_delta eine > Drehrichtungserkennung machen kann? Mich interessieren ja nur die ersten > beiden Bits?, oder nicht? > Momentan zerbreche ich mir den Kopf darüber. > > Weiterhin, möchte ich gerne wissen, wann der Drehgeber eine volle > Umdrehung gemacht hat. Der Geber hat 500 Impulse. > Vielleicht kann ich das ja über die For Schleife in der mainloop > realisieren? Aber irgendwie komme ich da nicht weiter.... Die Drehrichtung erkennst Du daran, ob enc_delta positiv oder negativ ist. Für die volle Umdrehung must Du oft genug enc_delta in Deiner mainloop auslesen und aufaddieren, wenn die Summe 500 ist hat er eine volle Rechtsdrehung gemacht, bei -500 eine volle Linksdrehung (oder umgekehrt...)
Beitrag #2397021 wurde von einem Moderator gelöscht.
Datum:
Angehängte Dateien:Hallo, ich habe es jetzt geschafft den Drehgeber und die Drehrichtung auszugeben. Weiterhin zählt mir ein Zähler die Inkremente und gibt pro voller Umdrehung ein digitales Signal aus. Dies klappt perfekt bis zu einer bestimmten Drehzahl (ca. 500U/min), ab dieser werden plötzlich rechts und links Drehungen erkannt und ich kann damit nicht mehr weiter arbeiten. Kann mir jemand sagen, ob dies am Inkrementalgeber liegt? Oder eher an der Abtastung mittels Timer. Ich lasse den Timer ohne Vorteiler laufen, denn mit Vorteiler kann ich auch die kleinen Drehzahlen nicht auswerten. Ich freue mich auf eine Antwort.
Datum:
obbedaja schrieb: > Kann mir jemand sagen, ob dies am Inkrementalgeber liegt? Das liegt wohl eher am Abtast-Theorem. Vermutlich verpaßt du Phasen des Gebers. Guck' dir auf 'nem Oszi mal deine Gebersignale und den Abtasttakt an.
Datum:
Danke für die schnelle Antwort. Habe soeben die Spuren A und B mit einem Messrechner aufgenommmen, hatte kei Oszi zur Hand. Im unteren Drehzahlbereich laufen die Rechtecksignale (mit leichter Rampenbildung) sehr genau und 90° verschoben. Erhöhe ich die Drehzahl, werden aus den Rechtecksignalen -> spitze Dreiecksignale und ca. jeder fünfte Strich wird noch als Rechteck erkannt. Dabei hatte ich den Geber beim Drehen festgehalten und bemerkt, dass er eine leichte Unwucht aufweist. Ich hoffe, dass der Fehler daher kommt und meine Messergebnisse verfälscht. Neuer Inkrementalgeber ist bestellt und werde sobald er da ist, neues berichten. Aber eine allgemeine Frage zu dem ablaufenden Timer0 (8-bit) habe ich noch. Ich benutze einen neuen Inkrementalgeber mit 1024 Impulsen. Meine Drehzahl ist 1333U/min. Der Geber hat somit eine Frequenz von 22749Hz=23KHz. Nach dem Abtasttheorem müsste ich mit 46KHz das Signal abtasten. Wie kann ich meinen Timer einstellen, damit er dies auch so macht? D.h. evtl einen Vorteiler einbauen? zur Info: Der Micrcontroller hat einen externen Quarz mit 3,6864MHz.
Datum:
Angehängte Dateien:Anbei der Signalverlauf der mittleren und hohen Drehzahlen.









