Forum: Mikrocontroller und Digitale Elektronik Timer und TCNT1


von Daniel (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

ich bin gerade dabei mich mit den Timer/Counter Funktionen des ATmega8
zu beschäftigen.
Mein Ziel war es, ein 1 Sekundentakt zu erzeugen.
Dies ist mir nun auch nach langem Kopfzerbrechen gelungen.
Allerdings ist da noch etwas unklar.

Nachdem der Interrupt aufgerufen wurde, wird TCNT1 nicht automatisch
resettet, sondern zählt fröhlich weiter nach oben.
Ist dies normal? Wäre doch dumm, wenn man TCNT1 nach jedem auftreten
des Interrupts auf 0 setzen muss. Es funktioniert zwar dann, aber würde
mir das nich um 3 Takte die Sekunde verfälschen?:
ldi temp, 0xFF
out TCNT1H, temp
out TCNT1L, temp

Oder ist es ein Bug im AVRStudio?

Den Code hab ich mal mit angehangen.

Gruß
Daniel

von Niko (Gast)


Lesenswert?

also ich kenne assembler nicht aber bei c macht man es so , das wenn der
interrupt aufgerufen wird man den tcnt1 auf null setzt wenn es erwünscht
ist und soweit ich weis verfälscht das deine zählung auch nicht

von MooseC (Gast)


Lesenswert?

Nutze statt dem TimerOverFlow den TimerCompare CTC (Mode 4), der resetet
den Timer automatisch nach dem Erreichen des Wertes in OCR1A.
Das Register musst Du nur einmal setzen und dann nie wieder (Beim Reset
endet diese Welt...).
Denke daran das Du dann einen anderen Vektor für den Interrupt nutzen
musst.

MooseC

von Daniel (Gast)


Lesenswert?

hey, danke für die schnellen Antworten.
Aber Moment mal! :)

Ich nutze doch den compare mode, oder nicht?

mit
ldi temp, 1<<OCIE1B
out TIMSK, temp

Habe ich doch das richtige Bit gesetzt.
Das Datenblatt sagt:
Bit 3   OCIE1B: Timer/Counter1, Output Compare B Match Interrupt
Enable

Was ist also der Fehler? :(

von MooseC (Gast)


Lesenswert?

Immer mit der Ruhe!
Ich hatte gar nicht in Deinen Code geschaut, da ich annahm Du
verwendest den normalen Timerinterrupt und Mode. Bei den erwähnten
zusätzlichen Takten lag das nahe.

Der CTC verwendet meines Wissens nur den OCR1A (oder ICR1 im MODE 12)
als Limit für den Zählwert, Du verwendet aber OCR1B.

MooseC

von Andi (Gast)


Lesenswert?

Du mußt TimerCompare CTC aktivieren (siehe Datenblatt PDF) und Deine ISR
über den Timer Overflow laufen lassen statt Output Compare B Match
Interrupt ansonsten werden Pins für PWM geschaltet (high/low-Wechsel).

Gruß
Andi

von Andi (Gast)


Lesenswert?

Ach ja, CTC heißt übrigens "Clear Timer on Compare" wodurch der Timer
auf 0 gesetzt wird und ein Overflow entsteht was wiederum den Timer
Overflow Interrupt auslöst.

Gruß
Andi

von MooseC (Gast)


Lesenswert?

Das stimmt nicht ganz, denn der Overflowinterrupt TOV1 wird als 17te Bit
beim Überlauf des 16 Bit Countregister gesetzt und löst so einen
Interrupt aus. Für den CTC gibt es den OCF1A, der natürlich auch seinen
eigenen Vektor hat, Der CTC hat keinen Überlauf auf das 17te Bit

MooseC

von Daniel (Gast)


Angehängte Dateien:

Lesenswert?

Hi,
tut mir leid, aber jetzt bin ich noch mehr durcheinander.
Soviel Register wie es da gibt :(

Also ich hab den Code jetz mal geändert.
Es funktioniert aber leider immernoch nicht.

Könnte vielleicht einer von euch, den Code grad so ändern, das es
richtig ist?
Ich denke viel kann da ja jetzt nicht mehr falsch sein :(

Danke!
Daniel

von MooseC (Gast)


Lesenswert?

Alles wichtige wurde bereits gesagt, verstehen und umsetzen mußt Du es
schon selber.
Das Teil viele Register, ja, und nur Du kannst es für Dich entdecken..

Fertiger Code nützt Dir da garnichts

MooseC

von Santa Klaus (Gast)


Lesenswert?

Hallo Daniel,

"ldi temp, 1<<CS11|1<<CS10|1<<WGM13"

Du mußt das WGM12-Bit setzen, nicht das WGM13-Bit.  Siehe Datasheet.

von Daniel (Gast)


Lesenswert?

So jetzt habe ich es geschafft.
Vielen Dank an Euch alle!

Gruß
Daniel

von Joe (Gast)


Lesenswert?

Hallo!

Ich habe hier den Compare-Match Mode gewählt(ATMEGA8535 mit 8Mhz Takt).
Leider läuft der Timer1
noch zu schnell. Was könnte ich da falsch gemacht haben?

TCCR1A=0x00;
TCCR1B=0x0B;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x04;
OCR1AL=0xE2;
OCR1BH=0x00;
OCR1BL=0x00;

TIMSK=0x10;

// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
PORTB = ~PORTB;
if (zehntelsek < 9) ++zehntelsek;
else
    {
     zehntelsek = 0;
     if (sekunden < 59) ++sekunden;
     else
        {
        sekunden = 0;
        if (minuten < 59) ++minuten;
        else
           {
           minuten = 0;
           if (stunden < 23) ++stunden;
           else
              {
              stunden = 0;
              }
           }
        }
    }
}

von Joe (Gast)


Lesenswert?

Was mach ich da nur falsch! Ich bin jetzt total ratlos.

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.