Forum: Mikrocontroller und Digitale Elektronik Problem beim Ansteuern vom Servo


von Kai S. (luxell)


Lesenswert?

Hallo alle zusammen,
ich habe ein Problem. :D
Erst mal zur Hardware: Atmega8 mit 16 MHz, Servo von Graupner (C557) 
Standart.

Nun zu meinen Problem: Mein nächster Aufbau vom Atmega8 sollte ein Servo 
beinhalten. Also wollte ich zuerst versuchen ganz einfach den Servo 
anzusteuern. Von einer zur anderen Seite drehen um die Funktion vom 
Atmega8 und dem Servo zu verstehen. Hier nun mein Programm:
#include <avr/io.h>
#include "system.h"
#include <util/delay.h>
int main(void){
sei();
DDRB = 0b00000111;
PORTB = 0b00000000;
uint16_t x;
x=1;

ICR1   = 40000;
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11);
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);
TCNT1  = 0;
OCR1A  = 3000;    // Servo Mittelstellung

while(1){
if(OCR1A >= 2000){
x=1;
}
if(OCR1A <= 4000){
x=0;
}

if(x==1){
OCR1A  = OCR1A - 50;
_delay_ms(1000);
}else{
OCR1A  = OCR1A + 50;
_delay_ms(1000);
}
}
}

Die ersten Sekunden sieht es ganz gut aus. Der Servo dreht sich Schritt 
für Schritt nach links. Aber dann, wenn er anscheint bis zum Anschlag 
kommt, dreht er sich fast bis zu anderen Seite und bewegt sich wider 
schritt für schritt nach links. Also grundsätzlich ein ganz komisches 
Verhalten. Ich wollte aber nur eine schrittförmige hin und her Funktion 
haben. Wo liegt nun mein Denkfehler?
Muss ich überhaupt ein „Nicht invertierten PWM“ einstellen. Weil der Pin 
soll ja nur bei erreichen des OCR1A umschalten und sonst nicht. Oder 
liegt hier ein dummer Anfängerfehler vor???
Und ja, in anderen Foren und im Internet habe ich auch schon 
nachgeforscht, aber leider auf kein besseres Ergebnis gekommen.

von Karl H. (kbuchegg)


Lesenswert?


von Peter B. (pbuenger)


Lesenswert?

Guck Dir Deine Grenzwertabfragen nochmal genau an, die sind so wohl 
ziemlich sinnlos.

Peter

von Kai S. (luxell)


Lesenswert?

Danke erst mal für eure schnellen Antworten.

Die Seite Modellbauservo Ansteuerung habe ich mir schon angesehen. Aber 
ich wollte ja den Servo nicht mit einem Taster ansteuern oder mit einer 
Delay- Schleife. Aber vielleicht versuche ich das heute Mittag doch mit 
Taster aus.

Und danke Peter. Ja, dummer Anfängerfehler. Werde das schnellstmöglich 
korrigieren und ausprobieren.

Danke für eure Hilfe. Werde mich noch mal melden.

von Kai S. (luxell)


Lesenswert?

Habe es ausprobiert. Leider ohne Erfolg. Werder mein korrigiertes 
Programm noch das 2 Programm von Modellbauservo Ansteuerung mit 
veränderten Werten funktioniert richtig. Das Einzige was ich hin bekomme 
ist, den Servo auf eine Position zu setzen und den dann dort lassen. 
Aber ich möchte den ja bewegen. Wo könnte dann mein Fehler sein???

von Peter B. (pbuenger)


Lesenswert?

> Wo könnte dann mein Fehler sein???

In Zeile 43. Oder anders gesagt, wie soll das jemand beurteilen, ohne 
Deinen Code zu kennen?

Peter

von Reinhard R. (reirawb)


Lesenswert?

