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.
Guck Dir Deine Grenzwertabfragen nochmal genau an, die sind so wohl ziemlich sinnlos. Peter
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.
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???
> Wo könnte dann mein Fehler sein???
In Zeile 43. Oder anders gesagt, wie soll das jemand beurteilen, ohne
Deinen Code zu kennen?
Peter
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
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?
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
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
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. ;-)
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
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
@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).
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.