Forum: Mikrocontroller und Digitale Elektronik atmega48 Timer1 CTC Problem


von apfelsaft (Gast)


Lesenswert?

Hey Leute,

ich möchte mit einem atmega48 mithilfe des Timer1 drei Modellbauservos 
ansteuern. Allerdings habe ich das Problem, das der Chip keine Impulse 
mehr ausgibt wenn ich den Wert im OCR1A Register höher als 42000 
einstelle. Dadurch kann ich meinen Servo nicht bis an die Endlage 
fahren. Hier mal ein Auszug aus dem Programm mit der Initialisierung des 
Timers und der dazu gehörigen ISR:

ISR(TIMER1_COMPA_vect) {
PORTB&=~((1<<PB0)|(1<<PB1)|(1<<PB2)); //aktuelleImpulsausgabe beenden
Servo_Port = Servo_Bit[Servo_Nr];     //nächsten Impuls beginnen
OCR1A = 44000;                  //die länge des nächsten Impulses 
festlegen
TCNT1 = 0;                        //das Zählregister zurrücksetzen

//die Zählvariable erhöhen, damit beim nächsten Durchgang der nächste 
Pin gsetzt wird
Servo_Nr++;
if(Servo_Nr==Servo_Anzahl){
  Servo_Nr=0;
   }
}

int main(void) {

DDRB|=(1<<PB0)|(1<<PB1)|(1<<PB2);         //Ausgänge für die Servos
TCCR1B |= (1<<WGM12)|(1<<WGM13)|(1<<CS10);//Timer1 im CTC initialiserien
TCCR1A&=~((1<<WGM10)|(1<<WGM11));
TIMSK1 |= (1<<OCIE1A);                    //Interrupt für Timer1 
freigeben
ICR1H = 0xFF;                             //Top Wert für Timer1 
festlegen
ICR1L = 0xFF;                             //Top Wert für Timer1 
festlegen
sei();
}

Das das ICR1 Register so beschrieben wird, war nur ein test, weil mir so 
langsam die Ideen ausgehen woran das liegen könnte. Danke schon mal im 
Voraus.

von Karl H. (kbuchegg)


Lesenswert?

Mir fehlt in diesem Code
1
int main(void) {
2
3
DDRB|=(1<<PB0)|(1<<PB1)|(1<<PB2);         //Ausgänge für die Servos
4
TCCR1B |= (1<<WGM12)|(1<<WGM13)|(1<<CS10);//Timer1 im CTC initialiserien
5
TCCR1A&=~((1<<WGM10)|(1<<WGM11));
6
TIMSK1 |= (1<<OCIE1A);                    //Interrupt für Timer1 
7
freigeben
8
ICR1H = 0xFF;                             //Top Wert für Timer1 
9
festlegen
10
ICR1L = 0xFF;                             //Top Wert für Timer1 
11
festlegen
12
sei();
13
}

die Hauptschleife.
Auch wenn es nichts zu tun gibt, MUSST du eine Hauptschleife haben! 
Selbst dann wenn sie leer ist. Du willst dein Programm niemals aus 
main() rauslassen. Denn dann kommt der Code zum Zug, der main() 
aufgerufen hat und der ... dreht als erstes die Interrupts ab. Das ist 
aber für dich fatal, denn du brauchst die Interrupts um die Pulse zu 
generieren!
Also flugs ein
1
   while( 1 ) {
2
   }
mit eingebaut.



Zu deiner Timersache.
Warum so kompliziert? Lass doch den Timer ganz einfach im normalen Modus 
durchlaufen. Kein CTC und auch kein ICR Register, einfach durchlaufen 
lassen mit aktiviertem Compare Match. Und in der ISR zählst du einfach 
zum OCR Register die gewünschte Zeit zum nächsten Compare Match dazu. 
Dann brauchst du auch den Timer nicht zurücksetzen.
1
ISR(TIMER1_COMPA_vect) {
2
  PORTB&=~((1<<PB0)|(1<<PB1)|(1<<PB2)); //aktuelleImpulsausgabe beenden
3
  Servo_Port = Servo_Bit[Servo_Nr];     //nächsten Impuls beginnen
4
5
  OCR1A += 44000;                  //die länge des nächsten Impulses festlegen
6
7
  //die Zählvariable erhöhen, damit beim nächsten Durchgang der nächste Pin gsetzt wird
8
  Servo_Nr++;
9
  if(Servo_Nr==Servo_Anzahl){
10
    Servo_Nr=0;
11
  }
12
}

das ist die allereinfachste Variante.

von apfelsaft (Gast)


Lesenswert?

Hi Karl Heinz,

erst einmal Danke für deine schnelle Antwort. In meinem  richtigen 
Programm habe ich natürlich eine Hauptschleife. Diese habe ich nur nicht 
kopiert, weil ja eh nichts drin steht.^^ Und das mit dem addieren des 
OCR1A Register funktioniert? Wenn ich das richtig verstehe würde zum 
Beispiel wenn im einen Durchgang 48000 drin steht und im nächsten 
addiere ich 48000 dann kommt eine Zahl raus die größer ist als 16 bit 
und somit zu groß. Naja egal. Ich werde es mal probieren. Aber komisch 
ist es doch trotzdem das der timer keinen höheren OCR Wert zulässt.

von Paul Baumann (Gast)


Lesenswert?

Apfelsaft schrob:
>zum Beispiel wenn im einen Durchgang 48000 drin steht und im nächsten
>addiere ich 48000 dann kommt eine Zahl raus die größer ist als 16 bit
>und somit zu groß.

Nein, das ist ein Trugschluß: Es wird bis 65535 gezählt und dann springt
es wieder auf 0. Es wäre also bei Deinem Beispiel so, daß wenn er 48000
drin stehen hat, noch 17536 Schritte bis 65535 und dann noch einmal 
30464.
Der nächste Zählerstand wäre also: 48000 (vom ersten Durchlauf)+48000 
dazu
vom nächsten Durchlauf ergäbe den neuen Stand von 30464.

Es kann nicht "überlaufen", da der Kollege Zähler nur 16-Bit "hoch" ist,
geht es nach dem Überlauf wieder von vorne los.

MfG Paul

von Karl H. (kbuchegg)


Lesenswert?

apfelsaft schrieb:
> Hi Karl Heinz,
>
> erst einmal Danke für deine schnelle Antwort. In meinem  richtigen
> Programm habe ich natürlich eine Hauptschleife. Diese habe ich nur nicht
> kopiert, weil ja eh nichts drin steht.^^

Dann bin ich raus.
Ich mag es nämlich nicht, wenn ich mir den Kopf darüber zerbreche, was 
in deinem Code alles schief gehen könnte und wie der beobachtete Effekt 
erklärbar wird, wenn du dann gar nicht deinen richtigen Code zeigst.

> Und das mit dem addieren des
> OCR1A Register funktioniert? Wenn ich das richtig verstehe würde zum
> Beispiel wenn im einen Durchgang 48000 drin steht und im nächsten
> addiere ich 48000 dann kommt eine Zahl raus die größer ist als 16 bit
> und somit zu groß.

Eine Uhr hat ein Ziffernblatt auf dem 60 Sekunden markiert sind. Wenn 
der Sekundenzeiger auf 48 steht und die Uhr 23 mal tickt, auf welcher 
Zahl steht der Zeiger dann?

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.