Forum: Mikrocontroller und Digitale Elektronik Timer laufen "auseinander"


von lex (Gast)


Lesenswert?

Morgen,
ich spiele gerade bisl mit den Timern meines ATmega16 und deren Modi.
Jetzt ist mir etwas seltsames aufgefallen:

Ich benutze den Timer0 (8 Bit) und Timer1 (16 Bit), beide im CTC Modus.
Mein Atmel rumpelt mit 16 MHz.

Der Timer0 benutzt den Prescaler 64 und das Compare Register lade ich 
mit 250.
Das sollte einen CompareMatch Interrupt alle 1 ms ergeben.

Timer1 benutzt als Prescaler 8 und das Compare Register wird mit 5000 
geladen, das sollte einen Interrupt alle 2.5 ms ergeben.

Um die Funktion zu testen toggle ich im IR jeweils eine LED.
Allerdings nicht jedesmal.
Bei Timer0 lasse ich eine Variable auf 1000 zählen, bei Timer1 bis 400.

D.h. beide LEDs sollten alle 1 s getoggelt werden.
Mein Atmel macht sonst rein garnichts mehr, auch keine anderen IRs.

Allerdings laufen die LEDs "auseinander". Je länger ich die Schaltung in 
Betrieb habe desto versetzter gehen die LEDs an und aus. Und zwar 
merklich mit bloßem Auge :/

Hab ich einen Denkfehler bei meinen Register/Variablen Werte?

Hier der Code der main:
1
volatile uint16_t counter_Timer1 = 0;
2
volatile uint16_t counter_Timer0 = 0;
3
4
ISR (TIMER0_COMP_vect)
5
{
6
    counter_Timer0++;
7
    if (counter_Timer0 >= 1000)
8
    {
9
      TOGGLE_PIN(0, PORTB);
10
      counter_Timer0 = 0;
11
    }
12
}
13
14
ISR (TIMER1_COMPA_vect)
15
{
16
    counter_Timer1++;
17
    if (counter_Timer1 >= 400)
18
    {
19
      TOGGLE_PIN(1, PORTB);
20
      counter_Timer1 = 0;
21
    }
22
}
23
24
int main(void){
25
26
    DDRB = 0xFF;
27
28
29
    Timer1_Init();
30
    Timer0_Init();
31
    sei();
32
    
33
    while(1);
34
35
    return 0;
36
}

Und hier meine Timer Inits:
1
void Timer0_Init()
2
{
3
4
  /* Compare Interrupt für Timer 0 aktivieren */
5
    TIMSK |= (1 << OCIE0);
6
7
    /* laden mit 250 */
8
    OCR0 = 0xFA;
9
    
10
    /* Prescaler 64 */
11
    TCCR0 = (1<<CS01) | (1<<CS00) | (1<<WGM01);
12
}
1
void Timer1_Init()
2
{
3
4
    /* Compare Interrupt A für Timer 1 aktivieren */
5
    TIMSK |= (1 << OCIE1A);
6
7
    /* laden mit 5000 */
8
    OCR1A = 0x1388;
9
10
    /* Prescaler 8 und Moduswahl */
11
    TCCR1A = (0 << WGM11) | (0 << WGM10);
12
    TCCR1B = (0 << CS12) | (1 << CS11) | (0 << CS10);
13
    TCCR1B  |= (0 << WGM13) | (1 << WGM12);
14
}

Kann da jemand vielleicht drüberschaun? Wahrscheinlich was ganz 
triviales...

Viele Grüße!

von Oliver (Gast)


Lesenswert?

Überleg dir nochmal, wieviele Zyklen deine Zähler wirklich durchlaufen. 
Kleinvieh macht auch Mist.

Oliver

von Peter D. (peda)


Lesenswert?

lex schrieb:
> /* laden mit 5000 */
>     OCR1A = 0x1388;

Der Kommentar ist sowas von überflüssig, der Compiler versteht nämlich 
Dezimalzahlen.
Hex ist hier nur dazu gut, um den Leser zu verwirren.
Also:
1
     OCR1A = 5000 - 1;


Peter

von Erik (Gast)


Lesenswert?

ja, wenn man von 0 anfängt zu zählen dann hat man beim Zählerwert 1000 
bereits wie viele male gezählt? ;)

SCNR
Erik

von spess53 (Gast)


Lesenswert?

Hi

>Der Timer0 benutzt den Prescaler 64 und das Compare Register lade ich
>mit 250.
>Das sollte einen CompareMatch Interrupt alle 1 ms ergeben.

Nein. Dazu müsste OCR0=249 sein.

>Timer1 benutzt als Prescaler 8 und das Compare Register wird mit 5000
>geladen, das sollte einen Interrupt alle 2.5 ms ergeben.

