Forum: Mikrocontroller und Digitale Elektronik Atmega88 Timer problem


von Aloha (Gast)


Angehängte Dateien:

Lesenswert?

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

von Stefan W. (swessels)


Lesenswert?

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

von Aloha (Gast)


Lesenswert?

Danke, also war mein Problem das der Servoimpulse nicht genau alle 20ms 
kam? Werde heute noch deinen Timer ausprobieren und berichten.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Stefan W. (swessels)


Lesenswert?

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

von Aloha (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Aloha (Gast)


Lesenswert?

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 =)

von Aloha (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Stefan W. (swessels)


Lesenswert?

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

von Stefan W. (swessels)


Lesenswert?

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

von Aloha (Gast)


Lesenswert?

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

von Stefan W. (swessels)


Lesenswert?

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

von Aloha (Gast)


Lesenswert?

muss leider sagen ja. Der Mc funktioniert zu 100% :(. Könnte vllt was 
mit den Servos nicht stimmen ?

von Stefan E. (sternst)


Lesenswert?

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.

von STK500-Besitzer (Gast)


Lesenswert?

Beitrag "Re: Problem mit PWM und Servo"

Stunden lang gesucht...

von Aloha (Gast)


Lesenswert?

@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

von Stefan E. (sternst)


Lesenswert?

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?

von Aloha (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Aloha (Gast)


Lesenswert?

TCCR1B |= (1<<WGM13)

WGM13 ist doch beiden Codes gesetzt

von Aloha (Gast)


Lesenswert?

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

von Stefan W. (swessels)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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.

von Stefan W. (swessels)


Lesenswert?

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

von Aloha (Gast)


Angehängte Dateien:

Lesenswert?

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
Noch kein Account? Hier anmelden.