Hey Leute!
Ich habe mir ein STK500 zugelegt und habe schon etwas Erfahrung mit
Bascom bin aber noch Anfänger. Ich möchte einen Servo ansteuern, aber
der macht nicht das, was ich will, ich nehme stark an, das an meinem
Code etwas falsch ist, leider weiß ich nicht was. Ich habe abundzu noch
mit der Syntax etwas Probleme bzw. damit, dem uC zu sagen, was er machen
soll.
Mein Vorhaben sah wie folgt aus:
Ich wollte über den Timer0 alle 20ms aus dem Hauptprogramm (ich lass
dort nur eine LED blinken) in eine ISR springen, die wiederum 1ms läuft.
Dann wollte ich dem Servo 1ms ein Signal geben, das heißt er musste dann
ganz nach links fahren. Tut er aber nicht, sondern zittert wenn überhaut
ein bisschen, ich bin am verzweifeln. Kann mir jemand weiterhelfen? Ich
habe zwar gelesen, dass es auch mit dem Timer1 geht, aber ich habe nicht
ganz verstanden, wie ich die Comparewerte nutzen soll, um die Zeitdauer
anzugeben, wie breit das Signal seien soll. Für Hilfe bin ich sehr
dankbar, weil ich nicht weiß, wo mein Denkfehler ist.
(Ich habe doch richtig verstanden, dass ein Servo alle 20ms ein Signal
bekommt, welches 1ms - 2ms lang ist, oder? 1ms wäre ganz links, 1,5
Mittelstellung, 2ms ganz rechts)
Den Servo (der von Conrad für 2,95€) habe ich an VTG/GND von Portd und
das gelbe Kabel an Portd.5 angeschlossen.
Anbei der Code:
'-----------------------------------------------------------------------
--'
$regfile = "m16def.dat"
$crystal = 8000000
$baud = 19200
$hwstack = 32
$swstack = 8
$framesize = 24
Dim K As Byte
K = 131
Config Portb = Output
Config Portd = Output
Config Timer0 = Timer , Prescale = 1024
Enable Interrupts
Enable Timer0
On Timer0 Isr_von_timer0
Timer0 = 99
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm
= Clear Down , Prescale = 1
Enable Timer1
Start Timer1
Do
Toggle Portb.0
Waitms 100
Loop
End
Isr_von_timer0:
Config Timer0 = Timer , Timer0 = K , Prescale = 64
Compare1a = 1
Return
'-----------------------------------------------------------------------
-'
Gruß Bascompasstschon
Ja, das habe ich gesehen. Aber kann ich einen Servo nicht auch über
einen Timer mit Comparewerten steuern? Das wollte ich gerne hinbekommen.
Gruß Bascompasstschon
Kann man.
Aber wenn ich mir dein Machwerk so ansehe, bist du mit den
vorgefertigten Routinen besser bedient.
Aber seis drum: Ist zwar nicht BASCOM, aber die Idee kann man sich holen
Modellbauservo Ansteuerung
Oh super, vielen Dank! :-))) Das habe ich gar nicht gesehen! :-)
Ich wollte ganz gerne eine Lageregelung machen, das ist mein Ziel. Ich
habe einen Gyro als Sensor (ADXRS610) und die Werte die ich einlese sind
auch ganz in Ordnung, natürlich nicht perfekt, aber einigermaßen gut.
Der Drift hält sich in Grenzen.
Bei diesen Routinen verstehe ich nicht ganz, was sich hinter dem Reload
verbirgt.
Ich wollte das so machen, dass ich die Werte einlese und dann daraus
einen Winkel bestimme. Aus diesem Winkel muss ich nun eine Signallänge
bestimmen (z.B +180 = 2ms) und dem Motor dann je nach Lage x ms ein
Signal (zwischen 1 - 2 ms) geben (alle 20 ms). So hatte ich mir das
gedacht. Mein Problem bei der Routine ist, dass ich nicht genau weiß,
was der Reload ist (in Bascom).
Gruß Bascompasstschon
Bascompasstschon schrieb:> Bei diesen Routinen verstehe ich nicht ganz, was sich hinter dem Reload> verbirgt.
Welchem Relaod?
Wieviele Servos hast du?
Eines?
Dann nimm dir den Timer 1, setz den Prescaler so, dass du damit 2
Millisekunden gut in einem Timerwert abbilden kannst.
Dann setzt du den Timer in einem PWM Modus auf. Der PWM Wert ist dann
die Länge des Pulses, den der Timer erzeugt.
Sprich: Deine gewünschte Zeit bildet sich in einem bestimmten Wert für
das Vergleichsregister ab. Den Wert rechnest du im Programm aus und
setzt ihn im Vergleichsregister. Fertig. Den Rest macht die Hardware-PWM
> bestimmen (z.B +180 = 2ms) und dem Motor dann je nach Lage x ms ein> Signal (zwischen 1 - 2 ms) geben
richtig
> (alle 20 ms).
Vergiss die 20ms. Die sind nicht wichtig. Ob der Puls alle 10 oder alle
15 oder alle 20 oder alle 25ms kommt, ist dem Servo herzlich egal. Das
ist keine Zeit, auf die du dein Augenmerk richten musst. Du
konzentrierst dich jetzt erst mal ausschlisslich darauf, einen Puls mit
Pulslängen von 1 bis 2 ms zu generieren. Und zwar in Hardware mit der
PWM. Wenn dann hinter dem Puls noch Zeit übrig bleibt, bis der Timer
überläuft und den nächsten Puls anfängt, dann passt das schon.
Erst einmal, herzlichen Dank, dass du mir hilfst! :-)
Ok, das werde ich versuchen, ich würde es so machen:
'-----------------------------------------------------------------------
--'
'Timer1 = 16Bit-Timer
'X_Takte: CPU[Hz]*Anzeit[ms]/1000 = X_Takte;
'Prescaler: Prescaler > X_Takte/65536
'Timer1_Anzahl_der_Takte: X_Takte/Prescaler = Timer_Anzahl_der_Takte
'Timer1 = 65536 - Timer_Anzahl_der_Takte
'-----------------------------------------------------------------------
--'
Wenn ich die Anzeit[ms] auf 2ms setze bekomme ich für den Prescaler 256
(> 244,14). Wenn ich dann z.B. COMPARE1A = 2 eingebe, heißt das, dass
der Servo dann ein Signal von 2ms bekommt und dann nach rechts fährt?
Hier mein Programm:
$regfile = "m16def.dat"
$crystal = 8000000
$baud = 19200
$hwstack = 32
$swstack = 8
$framesize = 24
Config Portd = Output
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm
= Clear Down , Prescale = 256
Do
Compare1a = 2
Loop
End
Was bedeutet Pwm = 8? Was würde passieren wenn ich den auf 9 oder 10
stelle?
Vielen Dank für die Hilfe! Tut mir Leid, wenn ich noch etwas länger auf
der Leitung stehe!
Viele Grüße
Ich glaube ich habe schon einen Fehler entdeckt, so müsste es sein,
oder?
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm
= Clear Down , Prescale = 256
Enable Timer
Start Timer
Warum eigentlich "dringend" ?
Das Problem, das sich mit einer PWM ergibt, ist daß bei PWM 8Bit nur 256
Stufen zur Verfügung stehen, und davon soll auch noch etwas die Pause
übrig sein. Also ist nur ein Teil der 256 Schritte für das Servosignal
nutzbar.
Eine reine Hardware PWM hat lediglich den Vorteil, daß sie keinerlei
Prozessorressourcen beansprucht.
Ich würd' einen anderen Ansatz nehmen, den Timer auf CLEAR TIMER = 1
konfigurieren, dann eine Compare-ISR aufsetzen und darin den
Compare1A-Wert abwechselnd auf die Puls- oder die Pause-Zeit setzen und
dabei den Servo-Pin entsprechend umschalten.
Das geht auch quasi im Hintergrund und schont die zur Verfügung stehende
Rechenleistung, braucht vielleicht 0.5% davon.
Solltest Du Deinen Hardware PWM Ansatz weiterverfolgen wollen, so wäre
die Rechnung bei 8MHz:
Servopuls 1-2ms, PWM 10Bit, Prescaler 64 = 8µs pro PWM-Stufe, ergibt für
1-2ms Werte von 62 - 128, mit einer Pulswiederholrate von 16,4ms.
Wichtig dabei ist zu wissen daß Bascom die Phase Correct PWM verwendet,
und die braucht doppelt so lange wie die Fast PWM, da sie rauf und
runterzählt, also bei PWM 10Bit von 0 bis 1023 und von 1023 bis 0.
Hey, vielen Dank, das werde ich mal probieren. Allerdings weiß ich nicht
genau, wie man das in einem Code schreiben kann, kannst du mir da evtl.
helfen? Muss ich dann das nehmen:
Config Timer1 = Counter , Edge = Falling , Compare A = Set , Compare B =
Toggle , Clear Timer = 1 ?
Würde das dann so aussehen? Ich habe noch mit der Syntax Probleme. :-(
Config Portd = Output
Condig Portb = Output
Config Timer1 = Counter , Edge = Falling , Compare A = Set , Compare B =
Toggle , Clear Timer = 1
Enable Timer1
Start Timer1
On Timer1 Isr_von_timer1
Do
Toggle Portb.0
Loop
End
Isr_von_timer1:
Compare1a = 2
Gruß Bascompasstschon
Wenn Du = Counter schreibst, dann wird der Prescaler abgeschaltet und
der Zähler erwartet das was er zählen soll am Pin, sollte T1 sein, aber
das willst Du sicher nicht.
Du braucht bei Clear Timer überhaupt keinen PWM Mode angeben, Clear
Timer arbeitet so, daß bei Eerreichen des Compare-Wertes der Zähler auf
0 gesetzt wird und wenn man es erlaubt hat, wird die Compare ISR
anesprungen. In dieser ISR kann man dann den neuen Comparewert setzen.
Syntax sollte in etwa so sein:
Config Timer1 = Timer, Prescale = 64, Clear Timer = 1
On Compare1A Comp1_ISR
Enable Compare1A
Enable Interrupts
...
Compare1A = 200 ' Wert, bei dem der Zähler rücksetzt und die ISR
aufgerufen wird
...
Comp1_ISR:
' Compare1A abwechselnd neu laden, usw.
Return
Ohne Gewähr, müsste es selbst testen. Versuch' doch mal, ob Du es so
hinbekommst, lass erst mal in der ISR 'ne Led blinken, nimm 'nen höheren
Prescaler, damit du's auch blinken siehst. Wenn das dann hinhaut, kannst
Du in der ISR beginnen den Comparewert abwechselnd neu zu laden.
Wenn das dann geht, hast Du Dein Ziel eigentlich schon erreicht.
Hallo Gerk!
Vielen Dank für deinen Code! Ich werde ihn morgen gleich ausprobieren
und werde versuchen alles zu verstehen! :-) Heute bin ich leider nicht
dazu gekommen, etwas zu machen!
Also, einen schönen Restsonntag! :-)
Bis dann!
Gruß Bascompasstschon