Forum: Mikrocontroller und Digitale Elektronik AVR Problem mit 16 Bit Timer


von Uwe (Gast)


Lesenswert?

Hi und hallo,

ich versuche gerade einen 16 Bit Timer ans Laufen zu bekommen. Dabei 
soll eben ein Interrupt kommen, wenn der Timer abgelaufen ist. Das 
passiert aber leider nicht.
Den 8 Bit Timer habe ich am Laufen. Bei dem 16 Bit Timer hänge ich eben.

Die Interrupt-Routine sollte die richtige sein. Vielleicht kan mir da ja 
jemand auf die Sprünge helfen.

Vielen Dank schon einmal!

Uwe

Die Initialisierung für den Timer sieht wie folgt aus:

1
void initTimer1(void)     
2
{
3
    OCR1AH= (unsigned char)(OCR_ONE>>8);   
4
    OCR1AL= (unsigned char)(OCR_ONE);                        
5
       
6
    TIMSK1= 1<<OCIE1A;          
7
}
Die ISR folgt hier:
1
ISR (TIMER1_COMPA_vect)            
2
{
3
    TCNT1H = (unsigned char)(TCNT_ONE>>8);          
4
    TCNT1L = (unsigned char)(TCNT_ONE);  
5
6
...mach was....
7
}

In der main.c will ich den Timer dann wie folgt starten:
1
TCNT1H = (unsigned char)(TCNT_ONE>>8);          
2
TCNT1L = (unsigned char)(TCNT_ONE);          
3
TCCR1B = (1<<CS12)|(1<<CS10);

Hier noch die Zählerwerte:
1
#define    OCR_ONE    0x3D08          
2
#define    TCNT_ONE  0xC2F7

von Uwe (Gast)


Lesenswert?

Und was ist mit "Global Interupt Enable" ?

von Oliver (Gast)


Lesenswert?

Uwe schrieb:
> Dabei
> soll eben ein Interrupt kommen, wenn der Timer abgelaufen ist.

Das klingt nach overflow-Interrupt. Du aber hast eine ISR für den 
compare-Interrupt angelegt. Da passt was nicht

Uwe schrieb:
> #define    OCR_ONE    0x3D08
> #define    TCNT_ONE  0xC2F7

Und das macht man nicht. Denn wer soll daraus erkennen können, was du da 
jetzt genau machst?

Schreib das bitte mit den einzelnen Bitnamen, dann sieht man (und auch 
du) direkt, was Sache ist. Z.B., ob du jetzt den Overflow, oder den 
Compareinterrupt freigegeben hast.

Und bitte immer den ganzen Quelltest posten, nicht nur Auschnitte. Mit 
fehlt da z.B. ein sei().

Oliver

von Krapao (Gast)


Lesenswert?

> #define OCR_ONE   0x3D08
> #define TCNT_ONE  0xC2F7

Achtung: TCNT_ONE > OCR_ONE

D.h. Compare Match für TCNT1 == OCR1A wird später als vielleicht 
erwartet erreicht. TCNT1 muss zuerst überlaufen!

In deinem Fall mit dem Vorbesetzen von TCNT1 braucht der Timer doppelt 
so lange wie von TCNT1 = 0 bis OCR1A.

Die Programmlogik hinter deinem Vorbesetzen von TCNT1 verstehe ich 
nicht. Warum lässt du Timer1 nicht im CTC Modus (d.h. bestimmte WGM1x 
Bits gesetzt, anders als jetzt Normalmodus mit allen WGM1x Bits = 0) 
laufen und lässt den TCNT1 in Ruhe. Wenn das mit der langen Zeit 
zwischen den Aufrufen der ISR PK ist dann ist OCR_ONE natürlich anders 
zu berechnen.

Lass dich nicht auf den K(r)ampf HIGH-vor-LOW? oder LOW-vor-HIGH? ein. 
Der Compiler kann das selbst entscheiden.
1
    OCR1A = OCR_ONE;   // TOP für OCIE1A setzen 
2
    TCNT1 = TCNT_ONE;  // Timerzähler1 setzen

von Uwe (Gast)


Lesenswert?

Hallo,

> Global Interupt Enable

Ist drin. Wie geschrieben. Den 8 Bit Timer habe ich nach gleichem Schema 
am Laufen; als Compare.

Oliver schrieb:
>> #define    OCR_ONE    0x3D08
>> #define    TCNT_ONE  0xC2F7
>
> Und das macht man nicht. Denn wer soll daraus erkennen können, was du da
> jetzt genau machst?
>
> Schreib das bitte mit den einzelnen Bitnamen, dann sieht man (und auch
> du) direkt, was Sache ist. Z.B., ob du jetzt den Overflow, oder den
> Compareinterrupt freigegeben hast.

