AVR Problem mit 16 Bit Timer

Gast #2560880
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
Gast #2560886
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
Gast #2560983
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
Gast #2560990
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 */
Gast #2561015
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
Gast #2561027
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
Gast #2561041
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
Gast #2561046
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
Gast #2561265
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren