Forum: Mikrocontroller und Digitale Elektronik Digital-Servo Futaba S3151 am ATMega48


von Axel L. (ligonap)


Lesenswert?

Ich möchte gerne einen Digital-Servo Futaba S3151 mit einem ATMega48 
betreiben. Der µC und der Servo hängen an der selben 5V-Spannungsquelle.
Das Steuerkabel ist direkt mit dem Port PB1 (OC1A / Pin 13) verbunden.
Den µC betreibe ich mit 16MHz (Quarz).

Ich habe es mit folgendem Programm versucht, aber nix tut sich:
1
void servo_init()
2
{
3
4
  TCCR1B = 0x00;
5
  TCCR1B = (1<<CS11) | (1<<WGM13);
6
   ICR1  = 20000; 
7
  TCCR1A = (1<<COM1A1) ;
8
  OCR1A  = 1222;  //default position  1,222ms = -25°
9
}
10
11
12
int main()
13
{
14
15
DDRB = 0b00000010;
16
17
servo_init();
18
19
while (1)
20
{
21
delay_ms(1000);
22
OCR1A  = 1778; // 1,778ms = 25°
23
24
delay_ms(1000);
25
OCR1A  = 1222;  // 1,222ms = -25°
26
27
}
28
}

Folgende Fragen habe ich dazu:

- Kann man den Servo direkt mit dem µC verbinden oder muss ich einen 
Widerstand (4,7K; ähnlich wie bei der Ansteuerung eines BC548C) 
zwischenschalten?

- Die "Low Fuse"-Einstellung ist standardmäßig auf "Divide clock by 8 
internally" und "Int. RC Osc. 8MHz; Start-Up time PWRDWN/RESET: 6 CK/14 
CK + 65 ms". Letztere habe ich geändert auf "Ext. Full-swing Crystal; 
Start-Up time PWRDWN/RESET: 16 CK/14 CK + 65 ms". Korrekt??

- Ist er Timer TCCR1A richtig eingestellt?

von Karl H. (kbuchegg)


Lesenswert?

Axel L. schrieb:

> - Kann man den Servo direkt mit dem µC verbinden

ja

> - Die "Low Fuse"-Einstellung ist standardmäßig auf "Divide clock by 8
> internally" und "Int. RC Osc. 8MHz; Start-Up time PWRDWN/RESET: 6 CK/14
> CK + 65 ms". Letztere habe ich geändert auf "Ext. Full-swing Crystal;
> Start-Up time PWRDWN/RESET: 16 CK/14 CK + 65 ms". Korrekt??

Sieht richtig aus.
Überprüfe es, indem du eine LED mittels _delay_ms im 1 Sekunden Takt 
blinken lässt. Wenn deine F_CPU Angabe mit der tatsächlichen Taktrate 
übereinstimmt, dann blinkt die LED auch mit 1 Sekunde. Ansonsten bei 4 
Mhz zb 4 mal so schnell oder 4 mal so langsam. etc. Auf jeden Fall: mit 
freiem Auge und ohne Messgerät erkennbar abweichend von 1 Sekunde.

> - Ist er Timer TCCR1A richtig eingestellt?

Lass mich das Datenblatt und deine Berechnung checken.

von Karl H. (kbuchegg)


Lesenswert?

Was steckt hinter der Idee, eine Phase/Frequency korrekte PWM zu 
benutzen? Ich wüsste jetzt auf Anhieb nicht, wie die die Dinge 
vereinfachen würde.

Modus 14 wäre zb ein guter Modus. Fast PWM mit Top Wert in ICR1

Aber abgesehen davon sollte auch der Phase/COrrect Mode gehen. Deine 
Berechnung scheint richtig zu sein und auch an der Pin Einstellung kann 
ich nichts entdecken.

von Axel L. (ligonap)


Lesenswert?

Karl heinz Buchegger schrieb:

> Überprüfe es, indem du eine LED mittels _delay_ms im 1 Sekunden Takt
> blinken lässt. Wenn deine F_CPU Angabe mit der tatsächlichen Taktrate
> übereinstimmt, dann blinkt die LED auch mit 1 Sekunde. Ansonsten bei 4
> Mhz zb 4 mal so schnell oder 4 mal so langsam. etc. Auf jeden Fall: mit
> freiem Auge und ohne Messgerät erkennbar abweichend von 1 Sekunde.

Habe den Test gemacht. LED geht regelmäßig nach einer Sekunde an und 
wieder aus. Scheint taktmäßig alles OK zu sein.

Folgenden Code habe ich dazu verwendet:
1
void delay_ms(int ms) 
2
{
3
4
  TCCR0B |= (1<<CS01) | (1<<CS00) ;
5
  int i ;
6
  for(i=0; i<ms; i++) {
7
8
    while(TCNT0<16) ;
9
    TCNT0=0;
10
  }
11
  TCCR0B=0;
12
}
13
14
int main()
15
{
16
17
DDRC = 0b00100000;
18
19
while (1) 
20
{
21
  PORTC |= (1<<PC5) ;
22
  delay_ms(1000);
23
  PORTC &= ~(1<<PC5) ;
24
  delay_ms(1000);
25
}
26
27
}

von sven (Gast)


Lesenswert?