Also HIGH und LOW trennen oder was?
#define    OCR_ONE_HI    0x3D
#define    OCR_ONE_LO    0x08
#define    TCNT_ONE_HI   0xC2
#define    TCNT_ONE_LO   0xF7

So in etwa oder habe ich das falsch verstanden?
Das sind Werte für 16MHz Takt/Prescaler 1024/!sec

Hier mal ein erweiterter Ausschnitt aus der main.c . Die initTimer1() 
und die ISR. Sind wie oben eben.
1
#include   <avr\io.h>          
2
#include   <stdlib.h>          
3
#include   <avr/interrupt.h>      
4
5
      
6
int main(void)
7
{   
8
    cli();
9
    Ports();                   
10
    Interupt();                            
11
    initTimer1();
12
    sei();
13
  
14
    // Timer 1
15
    TCNT1H = (unsigned char)(TCNT_ONE>>8);          
16
    TCNT1L = (unsigned char)(TCNT_ONE);          
17
    TCCR1B = (1<<CS12)|(1<<CS10);
18
19
    while(1)
20
    {
21
        .....
22
    }
23
}/* main */

von spess53 (Gast)


Lesenswert?

Hi

Irgendwie habe ich das Gefühl, das du das mit den Timer nicht so richtig 
verstanden hast.

Du lädst den Timer am Anfang mit einem Wert > Comparewert. Damit rennt 
der Timer bis $FFFF und fängt dann bei Null wieder an bis er zum 
Comparewert kommt. Dort fängt das Spiel wieder von vorn an.

Was willst du damit bezwecken? Dieses Vorladen der Timer ist in 99% 
aller Fälle bei AVRs unnötig.

MfG Spess

von Oliver (Gast)


Lesenswert?

Uwe schrieb:
> Also HIGH und LOW trennen oder was?
> #define    OCR_ONE_HI    0x3D
> #define    OCR_ONE_LO    0x08

Nein. Sowas in der Art:

TCCR0 |= 
(1<<WGM01)|(0<<WGM00)|(0<<COM01)|(0<<COM00)|(0<<CS02)|(0<<CS01)|(1<<CS00 
);

Damit man sieht, welche Bits da gesetzt werden.

Oliver

von Oliver (Gast)


Lesenswert?

Oliver schrieb:
> Nein. Sowas in der Art:
> TCCR0 |=

Grrr. Das war kein gutes Beispiel. Das Schieben von Nullen ist Murks. 
Also nochmal:

TCCR0 = (1<<WGM01 | (1<<CS00);

Oliver

von Uwe (Gast)


Lesenswert?

Hallo,

jetzt läuft es so wie oben angegeben. Ich hatte dummerweise bei mir 
durch das Rumprobieren einen Zahlendreher drin.

TCNT und OCR habe ich mit AVRCalc berechnet.

Wie wäre es dann richtig, also wenn man das Vorladen weglässt, um z.B. 
einen ein Sekunden Takt zu erzeugen?

Vielen Dank!

Grüße Uwe

von spess53 (Gast)


Lesenswert?

Hi

>Wie wäre es dann richtig, also wenn man das Vorladen weglässt, um z.B.
>einen ein Sekunden Takt zu erzeugen?

Dazu nimmt man einfach CTC. Da braucht man nur einmal das 
Compareregister laden und der Rest läuft automatisch.

MfG Spess

von Uwe (Gast)


Lesenswert?

Hallo,

wenn ich das richtig verstehe, setze ich dann eben
1
TCCR1B |= (1<<CS12)|(1<<WGM13)|(1<<WGM12);

Damit würde eben CTC eingestellt und Prescaler 256.

Soweit richtig? Nur bei den anderen Registern blicke ich dann noch nicht 
so ganz durch, welches wie geladen werden muss.

Uwe

von Karl H. (kbuchegg)


Lesenswert?

>> FAQ << Punkt 11

von Krapao (Gast)


Lesenswert?

Beim ??? stellt das den CTC Modus 12 mit ICR1 (Input Capture Register) 
als Top ein. CTC Modus 4 mit OCR1A als Top ist sinnvoller.

von spess53 (Gast)


Lesenswert?

Hi

>CTC Modus 4 mit OCR1A als Top ist sinnvoller.

Wieso?

MfG Spess

von Krapao (Gast)


Lesenswert?

> Wieso

Weil

>>    OCR1AH= (unsigned char)(OCR_ONE>>8);
>>    OCR1AL= (unsigned char)(OCR_ONE);

bzw.

>>    OCR1A= OCR_ONE;

keinen Einfluss auf ICR1 hat.

von Uwe (Gast)


Lesenswert?

Hallo,

>CTC Modus 4 mit OCR1A als Top ist sinnvoller.

Damit läuft es jetzt.

Vielen Dank!

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.