PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ENCODER Befehl zu langsam



Dr.Ice2000
20.08.2006, 00:54
Hallo,

ich habe versucht den Encoder Befehl praktisch wie in der Hilfe angegeben zu benutzen. Das funktioniert auch ganz ausgezeichnet wenn ich wirklich langsam drehe, sobald ich etwas schneller werde wird nur noch ab und zu etwas gezählt.

Gibt es eine Möglichkeit den Befehl mit einem Interrupt zu nutzen ?
Ich habe schon andere Vorschläge hier aus dem Forum versucht, aber die bringen nicht so gute Resultate wie der Bascom Befehl.

Ach so, ich nutze einen ATMega32 und einen Schrittmotor mit einem LM393 als Drehgeber.

Beste Grüße

Markus

PicNick
20.08.2006, 13:16
Das Voll-dekodieren ist, wenn's schneller geht, ein absoluter Full-Time-Job. Du mußt mal ausrechnen, wieviel Impulse du nun tatsächlich brauchst und dann sehen, ob sich das überhaupt ausgehen KANN.
Der Code von Bascom ist ja eigentlich nicht sehr lang.
https://www.roboternetz.de/wissen/index.php/Bascom_Inside-Code#.28Quadratur-.29_ENCODER

Beim Interrupt isses ja auch nicht so, daß auf einmal ein Wunder geschieht. Die Minimallösung wäre, von jedem Encoder ein Signal auf INT0
bzw INT1 zu legen, und im Interrupt das andere Signal zu checken, ob's rauf oder runter geht.

Rechne wirklich mal nach, was für Erfordernisse du tatsächlich hast.

Dr.Ice2000
20.08.2006, 13:51
Danke erst einmal für die Antwort Robert !

Ich drehe das Ding von Hand und über den LM393 liefert der Stepper den ich als Encoder "missbrauche" nur 12 Impulse pro Umdrehung.
Das ganze soll als Eingabe in einem DDS Generator dienen und da schubst man den Knopf halt schon mal an. Das schafft die ENCODER Routine aber nicht.

Ich habe schon mit optischen Encodern gearbeitet, allerdings über eine Interruptroutine. Da schaffe ich es selbst mit schnellem drehen nicht das Zählen aus dem Takt zu bringen obwohl ich da von dem optischen Encoder bis zu 500 Impulse pro Umdrehung bekomme.

Leider hab ich mit der Abfrage, die ich dort benutzt habe kein Glück gehabt, damit habe ich Probleme bei der Richtungsabfrage seltsamerweise.

Naja ich werde dann mal weiterbasteln, vieleicht finde ich ja auch den Fehler in meiner alten Routine.

Danke,
Markus

Hanni
20.08.2006, 14:52
Also eigentlich sollten auch 500 Impulse / sek nicht das große Problem für einen Mikrocontroller darstellen.

Vielleicht solltest du mal die minimallösung von Picnic austesten.

PicNick
20.08.2006, 15:08
Also, mit dieser beschaulichen Geschwindigkeit sollten alle Varianten klarkommen, möcht' man meinen.
Jetzt müßte man von deinem Programm wohl etwas mehr wissen, glaub ich. Vielleicht ist ja wo eine Ecke drinnen ?

Dr.Ice2000
20.08.2006, 15:26
Danke nochmal für eure Mühe !

Hier das Programm, das mit meinem optischen Encoder einwandfrei funktioniert:



$regfile = "m32def.dat"
$crystal = 8000000
$baud = 9600

Ddrd.2 = 0 'Eingänge mit Pullup für Drehgeber
Portd.2 = 1

Ddrd.4 = 0
Portd.4 = 1

On Int0 Onint0
Mcucr.isc00 = 1 'INT0 bei FALLING + RISING
Mcucr.isc01 = 0
Gimsk.int0 = 1

Dim Drehgeber As Long 'wird von ISR (INT0) verändert
Dim Drehgeber_alt As Long

Drehimpuls1 Alias Pind.2
Drehimpuls2 Alias Pind.4
Onint0:
If Drehimpuls2 <> Drehimpuls1 Then 'test phase B
If Divider1 = 9 Then 'soll 9 sein
Divider1 = 0
Incr Drehgeber
Else
Incr Divider1
Divider2 = 0
End If
Else
If Divider2 = 9 Then 'Soll 9 sein
Divider2 = 0
Decr Drehgeber
Else
Incr Divider2
Divider1 = 0
End If
End If
Return


Den Divider hab ich nur drin um die über 500 Impulse pro Umdrehung auf ein Maß zu bringen, dasss man auch von Hand drehen kann :-)

So und hier der Versuch mit dem Bascom Befehl :



$regfile = "m32def.dat" ' specify the used micro
$crystal = 8000000 ' used crystal frequency
$baud = 19200 ' use baud rate
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 10 ' default use 10 for the SW stack
$framesize = 40 ' default use 40 for the frame space
Config Lcd = 20 * 4a , Chipset = Ks077 '20*4 LCD DIP
Config Lcdpin = Pin , Db4 = Porta.4 , Db5 = Porta.5 , Db6 = Porta.6 , Db7 = Porta.7 , E = Porta.3 , Rs = Porta.2
Cls
Locate 1 , 1
Lcd "Encoder test"
Dim B As Byte
Dim Wert As Integer
Dim Divider1 As Integer
Dim Divider2 As Integer
Wert = 100
'we have dimmed a byte because we need to maintain the state of the encoder

Portb = &B11 ' activate pull up registers

