Hallo und guten Tag! Ich würde gern einen Fernsteuersenderknüppel als Handrad für eine CNC Maschine missbrauchen!Um nicht mein Steuerprogramm (Mach3) auszuhebeln, würde ich gern einen Drehencoder (Handrad) mit einem Atmega8 simulieren! Zwei verschiedene Signale per PWM mit gleichem Duty Cycle über ADC ansteuern, kein Problem! AAAber die Phasenverschiebung der beiden Signale hinzukriegen, stehe ich wie ein Ochs vorm Berg!Wenn ihr mir vielleicht ein Paar Lösungsansätze schreiben könntet? Ich weiß echt nicht weiter! Dank im Voraus! gruß Rainer
Rainer K. schrieb: > einem Atmega8 simulieren! Zwei verschiedene Signale per PWM mit gleichem > Duty Cycle über ADC ansteuern, kein Problem! AAAber die > Phasenverschiebung der beiden Signale hinzukriegen, stehe ich wie ein > Ochs vorm Berg!Wenn ihr mir vielleicht ein Paar Lösungsansätze schreiben Kennen wir alle. Aber vielleicht könntest du doch mal genauer erklären, welches Signal in den Mega8 reingeht und welches rauskommen soll.
Als Eingangssignal ist eigentlich nur das Steuerpoti vom Kreuzknüppel (10K) der auf einen ADC geht! In abhängigkeit vom Ausschlag des Knüppel möchte ich 2 Signale generieren die dem eines Drehencoders gleich sind! Bei einem Drehencoder oder Handrad= schnelleres Drehen= höhere Frquenz, langsam= niedriger! A und B Signal! Jedoch sind diese Signale um 90 Grad Phasenverschoben!Ich hoffe es ist etwas deutlicher geworden!
:
Bearbeitet durch User
Du legst den Graycode als 2-Bit-Wert fortlaufend in einem Byte-Array ab und steuerst mit dem ADC-Wert den Top-Wert eines Timer mit entsprechendem Prescaler. Der Timeroverflow-Int. zählt eine Variable (4Bit Ringzähler) hoch oder runter, deren Wert den Index des Arrays bestimmt, dessen Inhalt dann ausgelesen wird und per Maske auf die Ausganspins transferiert wird. Da du wahrscheinlich vorwärts und rückwärts zählen willst, nimmst du z.B. die mittleren fünf Werte des ADC-Bereichs (125-129 bei 8-Bit)als Nullstellung und alles was darüber ist als vorwärts und alles was darunter ist als rückwärts. Für vorwärts zählst du den Arraycounter hoch und für rückwärts zählst du den Arraycounter rückwärts. Je höher der ADC-Wert im Plus ist, umso schneller (also kleinerer Timer-Top-Wert!)wird der Graycode in aufsteigender Folge endlos generiert. Je weiter der ADC-Wert im unteren Beeich ist, umso schneller wird der Graycode rückwärts ausgegeben.
Jetzt muss ich nur noch das Timing wissen.
Die höchste Ausgabefrequenz liegt ungefähr bei 40KHz!Was meinst du mit Top Wert? Ich muss mir deinen Text doch einige male durchlesen, aber im groben weiß ich was du meinst! Besten dank erstmal
Der Top-Wert kann per Timerregister u.A. im CTC-Modus des Timers als Obbergrenze gesetzt werden. D.h. ein 8-Bit-Timer zählt dann nicht bis 255, sondern nur bis zum Top-Wert (z.B. 152), löst dann den Overflow-Interrupt aus und setzt sich dann wieder auf Zählerstand 0 zurück... usw. Der Überlauf kann dadurch beliebig nach unten gesetzt werden, so dass bei der selben Taktfrequenz der Zyklus zwischen den Ovl-Interrupts (fast) beliebig verkürzt werden kann. Ergo, die Impulse die durch den Interrupt generiert werden, folgen schneller aufeinander (=höhere Frequenz).
Hallo Simpel! Leider steige ich durch deine gute Beschreibung nicht ganz durch!Hättest du vielleicht ein Beispiel oder einen Link? Ich glaube das würde mir sehr weiterhelfen! Dank im Voraus!
Ich glaube du schiesst da mit Kanonen auf Spatzen. Die Idee, einen Timer eine PWM generieren zu lassen ist zwar nett, aber auch recht sinnlos. Auch braucht es da für einen Anfänger keinen Timer, da das Timing der Pulse absolut nicht zeitkritisch ist. Es kann also zb auch mittels Wait gemacht werden. Entscheidend ist lediglich, dass die Wait nicht allzulang gemacht werden, damit das Programm noch genügend 'reaktionsschnell' ist um als Mensch keine grossartigen Verzögerungen zu bemerken. Ansonsten würde ich die gleiche Technik wie bei DSS System einsetzen. Einen Counter, der in einer Array indiziert, aus dem die auszugebenden Pegel für die beiden Ausgabepins vorliegen. Der springende Punkt ist, in welchen Zeitabständen dieser Counter erhöht oder erniedrigt wird und so dann die korrekten Pegel ausgibt, so wie sie auch bei einem echten Encoder erscheinen würden. Damit das fein granuliert wird, kann der Counter zb in 1/100stel oder 1/1000stel Einheiten erhöht oder erniedrigt werden, ein Wert der aus dem eingelesenen ADC Wert errechnet wird. ungefähr so
1 | .... |
2 | |
3 | do |
4 | |
5 | position = getadc( 0 ) |
6 | position = 512 - position |
7 | |
8 | index = index + position |
9 | if index > 12000 then |
10 | index = index - 12000 |
11 | end if |
12 | if index < 0 then |
13 | index = index + 12000 |
14 | end if |
15 | |
16 | tableIndex = index / 1000 |
17 | tableIndex = tableIndex + 1 |
18 | |
19 | EncoderA = lookup( tableIndex, AValues ) |
20 | EncoderB = lookup( tableIndex, BValues ) |
21 | |
22 | waitms 10 |
23 | loop |
24 | |
25 | AValues: |
26 | Data 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 |
27 | |
28 | BValues: |
29 | Data 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 |
die genaue Ausformung überlasse ich dir. Aber so ungefähr sollte das hinkommen. EncoderA und EncoderB sind Alias für die Ausgabepins Der WErt von 12000 wurde so gewählt, dass sich nach Division durch 1000 und Addition von 1 ein Wert von 1 bis 12 ergibt, der direkt als Index in die Lookup-Tabelle benutzt werden kann (12 Werte im Data) Steht der Knüppel in Mittelstellung und ist das alles einigermassen sauber eingerichtet, dann kommt da im Idealfall vom ADC ein Wert von 512 zurück. Dadurch dass der ADC Wert um 512 'zentriert' wird (damit positive und negative ADC Ergebnisse möglich sind) kommt dann 0 heraus. Die Variable index wird dadurch nicht verändert, es wird daher immer derselbe Lookup Wert ausgegeben. Ist der ADC Wert größer als 512, dann bleibt nach Subtraktion etwas positives übrig, der index Wert wird größer und irgendwann wird dann auch bei der Division durch 1000 ein um 1 größerer Tabellen Index für lookup rauskommen: Die Ausgänge schalten auf den nächsten Zustand. Hier könnte man zb noch so eingreifen, dass ganz kleine umgerechnete Wert vom ADC, die nahe bei 0 liegen auch tatsächlich als 0 gewertet werden um eine stabile Mittenposition des Knüppels zu erreichen, die auch langfristig den simulierten Encoder nicht in die nächste Position driften lässt.
1 | .... |
2 | position = getadc( 0 ) |
3 | position = 512 - position |
4 | |
5 | if position > -10 and position < 10 then |
6 | position = 0 |
7 | end if |
8 | |
9 | index = index + position |
10 | .... |
Die 10 Millisekunden haben keine besondere Bewandtnis sondern sind einfach nur geschätzt. Auf der einen Seite scheint der Wert klein genug, dass kein Mensch eine gefühlte Verzögerung wahrnehmen wird und auf der anderern Seite ist er gefühlt gross genug geschätzt, dass der simulierte Encoder nicht wie wild eine Drehung simuliert. Ob der Wert allerdings vernünftig ist oder nicht, muss man in der Praxis sehen. Bis zu einem Wert von 100 Millisekunden hätte ich da noch keine grossen Bedenken. Es gibt allerdings mehrere Stellen im Programm, an denen man beim simulierten Timing den Hebel ansetzen kann.
:
Bearbeitet durch User
Erstmal herzlichen Dank Karl_Heinz! Das ist genau das, was ich gesucht habe! Damit kann ich gut arbeiten! Sobald das Projekt fertig ist, möchte ich es gern anderen hier Zugänglich machen! Layout, Schaltplan Quellcode und alles was dazu gehört!Die Zeit ist hier absolut unkritisch = Waitus!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.