Eigener prescaler funktioniert nicht

Gast #3712366
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?
#3712380
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.
Gast #3712397
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
}

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.