Forum: Compiler & IDEs Timer0 und Timer2 simultan - ATMega32


von TKam (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

bin ein GCC noob und ich habe ein Problem, wenn ich Timer 0 und Timer 2 
simultan initialisiere.

Ich moechte Timer 0 und 2 simultan etwas rechnen lassen und konfiguriere 
sie als compare interrupts:

    //Timer 0 und Timer 2 konfigurieren
    TCCR0 = (1<<WGM01) | (1<<CS01);
    OCR0 = 2;
    TCCR2 = (1<<WGM21) | (1<<CS21);
    OCR2 = 2;
    //Compare Interrupts 0 und 2 aktivieren
    TIMSK = (1<<OCIE0) | (1 << OCIE2);

Die Interrupt-Routinen inkrementeiren lediglich jeweils einen Integer:

    ISR(TIMER0_COMP_vect)
    {
        i++;
    }

    ISR(TIMER2_COMP_vect)
    {
        j++;
    }

In meiner main gebe ich in einer Schleife die Werte von i und j auf 
meinem LCD aus:

    for(;;) {
        set_cursor(0, 2);
        itoa(i,LcdBuffer,10);
        lcd_string(LcdBuffer);//lcd_string("  ");

        set_cursor(0, 3);
        itoa(j,LcdBuffer,10);
        lcd_string(LcdBuffer);//lcd_string("  ");
    }

Das Merkwuerdige ist, dass j staendig inkrementiert wird, aber i nicht; 
i hat permanent den Wert 0.

Und jetzt kommt's: wenn ich die Kommentare lcd_string("  "); nach der 
Ausgabe von i und j wieder in den Quellcode reinnehme, wird die 
Interrupt-Routine des Timers 0 EINMAL ausgefuehrt, denn i nimmt ab dann 
konstant den Wert 1 an.

Kann mir jemand erklaeren, womit das zu tun hat? Warum wird Timer0 nicht 
korrekt ausgefuehrt? Die main.c befindet sich im Anhang.

Vielen Dank im Voraus und schoene Gruesse,
Thomas

von TKam (Gast)


Angehängte Dateien:

Lesenswert?

Nur fuer den Fall, dass ich etwas in der Makefile verhauen habe, haenge 
ich sie auch nochmal an.

Die LCD-Routinen habe ich aus dem gcc-tutorial von hier.

von Magnus Müller (Gast)


Lesenswert?

Schon mal was von "volatile" gehört?

von TKam (Gast)


Lesenswert?

Vielen Dank fuer die schnelle Antwort.

Ich habe mal probiert, i und j als volatile unsigned int zu deklarieren, 
aber das Problem tritt nach wie vor auf. Worin besteht denn der 
Unterschied dazu, wenn ich i und j einfach als uint8_t deklariere?

Ich bin fuer jede Hilfe Dankbar!

von Karl H. (kbuchegg)


Lesenswert?

* das volatile muss rein

* Wenn ich das recht sehe, dann lässt du beide Timer mit Full-Speed im 
CTC Modus laufen und setzt einen Compare Wert von 2.
Das heist aber auch, dass alle 3 Takte ein Interrupt ausgelöst wird.

D.h. Der Timer2 macht dir mit seinen Interrupts alles andere dicht. 
Sobald der Interrupt abgearbeitet ist, ist auch schon der nächste 
Interrupt von diesem Timer da. Dein Hauptprogramm schleppt sich mit Ach 
und Krach durch die Hauptschleife, praktisch ständig von der Interrupt 
Bearbeitung für Timer2 unterbrochen. Der Interrupt vom Timer0 kommt da 
gar nicht mehr durch.

Änderungen:
i und j als volatile definieren.
die OCR Werte höher setzen.

von TKam (Gast)


Lesenswert?

Wow, das ist ja interessant.

Ich dachte fuer Interrupt-Routinen wird (egal wo) immer unterbrochen. 
Dass sich 2 Timer wegen der Zeiten in die Quere kommen, haette ich daher 
nicht vermutet.

Aber das Hochsetzen der OCRx-Register hats echt gebracht.

Herzlichen Dank an die schnelle Hilfe, Karl heinz und Magnus, und 
schoene Gruesse!
Thomas

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

TKam schrieb:
> Ich dachte fuer Interrupt-Routinen wird (egal wo) immer unterbrochen.
> Dass sich 2 Timer wegen der Zeiten in die Quere kommen, haette ich daher
> nicht vermutet.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Allgemeines_.C3.BCber_die_Interrupt-Abarbeitung

von Michael U. (amiga)


Lesenswert?

Hallo,

TKam schrieb:
> Wow, das ist ja interessant.
>
> Ich dachte fuer Interrupt-Routinen wird (egal wo) immer unterbrochen.
> Dass sich 2 Timer wegen der Zeiten in die Quere kommen, haette ich daher
> nicht vermutet.

Prinzipiell ist es auch so, wie Du schreibst.
Praktisch denke einfach darüber nach, wieviel Taktzyklen nötig sind, um 
Deine Befehle zu bearbeiten und wie oft Dein Interrupt auftritt.

Auch ein AVR kann immer nur einen Befehl nach dem anderen bearbeiten,
wenn eine Interruptroutine aufgerufen wurde, ist eben niemand da, der 
sich um den IRQ des 2. Timer oder um die Bearbeitung der main kümmern 
könnte.

Gruß aus Berlin
Michael

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.