Hallo, ich habe versucht 2 Servos mit dem Atmega88 zu steuern. Dabei arbeite ich zum ersten mal mit einem Timer (wie man bestimmt auch im Quellcode sieht :D).Beim Ausführen bewegen sich die Servos aber nur für ca 1/2 sec nachdem ich den mega88 resete(1mal reset = 1/2 bewegung der Servos). Ansosnten hört man ein brummen in den Servos. -Habe den Timer nicht ganz genau bekommen. Problem? Vllt ist es so wie ich es programmiert habe gar nicht möglich einen Servo zu betreiben.Hoffe ihr könnt mir vllt sagen was ich Falsch gemacht habe. Danke
Hallo,
>-Habe den Timer nicht ganz genau bekommen. Problem?
nein, kein Problem. Du solltest nur deine Impulse etwa alle 20ms
widerholen.
Aber:
Du solltest anstatt des CTC - Modes lieber einen der PWM Modi benutzen.
Im CTC wird jede Änderung der OCR1x Register sofort geschrieben.
Dadürch könntest Du extrem kurze oder auch lange Servoimpulse erzeugen.
Ich würde Dir den Mode 14 (Fast-PWM) und einen prescaler von 8
empfehlen. Dann hast Du 2304 Ticks/ms. Damit bekommst Du sowohl den
Servoimpuls (1,1 - 1,9ms) als auch die Rahmenzeit von ca. 20ms locker in
die Auflösung des Timers.
Beispiel:
1 | void T1_init(void) { |
2 | DDRB |= 1<<PB1 | 1<<PB2; //OC-Pins auf Ausgang |
3 | ICR1 = 46080; //Rahmenzeit 20ms |
4 | //OutputCompare auf Portpins, Timer Mode 14, Prescaler 8
|
5 | TCCR1A |= 1<<COM1A1 | 1<<COM1B1 | 1<<WGM11; |
6 | TCCR1B |= 1<<WGM13 | 1<<WGM12 | 1<<CS11; |
7 | }
|
Jetzt musst Du nur noch OCR1A und OCR1B mit sinnvollen Werten füttern. Buffern und so Weiter übernimmt der Mega88 für Dich. Ich hoffe es hilft... gruß, Stefan
Danke, also war mein Problem das der Servoimpulse nicht genau alle 20ms kam? Werde heute noch deinen Timer ausprobieren und berichten.
Aloha schrieb: > Danke, also war mein Problem das der Servoimpulse nicht genau alle 20ms > kam? Werde heute noch deinen Timer ausprobieren und berichten. Probiers aus. Aber normalerweise sind die 20ms noch das Variabelste in einer Servoansteuerung. Servos stören sich nicht daran, ob der Stell-Puls alle 20ms oder alle 16 oder 18 oder 22 oder 12ms kommt. Die 20ms resultieren aus der Übertragungstechnik auf der Funkstrecke und haben sich daraus ergeben. Für das Servo selbst haben sie kaum bis keine Bedeutung. Servos knurren auch schon mal, wenn das Rückmeldepoti 'blöd steht'. Kennt jeder mit einer Fernsteuerung: Schieb den Gas-Knüppel am Sender um eine Rastung weiter (egal in welche Richtung) und sofort hört das Knurren auf.
Hallo, >Servoansteuerung. Servos stören sich nicht daran, ob der Stell-Puls alle >20ms oder alle 16 oder 18 oder 22 oder 12ms kommt. Da gebe ich Dir Recht. Aber ich denke dass nicht jedes Servo mit kurzen Impulswiederholungen klar kommt. Die 20ms sind halt Quasi-Standard. @Aloha: Die 20ms kommen zustande, weil im ursprünglichen PPM - Übertragungsverfahren 8 Kanäle sequenziell übertragen wurden. 8x2,1ms + 8xPause + Synchronuisation entsprechen etwa 20ms. Gruß, Stefan
So habe den Quellcode an deinen Timer ,Stefan, angepasst. Hoffe ich habe alles richtig verstanden. Die Batterien sind zum laden gelegt. Dann werde ich es mal an den Servos probieren.
Die Servos bewegen sich super! Jedoch beide bis an den 180° Anschlag sehr komisch. Komme irgendwie nicht auf den Fehler. Danke für den Timer nochmal =)
Ein weiteres Problem habe ich wenn ich den Servo nach fahren zu Position1 auf eine´andere Position fahren will. Er stoppt einfach bei Position 1 und macht dannach nichts mehr ( Hält aber seine Position ). Vllt kann mir jemand erklären warum das so ist.
Moin, >void Servo1(unsigned char); Gibt es da keine Compilerwarnung? >for(i=0;i<2000;i++){_delay_ms(1);} // 2sec warten. Das kannst Du auch so schreiben:
1 | _delay_ms(2000); |
Die Variable i brauchst Du dann nicht mehr. Es gab wohl früher die Einschränkung, dass nur 255 ms Verzögerung möglich waren, heute geht mehr. Warum die Servos nicht fahren muss ich mir mal genauer anschauen. Auf den Ersten Blick sehe ich nichts. Die Ansteuerung der Servos mit Graden ist etwas schwierig. Die meisten Servos bewegen sich zwischen 1,1ms und 1,9ms Impulslänge um 90°, also ausgehend von der Mittelstellung bei 1,5ms um +/- 45°. Es gibt auch welche mit +/- 90°. ABer verlassen würde ich mich darauf nicht. Ich würde nicht mit Grad sondern mit Prozenten arbeiten, so in Richtung +-100% Weg. Ich suche mal ein Beispiel, melde mich dann wieder. Gruß, Stefan
So, hab mal schnell was getippt.... So sollte das funktionieren:
1 | #ifndef F_CPU
|
2 | #define F_CPU 18432000UL
|
3 | #endif
|
4 | |
5 | //servo values
|
6 | #define SERVOMAX 4377 //1,9ms => +100% => (F_CPU / 8 / 1000 * 1,9) -1
|
7 | #define SERVOMIN 2533 //1,1ms => -100% => (F_CPU / 8 / 1000 * 1,1) -1
|
8 | #define SERVOCENTER 3455 //1,5ms => 0% => (F_CPU / 8 / 1000 * 1,5) -1
|
9 | #define SERVOFRAME 46079 //20ms => (F_CPU / 8 / 1000 * 20) -1
|
10 | |
11 | #include <avr/io.h> |
12 | #include <util/delay.h> |
13 | |
14 | void init(void) { |
15 | DDRB |= (1<<PB1) | (1<<PB2); //OCR1x Ports auf Ausgang |
16 | |
17 | //Timer0, Mode 14 Fast-PWM, prescaler 8
|
18 | ICR1=SERVOFRAME; //Impulswiederholzeit 20ms |
19 | OCR1A=SERVOCENTER; //Servo 1 Mittelstellung |
20 | OCR1B=SERVOCENTER; //Servo 2 Mittelstellung |
21 | |
22 | TCCR1A |= (1<<COM1A1) | (1<<COM1B1) |(1<<WGM11); |
23 | TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS11); |
24 | }
|
25 | |
26 | int main(void) { |
27 | init(); |
28 | _delay_ms(1000); |
29 | while(1) { |
30 | //Servos auf MIN
|
31 | OCR1A = SERVOMIN; |
32 | OCR1B = SERVOMIN; |
33 | |
34 | _delay_ms(1000); |
35 | |
36 | //Servos auf CENTER
|
37 | OCR1A = SERVOCENTER; |
38 | OCR1B = SERVOCENTER; |
39 | |
40 | _delay_ms(1000); |
41 | |
42 | //Servos auf MAX
|
43 | OCR1A = SERVOMAX; |
44 | OCR1B = SERVOMAX; |
45 | |
46 | _delay_ms(1000); |
47 | |
48 | //Servos auf CENTER
|
49 | OCR1A = SERVOCENTER; |
50 | OCR1B = SERVOCENTER; |
51 | |
52 | _delay_ms(1000); |
53 | }
|
54 | return(1); |
55 | }
|
Dein LCD und das verändern der Werte musst Du selber reinfummeln.... Gruß, Stefan
Wow so früh morgens hilfst du mir schon :). DANKE! Leider fahren die Servos immer noch beide auf MAX und bleiben da :(. Ich probiere weiter herum und melde mich wenn ich etwas merkwürdiges entdecke
Hallo nochmal, bist Du sicher, dass Du auf den Externen Quarz umgeschaltet hast? Wenn nicht würde das einiges erklären... Das Timing sollte stimmen, den obigen Code habe ich, allerdings mit 16MHz Takt, in einem aktuellen Projekt am laufen. Gruß, Stefan
muss leider sagen ja. Der Mc funktioniert zu 100% :(. Könnte vllt was mit den Servos nicht stimmen ?
Der Code meines Namensvetters kann nicht funktionieren, weil ... Zitat Datenblatt:
1 | The ICR1 Register can only be written when using a Waveform Generation |
2 | mode that utilizes the ICR1 Register for defining the counter’s TOP value. |
3 | In these cases the Waveform Generation mode (WGM13:0) bits must be set |
4 | before the TOP value can be written to the ICR1 Register. |
PS: Und dein eigener Code hat das selbe Problem.
@Stefan Ernst Weiter unten im Handbuch bei Fast PWM steht aber dann -> Using the ICR1 Register for defining TOP works well... @STK500-Besitzer Danke, habe mir alles durchgelesen, habe jedoch noch Probleme deinen Code an meinen MC anzupassen um ihn zu testen, werde schreiben ob er Funktioniert hat sobald ich es geschafft habe ihn zu ändern
Aloha schrieb: > @Stefan Ernst > > Weiter unten im Handbuch bei Fast PWM steht aber dann -> > Using the ICR1 Register for defining TOP works well... Ja und? Ich habe ja nicht gesagt, dass es grundsätzlich nicht funktioniert. Es funktioniert nur nicht so, wie es jetzt im Code steht, weil ICR1 zum richtigen Zeitpunkt beschrieben werden muss. Oder meinst du der von mir zitierte Text steht nur aus Spaß im Datenblatt?
Ich danke dir auch, vllt kannst du mir auch helfen das Problem zu lösen? Oder ist deine Antwort ein Hinweis darauf das ich eine anderen Timer Mode nehmen muss/soll.
Aloha schrieb:
> Ich danke dir auch, vllt kannst du mir auch helfen das Problem zu lösen?
Was an dem zitierten Text verstehst du denn nicht?
Da steht doch unmissverständlich drin, wann ICR1 zu beschreiben ist.
Juhu!!! Hab den Fehler gefunden ... natürlich ein Hardware Problem, das Kabel das die beiden GNDs miteinander verbindet hatte einen Wackler. Danke an alle für die Hilfe
Hallo Stefan, >Es funktioniert nur nicht so, wie es jetzt im Code steht, >weil ICR1 zum richtigen Zeitpunkt beschrieben werden muss. ich gebe zu dass ich das Datenbaltt nicht allzu genau gelesen habe. Aber der Code funktioniert trotzdem. Bei mir zwar auf nem Mega168, aber beim Timer1 unterscheidet der sich nicht vom Mega88. Ich setze ICRx / OCRx bei allen PWM Modi so wie oben und hatte noch nie Probleme. Ich habe bisher Tiny13, Tiny25, Mega8 , Mega168 und Mega16 verwendet. Ist Dir da mal was aufgefallen? Gruß, Stefan
Stefan Weßels schrieb:
> Ist Dir da mal was aufgefallen?
Nein, aber es steht halt im Datenblatt eindeutig drin, dass ICR1 erst
beschrieben werden kann, nachdem man einen Timermode eingestellt hat,
bei dem ICR1 TOP ist.
Wenn es andersherum trotzdem funktioniert, hast du Glück. Darauf
verlassen würde ich mich nicht.
Hallo Stefan, dann werde ich es in Zukunft so machen ( Habe den Passus im Datenblatt gefunden):
1 | void init(void) { |
2 | DDRB |= (1<<PB1) | (1<<PB2); //OCR1x Ports auf Ausgang |
3 | |
4 | //Timer0, Mode 14 Fast-PWM, prescaler 8
|
5 | |
6 | TCCR1A |= (1<<COM1A1) | (1<<COM1B1) |(1<<WGM11); |
7 | TCCR1B |= (1<<WGM13) | (1<<WGM12); |
8 | |
9 | ICR1=SERVOFRAME; //Impulswiederholzeit 20ms |
10 | OCR1A=SERVOCENTER; //Servo 1 Mittelstellung |
11 | OCR1B=SERVOCENTER; //Servo 2 Mittelstellung |
12 | |
13 | TCCR1B |= (1<CS11); |
14 | |
15 | }
|
Danke für den Hinweis und frohe Feiertage! Gruß, Stefan
Habs bei mir auch geändert und dazu noch ein paar Taster, um an die Grenzen des Servos zu fahren und die passenden Werten auf dem Display zu haben, eingebaut. Frohe Feiertage euch.
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.