Forum: Mikrocontroller und Digitale Elektronik Servo Ansteuerung funktioniert nicht / Bascom


von Peter (Gast)


Lesenswert?

Hallo,

ich habe einen kleinen Code geschrieben (das meiste kopiert), der aber 
leider nicht funktioniert. Ich glaube das etwas mit der Timerbrechnung 
nicht stimmt. Also angeschlossen werden fünf Servos und mittels eines 
Interrups angesteuert. Der soll ja alles 20ms schalten.

Könnt ihr bitte mal drüberschauen, was da nicht passt? Wenn ich ein 
Servo anschließe, dreht es ein paar schritte in eine Richtung weiter und 
macht nichts mehr. Es fährt definitiv nicht in die Mitte!

DANKE
Lg
Peter
1
$regfile "m32def.dat"
2
$crystal = 8000000
3
$hwstack = 64
4
$swstack = 64
5
$framesize = 64
6
7
Config Pinc.1 = Output                                      'LCD
8
Config Pinc.0 = Output                                      'LCD
9
Config Pind.4 = Output                                      'LCD
10
Config Pind.5 = Output                                      'LCD
11
Config Pind.6 = Output                                      'LCD
12
Config Pind.7 = Output                                      'LCD
13
Config Pind.2 = Input                                       'Signal Eingang
14
15
Config Pina.7 = Output
16
Config Pinc.4 = Output
17
Config Pinc.5 = Output
18
Config Pinc.6 = Output
19
Config Pinc.7 = Output
20
21
22
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.7 , Db6 = Portd.5 , Db7 = Portd.6 , E = Portc.0 , Rs = Portc.1
23
Config Lcd = 20 * 2
24
Cursor Off
25
26
Config Timer1 = Timer , Prescale = 8                        'timer für servos
27
Enable Timer1
28
Timer1 = 45536
29
30
Portc.4 = 0                                                 'hier hängt servo1
31
Portc.5 = 0                                                 'hier hängt servo2
32
Portc.6 = 0                                                 'hier hängt servo3
33
Portc.7 = 0                                                 'hier hängt servo4
34
Porta.7 = 0                                                 'hier hängt servo4
35
36
On Timer1 Servoirq
37
Enable Interrupts
38
39
Dim Servo(5) As Word
40
Dim Kanal As Byte
41
Kanal = 0
42
43
Do
44
45
Servo(1) = 45535                                            'Mitte
46
Servo(2) = 45535                                            'Mitte
47
Servo(3) = 45535                                            'Mitte
48
Servo(4) = 45535                                            'Mitte
49
Servo(5) = 45535                                            'Mitte
50
51
52
Loop
53
End
54
55
Servoirq:
56
If Kanal = 0 Then
57
   If Portc.4 = 0 Then                                      'wenn port low
58
      Timer1 = Servo(1)                                     'dann timer auf entsprechende verzögerung
59
      Portc.4 = 1                                           'und port anschalten
60
   Else                                                     'das hier passiert erst bei dem darauf folgenden interrupt
61
      Portc.4 = 0                                           'dann port wieder ausschalten
62
      Incr Kanal                                            'und den nächsten kanal bearbeiten
63
   End If
64
End If
65
If Kanal = 1 Then
66
   If Portc.5 = 0 Then
67
      Timer1 = Servo(2)
68
      Portc.5 = 1
69
   Else
70
      Portc.5 = 0
71
      Incr Kanal
72
   End If
73
End If
74
If Kanal = 2 Then
75
   If Portc.6 = 0 Then
76
      Timer1 = Servo(3)
77
      Portc.6 = 1
78
   Else
79
      Portc.6 = 0
80
      Incr Kanal
81
   End If
82
End If
83
If Kanal = 3 Then
84
   If Portc.7 = 0 Then
85
      Timer1 = Servo(4)
86
      Portc.7 = 1
87
   Else
