Willa
02.10.2008, 09:37
Hi!
Ich möchte gerne 4 Servos schnell ansteuern (mit vielleicht 100 bis 200 Hz). Im Anhang findet Ihr ein Bild mit dem angedachten Aufbau. Die Framezeit scheint total unkritisch zu sein. Mein Programm funktioniert anscheinend wunderbar, allerdings frage ich mich wie effizient mein Code wohl ist...
Hier mal mein BASCOM Code:
$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 16000000
$baud = 9600
Config Timer0 = Timer , Prescale = 64 'je höher prescale desto resourcenschonender?
On Timer0 Timer_irq
Dim Servo1time As Byte 'servo1 high-time
Dim Servo2time As Byte 'servo2 high-time
Dim Servo3time As Byte 'servo3 high-time
Dim Servo4time As Byte 'servo4 high-time
Dim Kanal As Byte 'Kanal 1-4
Dim I As Byte
Dim Timeraufnull As Bit 'Timer Zurücksetzer
Enable Timer0
Enable Interrupts
Config Portb = Output
Portb.0 = 0 'hier hängt servo1
Portb.1 = 0 'hier hängt servo2
Portb.2 = 0 'hier hängt servo3
Portb.3 = 0 'hier hängt servo4
Kanal = 1
Timeraufnull = 0
Servo1time = 131 'Preload 131 = 2000Hz = 0.5ms pulse
Servo2time = 131
Servo3time = 131
Servo4time = 131
Do
'----- Das ist nur Code um servos zu bewegen --> unwichtig
For I = 0 To 255
'Servo1
Servo1time = I
Waitms 50 'bisschen warten damit servo auch position erreichen kann
'Servo2
If I < 163 Then
Servo2time = I + 20
Else
Servo2time = 131
End If
'Servo3
If I < 170 Then
Servo3time = 301 - I
Else
Servo3time = 150
End If
'Servo4
If I < 140 Then
Servo4time = I
Else
Servo4time = 170
End If
Next I
Loop
End
Timer_irq:
If Kanal = 1 Then
If Portb.0 = 0 Then 'wenn port low...
Timer0 = Servo1time 'dann timer auf gewünschte länge...
Portb.0 = 1 'und port auf high
Else 'portb.0 = 1
If Timeraufnull = 1 Then 'port erst wieder auf low wenn der timer
Portb.0 = 0 'servo1time gelaufen ist UND einmal zurückgesetzt wurde.
Incr Kanal 'das ergibt dann: 0 bis 1ms + 1ms = 1 bis 2ms high
Timeraufnull = 0
Else 'TimerAufNull=0
Timeraufnull = 1
Timer0 = 6 'ergibt 1ms bis zum erneuten überlauf
End If
End If
End If
'und hier das gleiche für die anderen kanäle...
If Kanal = 2 Then
If Portb.1 = 0 Then
Timer0 = Servo2time
Portb.1 = 1
Else
If Timeraufnull = 1 Then
Portb.1 = 0
Incr Kanal
Timeraufnull = 0
Else
Timeraufnull = 1
Timer0 = 6
End If
End If
End If
If Kanal = 3 Then
If Portb.2 = 0 Then
Timer0 = Servo3time
Portb.2 = 1
Else
If Timeraufnull = 1 Then
Portb.2 = 0
Incr Kanal
Timeraufnull = 0
Else
Timeraufnull = 1
Timer0 = 6
End If
End If
End If
If Kanal = 4 Then
If Portb.3 = 0 Then
Timer0 = Servo4time
Portb.3 = 1
Else
If Timeraufnull = 1 Then
Portb.3 = 0
Incr Kanal
Timeraufnull = 0
Else
Timeraufnull = 1
Timer0 = 6
End If
End If
End If
If Kanal > 4 Then
Kanal = 1
End If
Return
Ablauf:
Kanal = 1 und Portb.0 ist aus. Der Preload des Timers wird auf die gewünschte Länge gesetzt , z.b. 152 = 2400Hz = 0,416ms. Der Port wird angeschaltet, der Rest des Timer_irq wird nicht ausgeführt.
Nach 0,416ms wird erneut in Timer_irq gesprungen. Nun wird die Variable "Timeraufnull" auf "1" gesetzt, und der Preload des Timers auf 6 = 1000Hz = 1ms gesetzt. Timer_irq wird wieder verlassen.
Nach 1,416ms wird nochmal ins Timer_irq gesprungen. Jetzt wird Portb.0 ausgeschaltet, die Kanalnummer um eins erhöht und "Timeraufnull" wieder auf 0 gesetzt. Noch während dieses Interrupts wird das ganze für Servo2 eingeleitet usw....
Meine Fragen:
Es gibt 8 Interrupts von Timer0 um alle Servos zu stellen. Ist das gut so, oder nimmt man besser Timer1 mit Prescale=1?? Das ergäbe auch ne gute Auflösung, außerdem nur 4 Interrupts um 4 Servos zu stellen. Aber der Prescale wäre nur 1, und das ist doch ungünstig?
Wie stelle ich Performance des Programms fest? Im Simulator steht was von Cycles und "mS", kann man das benutzen um zu errechnen wie schnell ein Programm läuft?
In Zukunft soll das Programm auf einem ATmega644 mit 20 MHz laufen. Dann ist die maximale Pulslänge den ich mit Prescale=64 erreichen kann 0,8159ms und nicht mehr 1,019 ms. D.h. ich komme nicht mehr auf 2 ms wenn ich zwei Interrupts zusammenzähle, sondern nur noch auf ca. 1,632 ms. Das reicht nicht für den Vollausschlag eines Servos... Was tun? Evtl drei Interrupts zusammenhängen? Das wird aber ungleich komplizierter....
Wenn mir jemand ein bisschen weiterhelfen könnte wäre das fantastisch....!
Ich möchte gerne 4 Servos schnell ansteuern (mit vielleicht 100 bis 200 Hz). Im Anhang findet Ihr ein Bild mit dem angedachten Aufbau. Die Framezeit scheint total unkritisch zu sein. Mein Programm funktioniert anscheinend wunderbar, allerdings frage ich mich wie effizient mein Code wohl ist...
Hier mal mein BASCOM Code:
$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 16000000
$baud = 9600
Config Timer0 = Timer , Prescale = 64 'je höher prescale desto resourcenschonender?
On Timer0 Timer_irq
Dim Servo1time As Byte 'servo1 high-time
Dim Servo2time As Byte 'servo2 high-time
Dim Servo3time As Byte 'servo3 high-time
Dim Servo4time As Byte 'servo4 high-time
Dim Kanal As Byte 'Kanal 1-4
Dim I As Byte
Dim Timeraufnull As Bit 'Timer Zurücksetzer
Enable Timer0
Enable Interrupts
Config Portb = Output
Portb.0 = 0 'hier hängt servo1
Portb.1 = 0 'hier hängt servo2
Portb.2 = 0 'hier hängt servo3
Portb.3 = 0 'hier hängt servo4
Kanal = 1
Timeraufnull = 0
Servo1time = 131 'Preload 131 = 2000Hz = 0.5ms pulse
Servo2time = 131
Servo3time = 131
Servo4time = 131
Do
'----- Das ist nur Code um servos zu bewegen --> unwichtig
For I = 0 To 255
'Servo1
Servo1time = I
Waitms 50 'bisschen warten damit servo auch position erreichen kann
'Servo2
If I < 163 Then
Servo2time = I + 20
Else
Servo2time = 131
End If
'Servo3
If I < 170 Then
Servo3time = 301 - I
Else
Servo3time = 150
End If
'Servo4
If I < 140 Then
Servo4time = I
Else
Servo4time = 170
End If
Next I
Loop
End
Timer_irq:
If Kanal = 1 Then
If Portb.0 = 0 Then 'wenn port low...
Timer0 = Servo1time 'dann timer auf gewünschte länge...
Portb.0 = 1 'und port auf high
Else 'portb.0 = 1
If Timeraufnull = 1 Then 'port erst wieder auf low wenn der timer
Portb.0 = 0 'servo1time gelaufen ist UND einmal zurückgesetzt wurde.
Incr Kanal 'das ergibt dann: 0 bis 1ms + 1ms = 1 bis 2ms high
Timeraufnull = 0
Else 'TimerAufNull=0
Timeraufnull = 1
Timer0 = 6 'ergibt 1ms bis zum erneuten überlauf
End If
End If
End If
'und hier das gleiche für die anderen kanäle...
If Kanal = 2 Then
If Portb.1 = 0 Then
Timer0 = Servo2time
Portb.1 = 1
Else
If Timeraufnull = 1 Then
Portb.1 = 0
Incr Kanal
Timeraufnull = 0
Else
Timeraufnull = 1
Timer0 = 6
End If
End If
End If
If Kanal = 3 Then
If Portb.2 = 0 Then
Timer0 = Servo3time
Portb.2 = 1
Else
If Timeraufnull = 1 Then
Portb.2 = 0
Incr Kanal
Timeraufnull = 0
Else
Timeraufnull = 1
Timer0 = 6
End If
End If
End If
If Kanal = 4 Then
If Portb.3 = 0 Then
Timer0 = Servo4time
Portb.3 = 1
Else
If Timeraufnull = 1 Then
Portb.3 = 0
Incr Kanal
Timeraufnull = 0
Else
Timeraufnull = 1
Timer0 = 6
End If
End If
End If
If Kanal > 4 Then
Kanal = 1
End If
Return
Ablauf:
Kanal = 1 und Portb.0 ist aus. Der Preload des Timers wird auf die gewünschte Länge gesetzt , z.b. 152 = 2400Hz = 0,416ms. Der Port wird angeschaltet, der Rest des Timer_irq wird nicht ausgeführt.
Nach 0,416ms wird erneut in Timer_irq gesprungen. Nun wird die Variable "Timeraufnull" auf "1" gesetzt, und der Preload des Timers auf 6 = 1000Hz = 1ms gesetzt. Timer_irq wird wieder verlassen.
Nach 1,416ms wird nochmal ins Timer_irq gesprungen. Jetzt wird Portb.0 ausgeschaltet, die Kanalnummer um eins erhöht und "Timeraufnull" wieder auf 0 gesetzt. Noch während dieses Interrupts wird das ganze für Servo2 eingeleitet usw....
Meine Fragen:
Es gibt 8 Interrupts von Timer0 um alle Servos zu stellen. Ist das gut so, oder nimmt man besser Timer1 mit Prescale=1?? Das ergäbe auch ne gute Auflösung, außerdem nur 4 Interrupts um 4 Servos zu stellen. Aber der Prescale wäre nur 1, und das ist doch ungünstig?
Wie stelle ich Performance des Programms fest? Im Simulator steht was von Cycles und "mS", kann man das benutzen um zu errechnen wie schnell ein Programm läuft?
In Zukunft soll das Programm auf einem ATmega644 mit 20 MHz laufen. Dann ist die maximale Pulslänge den ich mit Prescale=64 erreichen kann 0,8159ms und nicht mehr 1,019 ms. D.h. ich komme nicht mehr auf 2 ms wenn ich zwei Interrupts zusammenzähle, sondern nur noch auf ca. 1,632 ms. Das reicht nicht für den Vollausschlag eines Servos... Was tun? Evtl drei Interrupts zusammenhängen? Das wird aber ungleich komplizierter....
Wenn mir jemand ein bisschen weiterhelfen könnte wäre das fantastisch....!