Forum: Mikrocontroller und Digitale Elektronik Problem mit Servo an einem Atmega8


von Niko (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich habe ein Programm zur Kontrolle eines Servos an einem Atmega8 
geschrieben (siehe Anhang).

Die Kontrolle des Servos funktioniert, die UART-Verbindung geht auch, 
aber ich kann die Stellung des Servos nicht über den UART (oder 
sonstwie) verändern.

Sobald ich dem Atmel ein Zeichen sende (0,1 oder 2) zuckt der Servo 
zwar, aber sonst passiert nichts. Wenn ich dem Servo wiederholt z.B. '0' 
sende, bewegt er sich zitternd um ein paar Grad nach Links, aber sobald 
ich aufhöre die Zeichen zu senden geht er wieder in die Mittelstellung.

Bei meinen zahlreichen Versuchen den Fehler zu finden, bin ich außerdem 
auf folgendes gekommen:
Wenn ich über den UART nicht die Position des Servos verändern möchte, 
sondern lediglich die LEDs an PORTC ein- oder ausschalten will, so 
funktioniert das nur, wenn der Code für den Servo auskommentiert ist.
1
  DDRC=255;  //PORTC als Ausgang, PC0-PC3 mit PullUp (Startzustand)
2
  PORTC=15;
3
4
  while(1)
5
  {
6
    if(x==0) PORTC=0; else
7
    if(x==1) PORTC=255;
8
  }

Wenn der Servo aktiviert ist tritt das gleiche Phänomen wie zuvor auf 
(Die LEDs flimmern nur kurz auf und werden dann wieder in den 
Startzustand versetzt).

Das Problem tritt auch dann auf, wenn der Servo nicht angeschlossen ist, 
also bin ich mir sicher, dass es nicht an zu hohem Stromverbrauch des 
Servos liegt.

lg
Niko

von Timmo H. (masterfx)


Lesenswert?

Ist in Mode 14 nicht ICR1 TOP?
Und wieso machst du die UART-Abfrage interrupt gesteurt? Kannst doch 
direkt in der while-Schleife einbinden.
Wer hat dir die Schreibweise in C beigebracht? Ist ja furchtbar
Was ist besser lesbar?
1
while(1)
2
{
3
  if(x==0) OCR1A=Links; else
4
  if(x==1) OCR1A=Mitte; else
5
  if(x==3) OCR1A=Rechts;
6
}
oder
1
while(1)
2
{
3
  if(x==0) 
4
    OCR1A=Links;
5
  else if(x==1) 
6
    OCR1A=Mitte; 
7
  else if(x==3) 
8
    OCR1A=Rechts;
9
}
oder sogar
1
while(1)
2
{
3
switch(x){ 
4
  case 0:
5
    OCR1A=Links;
6
    break;
7
  case 1: 
8
    OCR1A=Mitte; 
9
    break;
10
  case 3: 
11
    OCR1A=Rechts;
12
    break;
13
  default:
14
    OCR1A=Standard;
15
}

von Niko D. (niko)


Lesenswert?

Danke für deine Antwort,

Timmo H. wrote:
> Ist in Mode 14 nicht ICR1 TOP?

Ja, ICR1 ist Top (bei mir 20000) und mit OCR1A verändere ich die 
Pulsweite, oder ist das falsch?

> Und wieso machst du die UART-Abfrage interrupt gesteurt? Kannst doch
> direkt in der while-Schleife einbinden.

In der while-Schleife sind später andere Dinge vorgesehen, und was 
spricht gegen einen Interrupt?
Wenn ich direkt in der Schleife vom UART lese, ändert sich auch nichts.

> Wer hat dir die Schreibweise in C beigebracht? Ist ja furchtbar
> Was ist besser lesbar?

Meiner Meinung nach ist meine Schreibweise die leichter lesbare, aber 
das ist wohl Ansichtssache.

lg Niko

von Peter B. (pbuenger)


Lesenswert?

Lass mal nachrechnen:

Du hast einen Quartz von 12MHz und an der PWM einen Vorteiler von 8. Das 
gibt eine Auflösung von 666ns. Wenn Du nun in ICR1 20000 schreibst, 
erhältst Du eine Frametime von 13ms statt üblicherweise 20ms. Damit 
können einige Servos schon Probleme haben.

Die OCR-Werte schreibst Du mit 350, 1730 und 3100, was einer Pulsdauer 
von 0,2ms 1,1ms und 2,0ms entspricht. Die letzten beiden Werte sind 
brauchbar, aber mit den 0,2ms kann kein Servo was anfangen.

Üblich sind folgende Zeiten: 0,9ms / 1,5ms / 2,1ms mit einer Frametime 
von 20ms.

Gruß,
Peter

von Niko D. (niko)


Lesenswert?

Peter Bünger wrote:
>Wenn Du nun in ICR1 20000 schreibst, erhältst Du eine Frametime von 13ms
>statt üblicherweise 20ms. Damit können einige Servos schon Probleme haben.

Ich hab es jetzt auf 30000 geändert, das dürfte den 20ms entsprechen

> Die OCR-Werte schreibst Du mit 350, 1730 und 3100, was einer Pulsdauer
> von 0,2ms 1,1ms und 2,0ms entspricht. Die letzten beiden Werte sind
> brauchbar, aber mit den 0,2ms kann kein Servo was anfangen.

Meiner kann damit was anfangen (Robbe S3003)! Die Werte passen alle, 
jedenfalls kann ich mit Werten zwischen ~300 und ~3000 alle Positionen 
des Servos anfahren ohne das er Probleme macht.


Danke

Niko

von Niko D. (niko)


Lesenswert?

Irgendetwas läuft da komplett falsch...

Ich habe jetzt mal testweise den Prescaler auf 1024 gesetzt und in der 
Endlosschleife lasse ich PORTC, an dem LEDs hängen, hochzählen.

Man sieht jetzt deutlich, dass jedes Mal wenn der PWM-Generator PB1 
umschaltet der Controller resettet wird (PORTC zählt wieder ab 0). woran 
kann das liegen?

Kann es sein, dass ich noch irgendwo eine ISR definieren muss, weil der 
default Interrupt Vektor ja den Controller resettet?

Wenn es hilft, poste ich gerne den Code und/oder ein Video.

Danke für eure Hilfe

von Niko D. (niko)


Lesenswert?

Ich habe das Problem gerade beheben können.

Der Fehler war ein Hardwarebedingt: Der PWM-Pin PB1 ist bei meinem Board 
auf den Reset PIN-gejumpert (fälschlicherweise).

Seit dem Entfernen des Jumpers, funktioniert alles wie erwartet!

Danke für eure Mithilfe

Niko

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.