Hallo allerseits
Ich versuche gerade einen Emulator für einen Incrementalgeber zu bauen.
Ich möchte also das Ausgangssignal eines Incrementalgebers generieren (Kanal A und B).
Dabei sollen verschiedene Incrementalgeber (100, 500 und 1024 Pulse/Ump) verwendet werden können.
Mit einem Controller soll per Hardware und Timer1 am OC1A das A-Signal und am OC1B-Pin das B-Signal ausgegeben werden.
Mit einem Poti am ADC-Eingang ADC0 möchte ich die Frequenz einstellen können.
Rechtsanschlag, also 5V am ADC-Eingang soll 6000 rpm Signal ausgeben.
Das soll bis runter auf 200 rpm oder tiefer gehen.
Soweit habe ich das auch am laufen.
Hier mal den Code
Alles anzeigen
Das generierte Ausgangssignal sieht nun so aus:
DS1Z_QuickPrint2.png
Wie man sieht, werden etwa 10kHz ausgegeben, weas bei einem Incrementalgeber mit 100 Pulse je Umdrehung einer Drehzahl von 6000 rpm entspricht.
Um die Phasenverschiebung von 90° zu erzeugen, habe ich den Timer1 im Mode 12 (CTC-Mode mit ICR1-Registerwert als Top-Wert) konfiguriert.
Somit wird die Timerfrequenz auf die doppelte der Ausgangsfrequenz eingestellt und die Ausgänge getoggelt.
Nun das Problem:
Wenn ich am Poti drehe und damit die Frequenz ändere, springt sporadisch die Phase der A-B Kanäle.
Heißt, mal ist Kanal B 90° nacheilend, und mal Voreilend, aber dann stabil.
Ich denke es hängt mit dem Zeitpunkt zusammen, an den das OC1A-Register und das ICR1-Register geändert wird.
Bisher habe ich das noch nicht hinbekommen, dass die Phase stabil bleibt. Das ist wichtig, denn die bestimmt die Drehrichtung.
Um das Problem in den Griff zu bekommen habe ich noch ein Interrupt von OC1A-generieren lassen, in dem ich einen Puls auf PortB.0 ausgeben lasse.
(Siehe ISR_OC1A). Dort wollte ich die Signale zueinander synchronisieren. das klappt aber nicht.
Hier das Signal des OC1A-Pulses in Bezug auf OC1A.
DS1Z_QuickPrint3.png
Hat jemand eine Idee, wie ich Signal B dem Signal A stabil nacheilen lasse?
Ich versuche gerade einen Emulator für einen Incrementalgeber zu bauen.
Ich möchte also das Ausgangssignal eines Incrementalgebers generieren (Kanal A und B).
Dabei sollen verschiedene Incrementalgeber (100, 500 und 1024 Pulse/Ump) verwendet werden können.
Mit einem Controller soll per Hardware und Timer1 am OC1A das A-Signal und am OC1B-Pin das B-Signal ausgegeben werden.
Mit einem Poti am ADC-Eingang ADC0 möchte ich die Frequenz einstellen können.
Rechtsanschlag, also 5V am ADC-Eingang soll 6000 rpm Signal ausgeben.
Das soll bis runter auf 200 rpm oder tiefer gehen.
Soweit habe ich das auch am laufen.
Hier mal den Code
BASCOM-Quellcode: Emulator Incrementalgeben
- ' Incrementalgeber Emulator
- ' Das Tastverhältnis der Signale
- ' ist symetrisch mit 50%. Allerdings sind die Signale richtungsabhängig
- ' zueinander um ±90° phasenverschoben.
- ' ---- ----
- ' | | | |
- ' Kanal A ---- ---- ----
- '
- ' ---- ----
- ' | | | |
- ' Kanal B ---- ---- ----
- ' Die untere Frequenz (F out) ist theoretisch 0Hz. Die obere Frequenz hängt vom
- ' Incrementalgeber ab, der simuliert werden soll. Simuliert werden soll
- ' die Drehzahl n = 200 ... 6000 rpm mit den folgenden Incrementalgebern (umschaltbar).
- ' Incrementalgeber F out max.
- ' 100 Pulse/Ump 10000 Hz
- ' 500 Pulse/Ump 50000 Hz
- ' 1024 Pulse/Ump 100000 Hz
- $Regfile = "m168def.dat"
- $HWStack = 40
- $SWStack = 40
- $FrameSize = 40
- $Crystal = 14745600 ' Quarz
- Config SubMode = New
- Const PIN_AIN = 0 ' ADC0 Soll-Drehzahl
- ' mögliche Inkrementalgeber
- Const I_Geber_100 = 100 ' Geber mit 100 Pulse/Ump
- Const I_Geber_500 = 500 ' Geber mit 500 Pulse/Ump
- Const I_Geber_1024 = 1024 ' Geber mit 1024 Pulse/Ump
- Const I_Geber = I_GEBER_100 ' Geber setzen
- Dim F_Out as Long ' Ausgabefrequenz des Gebers
- Dim F_OutNew as Long
- Dim I_State as Byte ' Zustand der A-B-Signale
- ' ------------------------------------
- ' Routinen
- ' ------------------------------------
- ' Berechnung der Ausgabefrequenz des Gebers
- Function getFOut() as Long
- Local n as Integer ' Drehzahl
- Local f as Single ' Frequenz
- ' n-max * Adc 6000 * Adc
- ' frq = -------------- = -----------
- ' adc-max * 60 1000 * 60
- n = GetAdc(PIN_AIN) * 6 ' Soll-Drehzahl einlesen
- ' Drehzahlen unter 200 sollen Geberausgabe stoppen
- If n < 200 then
- F_Out = 0
- Exit Function
- End If
- ' Drehzahl (rpm) in Frequenz umrechnen
- f = n ' in Single wandeln
- f = f / 60 ' Umrechnung Drehzahl in Frq
- ' Berechnung Ausgabe-Frequenz mit gewähltem Inkremental-Geber
- f = f * I_GEBER
- GetFOut = f ' in Long umwandeln
- End Function
- ' Registerwerte Timer1 berechnen und setzen
- Sub setTimer()
- Local R_ICR as Long
- Local R_CM as Long
- Local tmp as Word
- If F_Out = 0 then
- Reset TCCR1B.0 ' Keine Drehzahl ausgeben (Timer1 Stop)
- Else
- ' Register berechnen / setzen
- R_ICR = _xtal \ F_Out ' ICR1-Registerwert berechnen
- R_ICR = R_ICR \ 2 ' Da Pin getoggelt wird, brauche ich doppelte Frequenz
- R_CM = R_ICR \ 2 ' Compare-Register berechnen
- tmp = LowW(R_ICR)
- ICR1 = tmp
- tmp = LowW(R_CM)
- Compare1A = tmp 'LowW(R_CM) ' Register setzen
- Set TCCR1B.0 ' Drehzahl ausgeben (Timer1 Start)
- End If
- End Sub
- ' ------------------------------------
- ' Initialisierung
- ' ------------------------------------
- Config ADC = Single , Prescaler = Auto , Reference = AVCC
- Config Portb.0 = Output
- Config PortB.1 = Output ' OC1A
- Config PortB.2 = Output ' OC1B
- ' Timer1 im Mode 12, CTC mit ICR1 als Top-Wert
- Compare1A = 368
- Compare1B = 1
- ICR1 = 737
- Config Timer1 = Timer , Prescale = 1 , COMPARE_A = Toggle , COMPARE_B = Toggle , Clear_Timer = 1
- Set TCCR1B.WGM13
- On OC1A ISR_OC1A NoSave
- Enable OC1A
- Enable Interrupts
- ' ------------------------------------
- ' Hauptschleife
- ' ------------------------------------
- Do
- F_Out = GetFOut() ' Ausgabe-Frequenz des Gebers berechnen
- Call SetTimer() ' Register für Frequenzausgabe setzen
- Waitms 100
- Loop
- ISR_OC1A:
- '!PUSH r23
- !PUSH r24
- !IN r24, SREG
- !PUSH r24
- !SBI Portb,0
- !NOP
- !CBI PortB,0
- '!SBIC PinB,1
- '!CBI PortB,0
- !POP r24
- !OUT SREG, r24
- !POP r24
- '!POP r23
- Return
DS1Z_QuickPrint2.png
Wie man sieht, werden etwa 10kHz ausgegeben, weas bei einem Incrementalgeber mit 100 Pulse je Umdrehung einer Drehzahl von 6000 rpm entspricht.
Um die Phasenverschiebung von 90° zu erzeugen, habe ich den Timer1 im Mode 12 (CTC-Mode mit ICR1-Registerwert als Top-Wert) konfiguriert.
Somit wird die Timerfrequenz auf die doppelte der Ausgangsfrequenz eingestellt und die Ausgänge getoggelt.
Nun das Problem:
Wenn ich am Poti drehe und damit die Frequenz ändere, springt sporadisch die Phase der A-B Kanäle.
Heißt, mal ist Kanal B 90° nacheilend, und mal Voreilend, aber dann stabil.
Ich denke es hängt mit dem Zeitpunkt zusammen, an den das OC1A-Register und das ICR1-Register geändert wird.
Bisher habe ich das noch nicht hinbekommen, dass die Phase stabil bleibt. Das ist wichtig, denn die bestimmt die Drehrichtung.
Um das Problem in den Griff zu bekommen habe ich noch ein Interrupt von OC1A-generieren lassen, in dem ich einen Puls auf PortB.0 ausgeben lasse.
(Siehe ISR_OC1A). Dort wollte ich die Signale zueinander synchronisieren. das klappt aber nicht.
Hier das Signal des OC1A-Pulses in Bezug auf OC1A.
DS1Z_QuickPrint3.png
Hat jemand eine Idee, wie ich Signal B dem Signal A stabil nacheilen lasse?