Forum: Mikrocontroller und Digitale Elektronik servo ansteuerung dringend


von Bascompasstschon (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

SChon mal die BASCOM Doku gelesen?

BASCOM kann aus dem STand heraus Servos ansteuern.
siehe zb
http://halvar.at/elektronik/servo_mit_bascom_avr/

von Bascompasstschon (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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

von Bascompasstschon (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Bascompasstschon (Gast)


Lesenswert?

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

von Bascompasstschon (Gast)


Lesenswert?

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

von Bascompasstschon (Gast)


Lesenswert?

Ich habe nur einen Servo

von MWS (Gast)


Lesenswert?

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.

von Bascompasstschon (Gast)


Lesenswert?

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

von MWS (Gast)


Lesenswert?

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.

von Bascompasstschon (Gast)


Lesenswert?

Oh klasse, vielen Dank für die Hilfe! :-) Das werde ich dann so 
probieren! :-)

von GerK (Gast)


Lesenswert?

Hallo!

Hier ein Auszug aus meinem Servotester mit 3 Tasten.
1
$regfile = "m88def.dat"
2
$crystal = 16000000
3
$hwstack = 48
4
$swstack = 32
5
$framesize = 32
6
7
 Ddrb = &B00000001                     'Portb.0 Ausgang für Servo
8
Portb = &B11111110                     'Pullups Portb
9
10
Dim Comp_b As Word
11
Dim Count As Word
12
13
14
Config Timer1 = Timer , Prescale = 8 , Compare A = Disconnect , Compare B = Disconnect , Clear Timer = 1
15
16
17
Enable Oc1a
18
On Oc1a Testa
19
20
Enable Oc1b
21
On Oc1b Testb
22
23
Compare1a = 39999                                '20ms
24
Compare1b = 2499                                 '449=linker Anschlag_4999=rechter Anschlag_2499=Mitte
25
26
Enable Interrupts
27
28
Do
29
30
If Pinb.5 = 0 Then
31
   Compare1b = 449
32
End If
33
34
If Pinb.4 = 0 Then
35
   Compare1b = 4999
36
End If
37
38
If Pinb.3 = 0 Then
39
   Compare1b = 2499
40
End If
41
42
Loop
43
End
44
45
Testa:
46
47
Portb.0 = 1
48
49
Return
50
51
Testb:
52
53
Portb.0 = 0
54
55
Return

Code dient nur zur Funktionserklärung.
Die Werte müssen natürlich an das verwendete Servo angepasst werden.

MfG

von Bascompasstschon (Gast)


Lesenswert?

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

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.