Forum: Mikrocontroller und Digitale Elektronik Problem mit Interrupt Prescaler


von Markus P. (sebastianwurst)


Lesenswert?

Hallo,

aus dem Datenblatt werde ich nicht so richtig schlau.... Meine Frage:

Ich habe einen Atmega 644 mit 16Mhz am laufen, nu will ich einen 
Timerinterrupt alle 1ms auslösen.
Ich muss den Timer 1 nehmen da Timer 0 schon belegt ist.

Meine Konfig sieht so aus:
1
    TCCR1B |= (1<<CS10) | (1<<CS11) | (1<<WGM12);   // Prescaler 64   
2
    TCNT1   = 0;
3
    OCR1AH   = 256;                     // Load register Ist das richtig so  
4
    OCR1AL   = 256;                     // Load register   
5
    TIMSK1 |= (1<<OCIE1A);             // Interrupt nach Overflow

Ich weiss garnicht wie ich den OCR1AH lade Im Datenblatt steht halt 
OCR1AH  / OCR1AL , high und low.
Aber wie muss ich das Handhaben, das ist bestimmt falsch.

Nach meiner Berechnung müsste ca. 1 ms rauskommen.
Prescaler 64 also:

16.000.000Hz/64/256 = 976 = 0,001s = 1ms ca.

Wenn ich aber einen counter in der ISR erhöhe und ich den counter bei 
1000 in der main Abfrage sind das nie und nimmer 1 Sekunde. Diese 1000 
werden viel heufiger erreicht. Bei ca. 100000 habe ich eine Sekunde.

Kann mir einer helfen ?

von Stefan E. (sternst)


Lesenswert?

1
OCR1A = 249;

von Daniel V. (danvet)


Lesenswert?

Also bei mir sieht das so aus und funktioniert:
1
//******************
2
// Timer1: Zeittakt 1ms
3
//******************
4
5
//TIMER1 initialize - prescale:1
6
// WGM: 0) Normal, TOP=0xFFFF
7
// desired value: 1mSec
8
// actual value:  1,000mSec (0,0%)
9
void timer1_init(void)
10
{
11
  TCCR1B = 0x00; //stop
12
  TCNT1L = (0xFFFF - F_CPU/1000 +1) & 0x0FF;
13
  TCNT1H = ((0xFFFF - F_CPU/1000 +1)>>8) & 0x0FF;
14
  OCR1AH = 0x39;  // does not matter
15
  OCR1AL = 0x99;  // does not matter
16
  OCR1BH = 0x39;  // does not matter
17
  OCR1BL = 0x99;  // does not matter
18
  OCR1CH = 0x00;  // does not matter
19
  OCR1CL = 0x00;  // does not matter
20
  ICR1H  = 0x39;  // does not matter
21
  ICR1L  = 0x99;  // does not matter
22
  TCCR1A = 0x00;
23
  TCCR1C = 0x00;
24
  TCCR1B = 0x01; //start Timer, no prescale
25
}
Ich verwende den OverflowInterrupt

von Daniel V. (danvet)


Lesenswert?

Stefan Ernst schrieb:
>
1
OCR1A = 249;

16.000.000 / 64 = 250000 = 0,004 ms

1ms / 0,004 ms = 250 --> OCR1A = 249

von Markus P. (sebastianwurst)


Lesenswert?

Danke,
Wenn ich jetzt den Timer alle 0,1 ms auslösen will? Muss ich dann den 
TNCT1 durch 10000 nehmen,  oder ?

von Daniel V. (danvet)


Lesenswert?

Markus P. schrieb:
> Danke,
> Wenn ich jetzt den Timer alle 0,1 ms auslösen will? Muss ich dann den
> TNCT1 durch 10000 nehmen,  oder ?

Ja.

von spess53 (Gast)


Lesenswert?

Hi

>Danke,
>Wenn ich jetzt den Timer alle 0,1 ms auslösen will? Muss ich dann den
>TNCT1 durch 10000 nehmen,  oder ?

Lies dir das Kapitel 'Timer' im Datenblatt mal richtig durch. Das tut ja 
schon weh.

Und das auch:

Beitrag "Re: Problem mit Interrupt Prescaler"

auch wenn es funktioniert.

MfG Spess

von Daniel V. (danvet)


Lesenswert?