Do
B = Encoder(pind.3 , Pind.2 , Links , Rechts , 0)
' ^--- 1 means wait for change which blocks programflow
' ^--------^---------- labels which are called
' ^-------^---------------------------- port PINs
Lcd B
Locate 4 , 1
Lcd "" ; Wert ; " "
Waitms 10
Loop
End

'so while you can choose PINB0 and PINB7,they must be both member of PINB
'this works on all PIN registers

Links:
Locate 2 , 1
Lcd "left rotation "
Decr Wert
Return

Rechts:
Locate 2 , 1
Lcd "right rotation "
Incr Wert
Return


End


Das ist praktisch genau der Code aus der Hilfe.

Gruß Markus

PicNick
20.08.2006, 15:44
Nun, "Waitms 10" nach jeder Abfrage (ohne change WAIT) ist nicht zweckmäßig, da geht ihm ja was verloren.

Dr.Ice2000
20.08.2006, 15:59
Das habe ich gerade einmal auskommentiert, nützt aber nicht viel. Sobald ich den Knopf ein bischen "andrehe", so wie man das von Funkgeräten kennt z.B. verliert er den Takt und erkennt auch die Drehrichtung nicht sauber.

Ich vermute aber so langsam vieleicht ein Problem mit meiner Hardware, wobei die Signale auf dem Oszilloskop eigentlich ganz ok aussehen.

ich werde aber morgen mal mit einem Speicheroszi messen, dann kann ich auch die Abstände sehen, die kommen auf meinem analogen Oszi nicht so gut raus.

Vielen Dank erst mal

Markus

PicNick
20.08.2006, 16:11
Do
B = Encoder(pind.3 , Pind.2 , Links , Rechts , 1)
--- 1 means wait for change which blocks programflow
Lcd B
Locate 4 , 1
Lcd "" ; Wert ; " "
Loop
End


Probier's mal mit "WAIT" beim "ENCODE"

Dr.Ice2000
20.08.2006, 17:00
Hi

hab ich auch versucht, wird aber nicht schneller, hält mir nur das Programm an.

mfG
Markus

PicNick
20.08.2006, 17:06
mmhhh. Dann nehm' ich an, daß die LCD Befehle zu lange brauchen.
Da wärst du mit der interrupt-Methode dann wirklich besser dran

dk5rm
21.08.2006, 10:16
Hallo zusammen,
im Anhang ist eine Routine , die einen Encoder über eine state machine voll decodiert und damit die VOLLE Auflösung liefert. (d.h. bei JEDEM H/L Übergang wird rauf oder runter gezählt). Durch Speichern der Interrupts in Int_cnt und Abarbeiten in den While- Schleifen gehen auch bei schnellem Drehen keine Impulse verloren.

Millenniumpilot
21.08.2006, 10:50
Hallo,

vielen Dank für Deinen gelungenen "Einstand" hier. Herzlich willkommen in Forum.

Gruß Dirk

Dr.Ice2000
21.08.2006, 22:19
Hallo,

ich habe auch die Statemachine versucht, funktioniert für mich leider auch nicht, ich denke ich habe wohl doch ein Hardwareproblem, denn mit einem anderen Drehgeber funktioniert es. An das Speicheroszi komme ich leider in nächster Zeit nicht ran, aber ich werde mal andere Hardwarelösungen versuchen um meinen Steppermotor zu benutzen.

Ich wünsche euch noch viel Spaß und nochmals vielen Dank !!!

Ach so, das Programm muss für die aktuellen Bascom Versionen etwas geändert werden, denn Bascom hat "ENCODER" ja jetzt als reservierten Befehl, das sollte man also nicht mehr als Variable verwenden.

MfG

Markus



'-----------------------------------------------------------------
' (c) 2003 Manfred Fleischmann
' full quad encoder implementation with state machine
'-----------------------------------------------------------------
$regfile = "m32def.dat"
$crystal = 16000000

Ddrd.1 = 0 ' axial in
Ddrd.2 = 0 ' coder in
Ddrd.3 = 0 ' coder in
Portd.1 = 0 ' axial pullup
Portd.2 = 0 ' coder pullup
Portd.3 = 0 ' coder pullup

Const True = 1
Const False = 0

Dim Int_cnt As Byte
Dim Encoder1 As Bit ' Encoder ist ein reserviertes Wort in Bascom
Dim Rx_freq As Single
Dim Old As Byte
Dim New As Byte
Dim Calc As Byte

Enable Interrupts
Enable Int0 ' Enable the interrupt 1 / 2
Enable Int1
Mcucr = 00000101 ' Interrupt 0 und 1 bei logical change auslösen
On Int0 Int_encoder ' Labels for the Interrupt routine
On Int1 Int_encoder

INt_cnt = 128 ' Initialisierung
Encoder1 = True
Old = 3

Do ' Main Program Loop ************************************************** **************************
If Encoder1 = True Then
While INt_cnt > 128
Rx_freq = Rx_freq + 10
Decr INt_cnt
Wend
While INt_cnt < 128
Rx_freq = Rx_freq - 10
Incr INt_cnt
Wend
Encoder1 = False
End If
Loop ' END MAIN ************************************************** **************************



'***************** Encoder Interrupt Routine ***************************************
Int_encoder:
Encoder1 = True ' Frequenz muß nachgeführt werden
New = Pind
Calc = Old.2 Xor New.3 ' berechne FSM
Calc = Calc * 2
Decr Calc
INt_cnt = INt_cnt + Calc
Old = New
Return

End