Ich hatte auch mal ein billiges Digitalservo auf dem Steckbrett mit 
Controller + Batterieversorgung betrieben : Das Servo oszillierte und 
drehte sich von einem Anschlag zum anderen obwohl ein konstanter 
PWM-Wert ausgegeben wurde - mit einem Analogservo funktionierte es.
Erst eine gesonderte Akkuversorgung für das Digitalservo hat geholfen - 
Digitalservos brauchen wesentlich mehr Spitzenstrom, so dass die 
Spannungsversorgung zusammenbricht (was in meinem Fall das Servo aber 
nicht den Controller gestört hat).

von Axel L. (ligonap)


Lesenswert?

sven schrieb:
> Ich hatte auch mal ein billiges Digitalservo auf dem Steckbrett mit
> Controller + Batterieversorgung betrieben : Das Servo oszillierte und
> drehte sich von einem Anschlag zum anderen obwohl ein konstanter
> PWM-Wert ausgegeben wurde - mit einem Analogservo funktionierte es.
> Erst eine gesonderte Akkuversorgung für das Digitalservo hat geholfen -
> Digitalservos brauchen wesentlich mehr Spitzenstrom, so dass die
> Spannungsversorgung zusammenbricht (was in meinem Fall das Servo aber
> nicht den Controller gestört hat).

Servo und µC werden von der selben Batterie (5V) versorgt. Im übrigen 
habe ich den Servo an einem Robbe R137F Empfänger getestet, welcher auch 
nur eine 4,8V-Versorgung hat. Test war OK.

Ich tippe mal auf einen Programmfehler.

von Axel L. (ligonap)


Lesenswert?

Was bedeutet exakt die "Low Fuse"-Einstellung "Divide clock by 8
internally"??  Zumal ja im TCCR1B mit (1<<CS11) ein Prescaler von 8 
eingestellt wird. Habe ich dann keine 16Mhz mehr sondern nur 2 MHz?

von 8AF6lUf8OT (Gast)


Lesenswert?

wenn F_CPU 16e6 ist und dein delay_ms(1000) eine Sekunde, sollte das 
nicht die Ursache sein.

von Karl H. (kbuchegg)


Lesenswert?

Häät ich mal bloss dein Delay-Progamm kontrolliert.

Das macht nicht das, was du denkst.

Ein einfaches Testprogramm hätte so ausgesehen
1
#define F_CPU 1600000
2
 
3
#include <avr/io.h>
4
#include <util/delay.h>
5
 
6
#define LED_PORT    PORTC
7
#define LED_DDR     DDRC
8
#define LED_PIN     PC5
9
 
10
int main()
11
{
12
  LED_DDR |= (1<<LED_PIN);
13
 
14
  while( 1 ) {
15
    LED_PORT ^= (1<<LED_PIN);
16
    _delay_ms(1000);
17
  }
18
}

je weniger künsteln, desto besser. Je weniger Fehlermöglichkeiten, desto 
besser (dein Timer-Testprogramm hat keinen Vorteiler von 1024, wie alle 
angenommen haben, sondern einen Vorteiler von 64)

Wenn du die CKDIV8 Fuse mitlrweile nicht ausgeschaltet hast, wrst du 
damit nämlich merken, dass die 1 Sekunde keineswegs stimmt.

Dein µC läuft mit 2 Mhz, durch die interne Teilung durch 8. Die muss 
abgeschaltet werden.

von Axel L. (ligonap)


Lesenswert?

Jo das ist es. Ich habe die "Low Fuse"-Einstellung "Divide clock by 8
internally" heraus genommen und schupps stimmen die Delay-Zeiten nicht 
mehr, aber dafür bewegt sich der Servo. ;-)
Ich ändere eigentlich nie die Low Fuse, daher meine Nachfrage.
Werde mal den Teiler neu einstellen.

von Axel L. (ligonap)


Lesenswert?

Durch die Änderung der "Low Fuse" läuft der ATMega48 nun mit 16MHz. Der 
Delay-Timer musste ich dann auch ändern. Nun läuft alles so wie es soll. 
Dank an alle, die mir geholfen haben.

1
void delay_ms(int ms) 
2
{
3
4
  TCCR0B |= (1<<CS02) | (1<<CS00) ;
5
  int i ;
6
  for(i=0; i<ms; i++) {  
7
8
    while(TCNT0<8);  
9
    TCNT0=0; 
10
  }
11
  TCCR0B=0; 
12
}
13
14
15
void servo_init()
16
{
17
18
  TCCR1B = 0x00;
19
  TCCR1B = (1<<CS11) | (1<<WGM13);
20
   ICR1  = 20000; 
21
  TCCR1A = (1<<COM1A1) ;
22
  OCR1A  = 1270;  // Servo Startposition
23
}
24
25
26
int main()
27
{
28
29
DDRB = 0b00000010;
30
31
servo_init();
32
33
while (1)
34
{
35
delay_ms(1000);
36
OCR1A  = 1880; // Erste Position
37
38
delay_ms(1000);
39
OCR1A  = 1270; // Zweite Position
40
41
}
42
}

von Karl H. (kbuchegg)


Lesenswert?

für diese delays brauchst du doch keinen Timer verschwenden!

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.