Kai S. schrieb:
> while(1){
> if(OCR1A >= 2000){
> x=1;
> }
> if(OCR1A <= 4000){
> x=0;
> }
Also... wenn der Wert OCR1A z.B. 3000 ist, dann sind beide if-Abfragen 
wahr, es ist sowohl >= 2000 als auch <= 4000, d.h. X bleibt am Ende "0". 
Ändern in:

while(1){
if(OCR1A <= 2000){
         ^
x=1;
}
if(OCR1A >= 4000){
         ^
x=0;
}


> if(x==1){
> OCR1A  = OCR1A - 50;
> _delay_ms(1000);
> }else{
> OCR1A  = OCR1A + 50;
> _delay_ms(1000);
Wenn x==1 ist, ist das niedrigste Level erreicht, also mußt Du dann hoch 
zählen. Bei x==0 runter. Ändern in:

if(x==1){
OCR1A  = OCR1A + 50;
               ^
_delay_ms(1000);
}else{
OCR1A  = OCR1A - 50;
               ^
_delay_ms(1000);

Viel Erfolg.

Reinhard

von Kai S. (luxell)


Lesenswert?

Danke Reinhard für deine Antwort.
Stimmt. Dumme Fehler. Habe ich berichtig und dann ausprobiert. Doch auch 
hier wider ohne Erfolg. Der Servo ruckelt mehr oder weniger und bewegt 
sich nur minimal in einem kleinen Radius. Aber nicht so wie er soll. 
Über AVR hab ich mir den OCR1A auslesen lassen und musste feststellen, 
dass er beim Überschreiten von 512 wider bei 0 anfängt. Das war mir 
bisher unbekannt und würde auch das Verhalten erklären. Aber kann das 
sein???

Aus diesem Grund habe ich mal alle Werte geändert und den CK-Teiler auf 
64 gestellt. So konnte der OCR1A nur bis 500 bei 2 Sekunden gehen und 
damit keinen überschlag machen. Aber auch hier musste ich leider 
feststellen, dass es ganz und gar nicht funktioniert. :(

Hier noch mal mein Programm mit neuen Werten:

#include <avr/io.h>
#include "system.h"
#include <util/delay.h>
int main(void){
sei();
DDRB = 0b00000111;
PORTB = 0b00000000;
uint16_t x,y;
x=1;
//init timer 1:
ICR1   = 5000;
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11);
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11) | (1<<CS10);
TCNT1  = 0;
OCR1A  = 375;    // set Servo 1 to 2ms-position
OCR1B  = 375;    // set Servo 1 to 2ms-position
y = OCR1A;
while(1){
if(OCR1A <= 250){
x=1;
}
if(OCR1A >= 500){
x=0;
}
if(x==1){
OCR1A  = OCR1A + 10;
_delay_ms(1000);
}else{
OCR1A  = OCR1A - 10;
_delay_ms(1000);
}
y = OCR1A;
OCR1B  = 375;
}
}

Kann das nun wirklich sein das der OCR1A bei 512 überspringt und bei 0 
wider anfängt?
Und hab ich noch ein Fehler, der erklärt, warum der Servo nicht das 
macht was er soll?

von Reinhard R. (reirawb)


Lesenswert?

Kai S. schrieb:
> Und hab ich noch ein Fehler, der erklärt, warum der Servo nicht das
> macht was er soll?
Ich kann Dir da leider nicht weiter helfen, da meine C-Kenntnisse eher 
rudimentär sind. Ich programmiere in Assembler. Habe aber gerade in 
letzter Zeit selbst so eine Ansteuerung für ein Servo programmiert. Hat 
auch funktioniert.
Das Impulsdiagramm sollte Dir ja bekannt sein:
Der Impuls soll eine Länge von 1..2ms (Stellung des Servos) haben, bei 
einem Impulsabstand von etwa 20ms. Mein Servo hat bei 0,7ms und 2,4ms 
seine Begrenzung. Ist so ein Billigst-Servo vom großen C für 2.95 Euro.

    ------                            ------
   |      |                          |      |
   |      |                          |      |
---        --------------------------        ----------------
   |1..2ms|                          |
   |             20ms                |

Wie schon gesagt, reichen meine C-Kenntnisse nicht aus, um Dein Programm 
auf die Einhaltung dieses Impulsdiagramms hin zu analysieren, mir waren 
nur die Fehler in der Logik aufgefallen :-(
Wo entsteht denn die 20ms-Impulsfolge? Hilfreich wäre auch ein 
Oszillogramm von dem steuernden Portpin.

Reinhard

von Karl H. (kbuchegg)


Lesenswert?

Machs doch erst mal nicht so kompliziert. (Und ein paar Einrückungen 
würden deinem Code auch nicht schaden. Schon seltsam: Die mit dem 
grauslichsten unübersichlichsten Code machen immer die dümmsten Fehler)

1
  OCR1A  = 375;
2
3
  while(1) {
4
5
    while( OCR1A < 500 ) {
6
      OCR1A += 10;
7
      _delay_ms( 1000 );
8
    }
9
10
    while( OCR1A > 250 ) {
11
      OCR1A -= 10;
12
      _delay_ms( 1000 );
13
    }
14
  }


> Kann das nun wirklich sein das der OCR1A bei 512 überspringt
> und bei 0 wider anfängt?

Nein, kann nicht sein.


> Der Servo ruckelt mehr oder weniger und bewegt
> sich nur minimal in einem kleinen Radius.

Hast du eine vernünftige Spannungsversorgung?
Wenn du die nicht hast, dann bricht dir jedesmal, wenn der Servomotor 
anläuft, die Versorgungsspannung ein.
Hast du 100nF Kondensatoren an den Versorgungspins des Mega8

von Tip (Gast)


Lesenswert?

Kai S. schrieb:
> Und hab ich noch ein Fehler, der erklärt, warum der Servo nicht das
> macht was er soll?Beitrag melden | Bearbeiten | Löschen |

Das blöde ist, das Rechner prinzipiell immer das machen, was man ihnen 
sagt, aber nicht unbedingt das, was sie sollen.

;-)

von Karl H. (kbuchegg)


Lesenswert?

Hast du kontrolliert, ob dein 16Mhz Quarz überhaupt benutzt wird?

Led an einen Pin anschliessen und
1
#define F_CPU 16000000UL
2
3
#include ....
4
5
....
6
7
int main()
8
{
9
10
  ....
11
12
  while( 1 ) {
13
    _delay_ms( 1000 );
14
    Pin auf 1
15
    _delay_ms( 1000 );
16
    Pin auf 0
17
  }

Die LED muss 1 Sekunde an, 1 Sekunde aus sein. (Mit freiem Auge 
kontrollieren genügt.)
Wenn nicht, dann stimmt deine Takteinstellung nicht

von Peter B. (pbuenger)


Lesenswert?

Ich könnte mir vorstellen, dass die ganzen Vergleiche und 
Rechenoperationen direkt auf das OCR-Register die Probleme machen, ist 
ja schließlich ein besonderes 16Bit Register. Probiere doch mal aus, die 
Positionen in Variablen zu halten und nur bei Änderungen ein einziges 
Mal auszugeben.

Ausserdem kriegst Du möglicherweise einen ungleichmäßigen Lauf der 
Servos, weil Du das Updaten der OCR-Register nicht synchron zum Timer 
machst. Ich benutze da den Compare Match Interrupt, um das OCR genau 
dann upzudaten.

Peter

von Karl H. (kbuchegg)


Lesenswert?

@Peter

Kann er versuchen, ist aber alles kein wirkliches Problem. Der Update 
des eigentlich benutzten Compare Match Registers macht sich der Timer 
aus OCR1A selber, wenn der Timer bei BOTTOM ist. Und wenn der OCR Wert 
mal 20 ms (also 1 Zyklus) zu spät verändert wird, ist das jetzt auch 
noch kein Problem (bei 1 Sekunde Wartezeit bis zum nächsten Update).

von Kai S. (luxell)


Angehängte Dateien:

Lesenswert?

Jetzt hab ich es.
Vorweg. Es funktioniert :D.
Zu Karl: Danke für deine Kritik. Ich werde sie mir zu Herzen nehmen um 
so weniger Fehler zu verursachen. Und ja, die Taktung von meinen Board 
ist richtig. Hab das mit der LED ausprobiert. Funktioniert wie eine Uhr.

Reinhard: Wie ein Servo funktioniert und angesteuert werden soll weiß 
ich schon. Aber trotzdem danke dir und für deine Zeichnung.

Ich vermute wirklich dass es an der Spannungsversorgung lag. Ich hab die 
Pins weiter weg vom µc angeschlossen und zwar näher an der 
Spannungsversorgung. Gleichzeitig hab ich auch noch mehr "Saft" auf mein 
Netzgerät gegeben. Und siehe da, es läuft. Endlich.

Ich danke euch, für eure hilfreichen Beiträge bei so einem dummen 
Problem.

Gruß Kai

PS.: Bevor ich es vergesse.

Kai S. schrieb:
> Kann das nun wirklich sein das der OCR1A bei 512 überspringt und bei 0
> wider anfängt?
> Und hab ich noch ein Fehler, der erklärt, warum der Servo nicht das
> macht was er soll?

Von meinen Lehrer habe ich erfahren das AVR in Modus 14 beim PWM mit dem 
ATmega8 Probleme macht und nicht so reagiert wie er soll. Daher 
anscheint der Überlauf bei 512.

von spess53 (Gast)


Lesenswert?

Hi

>Von meinen Lehrer habe ich erfahren das AVR in Modus 14 beim PWM mit dem
>ATmega8 Probleme macht und nicht so reagiert wie er soll. Daher
>anscheint der Überlauf bei 512.

Nicht der AVR, sondern nur der Simulator.

MfG Spess

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.