88
      Portc.7 = 0
89
      Incr Kanal
90
   End If
91
End If
92
If Kanal = 4 Then
93
   If Porta.7 = 0 Then
94
      Timer1 = Servo(5)
95
      Porta.7 = 1
96
   Else
97
      Porta.7 = 0
98
      Incr Kanal
99
   End If
100
End If
101
102
103
If Kanal = 4 Then
104
  Timer1 = 55536                                            '10ms pause damit ich auch 20ms komme
105
  Kanal = 0
106
End If
107
Return

von Karl H. (kbuchegg)


Lesenswert?

Peter schrieb:

> leider nicht funktioniert. Ich glaube das etwas mit der Timerbrechnung
> nicht stimmt.

Genau.

Wenn dein µC mit 8 Mhz Taktet und der Vorteiler auf 8 steht, dann zählt 
der Timer mit 1Mhz ( 8000000 / 8 )

Der Timer muss von 45535 bis 65536 hochzählen, das sind über den Daumen 
20000 Zählschritte.

Wie lang braucht er dafür, wenn er in 1 Sekunde bis 1 Mio zählen könnte?

20000 / 10000000 = 0.02 also 20 Millisekunden.

Das ist zu lang für den Servopuls. Der sollte für Mittelstellung bei ca 
1.5 Millisekunden sein und nicht bei 20


> Also angeschlossen werden fünf Servos und mittels eines
> Interrups angesteuert. Der soll ja alles 20ms schalten.

Bei 4 Servos hintereinander brauchst du den 20ms keine großartige 
Beachtung mehr schenken. Die sich ergebende Pause nach den Pulsen ist 
mit einiger Sicherheit lang genug, dass kein Servo mehr ins straucheln 
kommt. Zumindest ist mir noch nie eines untergekommen.

von Peter (Gast)


Lesenswert?

Hallo Karl Heinz,

danke für die Infos.

Nun gut, Mittelstellung ist 1,5ms. das wäre bei 1000000 hz =1500 
Zählschritte.

also 65536-1500=64036

Nun gut, leider funkt der Code dadurch auch noch nicht...

Für was genau ist der Timerwert am Anfang des programms? Also bei meinem 
Beispiel 45536? Das ist doch dafür da, dass alle 20ms die Signal 
ausgeschickt werden?

Und ganz unten im Programm ist nochmal ein Timer, der quasi die 20ms 
"auffüllt".Bei fünf Servos müssen da noch 10ms offen sein.

Kannst du bitte nochmal drüberschauen?

Sorry wenn ich lästig bin, bin noch Anfänger...
1
Config Timer1 = Timer , Prescale = 8                        'timer für servos
2
Enable Timer1
3
Timer1 = 45536
4
5
Portc.4 = 0                                                 'hier hängt servo1
6
Portc.5 = 0                                                 'hier hängt servo2
7
Portc.6 = 0                                                 'hier hängt servo3
8
Portc.7 = 0                                                 'hier hängt servo4
9
Porta.7 = 0                                                 'hier hängt servo4
10
11
On Timer1 Servoirq
12
Enable Interrupts
13
14
Dim Servo(5) As Word
15
Dim Kanal As Byte
16
Kanal = 0
17
18
Do
19
20
Servo(1) = 64035                                            'Mitte
21
Servo(2) = 64035                                            'Mitte
22
Servo(3) = 64035                                            'Mitte
23
Servo(4) = 64035                                            'Mitte
24
Servo(5) = 64035                                            'Mitte
25
26
27
Loop
28
End
29
30
Servoirq:
31
If Kanal = 0 Then
32
   If Portc.4 = 0 Then                                      'wenn port low
33
      Timer1 = Servo(1)                                     'dann timer auf entsprechende verzögerung
34
      Portc.4 = 1                                           'und port anschalten
35
   Else                                                     'das hier passiert erst bei dem darauf folgenden interrupt
