Forum: Compiler & IDEs Bräuchte eure Hilfe! Drehencoder mir Bascom simulieren!


von Rainer K. (rc_rainer)


Lesenswert?

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

von nebel (Gast)


Lesenswert?

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.

von Rainer K. (rc_rainer)


Angehängte Dateien:

Lesenswert?

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
von Simpel (Gast)


Lesenswert?

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.

von Joe (Gast)


Lesenswert?

Jetzt muss ich nur noch das Timing wissen.

von Rainer K. (rc_rainer)


Lesenswert?

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

von Simpel (Gast)


Lesenswert?

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).

von Rainer K. (rc_rainer)


Lesenswert?

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!

von Karl H. (kbuchegg)


Lesenswert?

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
von Rainer K. (rc_rainer)


Lesenswert?

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
Noch kein Account? Hier anmelden.