Forum: Compiler & IDEs Eigener prescaler funktioniert nicht


von Sherlock´s Tone (Gast)


Lesenswert?

Hallo Leute,

ich setze mich momentan mit Timern auseinander und bin auf folgendes 
Problem gestoßen:

Ich habe einen CTC Timer Programmiert und OCR0 auf 50-1 gesetzt.
Da ich einen Quarz von 7,3728MHz verbaut hatte und lediglich eine LED im 
1Hz Takt als Test blinken lassen wollte, habe ich mir einfach selber 
einen prescaler programmiert:
1
uint32_t prescale = 0;
2
3
.
4
.
5
.
6
.
7
8
if (prescale >=73728)
9
{
10
  PORTB ^= (1<<LED);
11
  prescale = 0;
12
}
prescale wird bei jedem compare match um 1 erhöht.


Als ich das Programm testete, habe ich jedoch festgestellt, das die LED 
nicht im exakten Takt zu blinken scheint und ich durch ändern des OCR0 
Wertes keine korrekte Frequenzänderung habe...

Nach langen versuchen und ausprobieren entschied ich mich dafür einfach 
mal einen "richtigen" prescaler zu verwenden.
Folglich setzte ich das CS02 Bit, um den prescaler von 1024 zu 
verwenden.

So sieht der angepasste Code aus:
1
if (prescale >=73728/1024)
2
{
3
  PORTB ^= (1<<LED);
4
  prescale = 0;
5
}
Nach diesem eingriff funktioniert das Programm komischer weise 
einwandfrei und exakt.
Nun frage ich mich trotzdem woran das liegt? Im Grunde ist dies doch das 
selbe oder?

von Jürgen S. (jurs)


Lesenswert?

Sherlock´s Tone schrieb:
> Ich habe einen CTC Timer Programmiert und OCR0 auf 50-1 gesetzt.
> ...
> uint32_t prescale = 0;
> ...
> if (prescale >=73728)
> ...
> prescale wird bei jedem compare match um 1 erhöht.
>
>
> Als ich das Programm testete, habe ich jedoch festgestellt, das die LED
> nicht im exakten Takt zu blinken scheint und ich durch ändern des OCR0
> Wertes keine korrekte Frequenzänderung habe...

Dein Programm enthält mindestens zwei Anfängerfehler im Zusammenhang mit 
Interruptprogrammierung.

Variablen, auf die Du sowohl von einer Interruptbehandlungsroutine als 
auch von normalem Code aus zugreifst, müssen "volatile" deklariert sein.

Und wenn die Variable mehr als 8 Bit groß ist, mußt Du die Interrupts 
sperren, wenn Du sie außerhalb einer Interruptroutine ausliest.

von Sherlock´s Tone (Gast)


Lesenswert?

Danke für deine Antwort,

ich habe volatile nur vergessen mit reinzuschreiben und das wegen cli(); 
und sei(); habe ich getestet, jedoch bleibt dieses Problem bestehen.

Hier mein ganzer Quellcode:
1
//Quarz = 7.372.800 Hz
2
3
4
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
8
9
10
#define LED PB0
11
12
volatile uint32_t prescale = 0;
13
14
15
void Timer1 (void)
16
{
17
18
  
19
  
20
  TIMSK |= (1<<OCIE0); //Interupt bei compare match
21
  TCCR0 |= (1<<WGM01) | (1<<CS00); //CTC Modus, (TCNT0 start)
22
  OCR0 = 50-1;
23
  TCNT0 = 0;
24
}
25
26
int main(void)
27
{
28
  Timer1();
29
  DDRB |= (1<<LED);
30
31
  
32
  
33
  sei();
34
35
    while(1)
36
    {
37
    cli();
38
    if (prescale >=73728)
39
    {
40
      PORTB ^= (1<<LED);
41
      prescale = 0;
42
    }
43
    sei();
44
    }
45
}
46
47
ISR (TIMER0_COMP_vect)
48
{
49
  prescale++;
50
}

von Stefan E. (sternst)


Lesenswert?

Vermutlich wird deine ISR mehr als 50 Takte zur Ausführung benötigen.

von Sherlock´s Tone (Gast)


Lesenswert?

Hmm naja dann muss ich wohl damit leben und hoffen das ich diesen Fehler 
beim nächsten mal schnell finde...

Danke für eure Antworten!

MfG Alex

von Verwirrter (Gast)


Lesenswert?

>Variablen, auf die Du sowohl von einer Interruptbehandlungsroutine als
>auch von normalem Code aus zugreifst, müssen "volatile" deklariert sein.
Warum denn das ?

von Jürgen S. (jurs)


Lesenswert?

Verwirrter schrieb:
>>Variablen, auf die Du sowohl von einer Interruptbehandlungsroutine als
>>auch von normalem Code aus zugreifst, müssen "volatile" deklariert sein.
> Warum denn das ?

Die kurze Antwort:
http://www.mikrocontroller.net/articles/Interrupt#Volatile_Variablen

Die lange Antwort:
http://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich

von Uwe (de0508)


Lesenswert?

Hallo  Sherlock

was ich nicht verstehe ist, dass Du den Timer ohne Vorleiter laufen 
lässt.

Dann muss die Timer-ISR die ganze Arbeit machen.

Üblicherweise wählt man einen ISR Frequenz von 1000Hz (1ms) - 100Hz 
(10ms).

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Stefan Ernst schrieb:
> Vermutlich wird deine ISR mehr als 50 Takte zur Ausführung benötigen.

  4 * Push
+ 4 * LDS
+ 4 * SUBI/SBCI
+ 4 * STS
+ 4 * POP
+ Prolog, Epilog
= 61 Zyklen.

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.