36
      Portc.4 = 0                                           'dann port wieder ausschalten
37
      Incr Kanal                                            'und den nächsten kanal bearbeiten
38
   End If
39
End If
40
If Kanal = 1 Then
41
   If Portc.5 = 0 Then
42
      Timer1 = Servo(2)
43
      Portc.5 = 1
44
   Else
45
      Portc.5 = 0
46
      Incr Kanal
47
   End If
48
End If
49
If Kanal = 2 Then
50
   If Portc.6 = 0 Then
51
      Timer1 = Servo(3)
52
      Portc.6 = 1
53
   Else
54
      Portc.6 = 0
55
      Incr Kanal
56
   End If
57
End If
58
If Kanal = 3 Then
59
   If Portc.7 = 0 Then
60
      Timer1 = Servo(4)
61
      Portc.7 = 1
62
   Else
63
      Portc.7 = 0
64
      Incr Kanal
65
   End If
66
End If
67
If Kanal = 4 Then
68
   If Porta.7 = 0 Then
69
      Timer1 = Servo(5)
70
      Porta.7 = 1
71
   Else
72
      Porta.7 = 0
73
      Incr Kanal
74
   End If
75
End If
76
77
78
'If Kanal = 4 Then
79
'  Timer1 = 55536                                            '10ms pause damit ich auf 20ms komme
80
'  Kanal = 0
81
'End If
82
Return

von Karl H. (kbuchegg)


Lesenswert?

Peter schrieb:
> Hallo Karl Heinz,
>
> danke für die Infos.
>
> Nun gut, Mittelstellung ist 1,5ms. das wäre bei 1000000 hz =1500
> Zählschritte.
>
> also 65536-1500=64036
>
> Nun gut, leider funkt der Code dadurch auch noch nicht...

Hast du deine 8Mhz überprüft?

> Für was genau ist der Timerwert am Anfang des programms?
> Also bei meinem Beispiel 45536?

Für nix

> Und ganz unten im Programm ist nochmal ein Timer,

Im ganzen Programm gibt es nur 1 Timer, der nacheinander die Pulse in 
jedem Overflow Interrupt erzeugt. Die Zahl die jedesmal in den Timer 
geladen wird, betimmt die Zeit bis dann der nächste Overflow auftreten 
wird.

> Bei fünf Servos müssen da noch 10ms offen sein.
Die kannst du getrost ignorieren. Die sind nicht das Problem.

Wahrscheinlich wird dein Mega nicht mit 8Mhz arbeiten, sondern mit dem 
1Mhz mit dem er von Atmel ausgeliefert wird.

von MIR Mitentwickler (Gast)


Lesenswert?

oszillograph vorhanden ???

von Karl H. (kbuchegg)


Lesenswert?

Peter schrieb:
1
> 'If Kanal = 4 Then
2
> '  Timer1 = 55536                                            '10ms pause
3
> damit ich auf 20ms komme
4
> '  Kanal = 0
5
> 'End If
6
> Return
7
>

Du musst die Kanalnummer schon auf 0 setzen!
Sonst kommt da auf jedem Kanal nur 1 Puls raus!
Lass es erst mal so wie es ist (auch mit der Zuweisung an den Timer)

Das ganze lebt davon, dass die Variable Kanal nacheinander die Werte 0, 
1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, .... annimmt. Wenn du Kanal nie auf 0 
setzt ... von alleine passiert das nicht.

Da ist im Original übrigens ein Fehler.
Es muss
1
If Kanal = 5 then
2
  Timer1 = 55536
3
  Kanal = 0
4
end if

heissen, wenns 5 Servos sein sollen.

von Peter (Gast)


Lesenswert?

Hallo Karl Heinz,

vielen Dank!

Genau das war der Fehler. Funktioniert nun einwandfrei!

Kleiner Fehler mit großer Auswirkung ;o)
Lg
Peter

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.