spess53 schrieb:
> Hi
>
> Lies dir das Kapitel 'Timer' im Datenblatt mal richtig durch. Das tut ja
> schon weh.
>
> Und das auch:
>
> Beitrag "Re: Problem mit Interrupt Prescaler"
>
> auch wenn es funktioniert.
>
> MfG Spess

Was tut denn daran weh?

von spess53 (Gast)


Lesenswert?

Hi

>Was tut denn daran weh?

Wozu dieses Vorgelade? Timer1 hat CTC. Außerdem hast du vergessen zu 
sagen, das man das Vorladen bei jedem Interrupt machen muss. Nur in der 
Init bringt nichts.

Und 'TCCR1B = 0x01;' ist alles andere als aussagekräftig.

MfG Spess

von (prx) A. K. (prx)


Lesenswert?

Ausserdem ist der Compiler bei den weitaus meisten 16-Bit Werten in 
IO-Registern in der Lage, sie als solche zu behandeln. Daher besteht 
keine Notwendigkeit, die Werte selbst in Bytes zu zerpflücken. Also
  OCR1A = ...
statt
  OCR1AL = ...
  OCR1AH = ...

von spess53 (Gast)


Lesenswert?

Hi

>Ausserdem ist der Compiler bei den weitaus meisten 16-Bit Werten in
>IO-Registern in der Lage,....

Und außerdem sind diese Register nach einem Reset mit 0x00 
initialisiert.

Z.B. 'TCCR1A = 0x00;' ist also unnötig.

MfG Spess

von Daniel V. (danvet)


Lesenswert?

Wow, jetzt habt ihrs mir aber gegeben :-=

Aber:
"TCCR1B = (1<<CS10)" ist für mich jetzt auch nicht ausagekräftiger, weil 
ich auch erstmal nachschauen muss, wass denn nun "CS10" ist.
Und ausserdem ist das Ganze eine Initialisierungsroutine, die den Timer 
auf die Anfangswerte setzen soll. Egal, wie die Werte vorher gestanden 
haben.

Schön, dass ihr das anders macht.

von Justus S. (jussa)


Lesenswert?

Daniel V. schrieb:
> "TCCR1A = (1<<CS10)" ist für mich jetzt auch nicht ausagekräftiger, weil
> ich auch erstmal nachschauen muss, wass denn nun "CS10" ist.

das da ei ClockSelect-Bit gesetzt wird ist aber sofort klar, dafür muss 
man nicht nachschauen...im Gegensatz zu deiner Schreibweise, wo man 
überhaupt nicht weiss, was gerade gesetzt werden soll

von Markus P. (sebastianwurst)


Lesenswert?

Also,
ich habe jetzt diese Einstellungen:
1
  TCCR1B = 0x00; //stop
2
  TCNT1L = (0xFFFF - F_CPU/1000 +1) & 0x0FF;
3
  TCNT1H = ((0xFFFF - F_CPU/1000 +1)>>8) & 0x0FF;
4
  TCCR1A = 0x00;
5
  TCCR1C = 0x00;
6
  TCCR1B = 0x01; //start Timer, no prescale
7
  OCR1A   = 256;  
8
  TIMSK1 |= (1<<OCIE1A);             // Interrupt nach Overflow

und das mache ich in der ISR:
1
ISR (TIMER1_COMPA_vect)
2
{
3
counter++;
4
}

Wenn ich den Counter so Abfrage:
1
if (counter >= 1000)
2
{
3
USART_Transmit('1');
4
counter=0;
5
}

Warum wird alle 4 Sekunden nur eine 1 ausgegeben ?
Verstehe das nicht....

von Markus P. (sebastianwurst)


Lesenswert?

Ich weiß das pushen macht man eigentlich nicht, aber ich sitze immer 
noch an dem Problem und ich will das heute noch verstehen ;-(
Wäre über jede Hilfe sehr dankbar !

von spess53 (Gast)


Lesenswert?

Hi

>Warum wird alle 4 Sekunden nur eine 1 ausgegeben ?
>Verstehe das nicht....

Habe ich doch schon hier

Beitrag "Re: Problem mit Interrupt Prescaler"

geschrieben. Daniel V. (danvet) hat vergessen, dazu zu sagen, das

  TCNT1L = (0xFFFF - F_CPU/1000 +1) & 0x0FF;
  TCNT1H = ((0xFFFF - F_CPU/1000 +1)>>8) & 0x0FF;

in jedem Interrupt ausgeführt werden muß.

Nimm einfach CTC.

MfG Spess

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.