Ebenfalls falsch: OCR1A =4999.

MfG spess

von lex (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Der Kommentar ist sowas von überflüssig

Das stammt noch aus einem vorherigen Versuch, da hab ich High und Low 
Byte seperat geschrieben, bevor ich gelesen habe dass der Compiler eine 
"direkte" Zuweißung richtig übersetzt.

Ansonsten klappts jetzt, Danke euch!

Kopf => Tisch

Viele Grüße

von lex (Gast)


Lesenswert?

Achja, mir fällt noch eine Frage zum Timer1 ein.

Laut Datenblatt Seite 112 zählt der Timer im CTC Modus immer bis OCR1A.

Jetzt besitzt aber dieser Timer noch ein zweites Compare Register, 
OCR1B.

Wenn ich diesen Interrupt benutzen will muss ich ja anscheinend das B 
Register mit einem kleineren Wert laden als A. Richtig?

Und was passiert dann? Bei einem CompareMatch Interrupt A fängt der 
Timer wieder bei 0 an.
Was passiert bei einem CompareMatch Interrupt B? Der Timer muss ja noch 
weiter zählen bis OCR1A.
Wie genau ist also dieser Interrupt zu benutzen? Das ist mir gerade 
nicht ersichtlich :/

Viele Grüße

von Falk B. (falk)


Lesenswert?

@lex (Gast)

>Jetzt besitzt aber dieser Timer noch ein zweites Compare Register,
>OCR1B.

Sieht so aus.

>Wenn ich diesen Interrupt benutzen will muss ich ja anscheinend das B
>Register mit einem kleineren Wert laden als A. Richtig?

Falsch. B ist vollkommen unabhängig.

Es gibt zwei CTC Modi. Dabei wird der Endwert jeweils durch ein anderes 
Register bestimmt.

WGM 4, OCR1A
WGM 12, ICR1

Logisch dass in dem jeweiligen Mode die "normale" Funktion des Registers 
nicht verfügbar ist. OCR1B ist immer verfügbar.

>Was passiert bei einem CompareMatch Interrupt B? Der Timer muss ja noch
>weiter zählen bis OCR1A.

Macht er auch, er löst nur den Interrupt für OCR1B aus.

>Wie genau ist also dieser Interrupt zu benutzen?

Genauso wie A, nur dass man damit kein CTC machen kann.

MfG
Falk

von Karl H. (kbuchegg)


Lesenswert?

lex schrieb:

> Jetzt besitzt aber dieser Timer noch ein zweites Compare Register,
> OCR1B.
>
> Wenn ich diesen Interrupt benutzen will muss ich ja anscheinend das B
> Register mit einem kleineren Wert laden als A. Richtig?

Logisch.

Wenn du immer nur von 1 bis 10 zählst und deine Freundin hat die Aufgabe 
immer dann wenn du 20 sagst "Feuer" zu rufen, dann wird sie nie rufen. 
Denn du sagst ja nie 20.

> Was passiert bei einem CompareMatch Interrupt B? Der Timer muss ja noch
> weiter zählen bis OCR1A.

Ja, tut er auch.
Der Interrupt wird ausgelöst und wenn du eine ISR daran gekoppelt hast, 
wird sie ausgeführt. Währenddessen zählt der Timer weiter, bis er bei 
OCR1A angelangt ist.

> Wie genau ist also dieser Interrupt zu benutzen? Das ist mir gerade
> nicht ersichtlich :/

Du kannst zb im OCR1A Interrupt einen Pin auf 1 setzen und mit dem OCR1B 
denselben Pin wieder abschalten.

Dann kannst du mit dem OCR1A einstellen, wie oft das in der Sekunde 
passiert und mit dem OCR1B wie lange der Pin in einem Zyklus auf 1 ist.

von spess53 (Gast)


Lesenswert?

Hi

> Bei einem CompareMatch Interrupt A fängt der Timer wieder bei 0 an.

Nur bei CTC oder PWM mit OCR1A als Top. Allerdings hat das nichts mit 
dem Interrupt zu tun. Das passiert auch ohne Interrupt.

>Was passiert bei einem CompareMatch Interrupt B? Der Timer muss ja noch
>weiter zählen bis OCR1A.

kommt auf den Timermode an.

MfG Spess

von Peter D. (peda)


Lesenswert?

Will man 2 unabhängige Timer, dann setzt man einfach im Compareinterrupt 
den nächsten Comparewert.
1
ISR( TIMER1_COMPA_vect )
2
{
3
  OCR1A += time1;
4
}
5
6
ISR( TIMER1_COMPB_vect )
7
{
8
  OCR1B += time2;
9
}
Und den Timer natürlich in Mode 0.


Peter

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.