Forum: Mikrocontroller und Digitale Elektronik Timer zählt zu langsam


von Patrick R. (pat711)


Lesenswert?

Abend zusammen,

ich schmore gerade über folgendem Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include "lcd-routines.h"
5
#include <stdlib.h>
6
7
 
8
//Variablen für die Zeit
9
volatile unsigned int  millisekunden=0;
10
volatile unsigned int  sekunde=0;
11
12
int main(void)
13
{
14
  TCCR2 =(1<<WGM21) | (1<<CS00) | (1<<CS01);    //Prescaler 64 / OCR0 125: 8MHz:64:125 = 1KHz
15
  OCR2=125;
16
  TIMSK|=(1<<OCIE2);
17
  sei();                          //3)Interrupts aktivieren
18
19
   while(1)
20
   {
21
   }
22
 
23
   return 0;
24
}
25
 
26
ISR (TIMER2_COMP_vect)              //4)Führe diese ISR bei Overflow von TCNT0 aus
27
{
28
  millisekunden++;
29
  if (millisekunden == 1000)
30
  {
31
    sekunde ++;
32
    millisekunden = 0;
33
  }
34
  // ... umwandeln siehe FAQ Artikel bei www.mikrocontroller.net
35
  // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include <stdlib.h>
36
  char Buffer_ms[20]; // in diesem {} lokal
37
  itoa( millisekunden, Buffer_ms, 10 ); 
38
  // ... ausgeben 
39
  char Buffer_s[20]; // in diesem {} lokal
40
  itoa( sekunde, Buffer_s, 10 ); 
41
  // ... ausgeben 
42
  lcd_init();
43
  set_cursor(7,1);
44
  lcd_string( Buffer_ms );
45
  set_cursor(0,1);
46
  lcd_string( Buffer_s );
47
}

und kann mir nicht erklären warum der zu langsam zählt.

Taktfrequenz ist 16MHz, fuses dafür sind gesetzt.
Eigentlich sollte es ja laut der Formel:
16 000 000  64  250 = 1000
in einer sekunde 1000 interrupts geben. und da 1sec = 1000ms sollte des 
j stimmen...

kann mir vll jemand helfen?

Mfg, Pat

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

1
  lcd_init();
2
  set_cursor(7,1);
3
  lcd_string( Buffer_ms );
4
  set_cursor(0,1);
5
  lcd_string( Buffer_s );
Das alles in einem Interrupt?
Wie lange dauert denn z.B. lcd_init()?
Sowas gehört in die leere while(1)-Schleife  :-o

von HerrBrause (Gast)


Lesenswert?

TCCR2 =(1<<WGM21) | (1<<CS20) | (1<<CS21);

von holger (Gast)


Lesenswert?

>Wie lange dauert denn z.B. lcd_init()?
>Sowas gehört in die leere while(1)-Schleife  :-o

lcd_init() gehört nicht unbedingt in die while(1) ;)

von Stefan E. (sternst)


Lesenswert?

Schau nochmal genau hin. Die Formel im Datenblatt beschreibt etwas 
anderes (nicht Interrupts pro Sekunde), deshalb hast du einen 
Fehlerfaktor von 2 drin.

von Patrick R. (pat711)


Lesenswert?

thx für die schnelle Hilfe, nun gehts habs noch n bissle mehr 
abgeändert.^^
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include "lcd-routines.h"
5
#include <stdlib.h>
6
7
 
8
//Variablen für die Zeit
9
volatile unsigned int  millisekunden=0;
10
volatile unsigned int  sekunde=0;
11
12
int main(void)
13
{
14
  TCCR2 =(1<<WGM21) | (1<<CS20) | (1<<CS21);    //Prescaler 64 / OCR0 125: 8MHz:64:125 = 1KHz
15
  OCR2=250;
16
  TIMSK|=(1<<OCIE2);
17
  sei();                          //3)Interrupts aktivieren
18
19
   while(1)
20
   {
21
   }
22
 
23
   return 0;
24
}
25
26
void anzeigen (void)
27
{
28
    // ... umwandeln siehe FAQ Artikel bei www.mikrocontroller.net
29
  // WinAVR hat eine itoa()-Funktion, das erfordert obiges #include <stdlib.h>
30
  char Buffer_ms[20]; // in diesem {} lokal
31
  itoa( millisekunden, Buffer_ms, 10 ); 
32
  // ... ausgeben 
33
  char Buffer_s[20]; // in diesem {} lokal
34
  itoa( sekunde, Buffer_s, 10 ); 
35
  // ... ausgeben 
36
  lcd_init();
37
  set_cursor(7,1);
38
  lcd_string( Buffer_ms );
39
  set_cursor(0,1);
40
  lcd_string( Buffer_s );
41
}
42
43
ISR (TIMER2_COMP_vect)              //4)Führe diese ISR bei Overflow von TCNT0 aus
44
{
45
  millisekunden++;
46
  if (millisekunden == 1000)
47
  {
48
    sekunde ++;
49
    millisekunden = 0;
50
  }
51
  if(millisekunden % 100 == 0)
52
  {
53
  anzeigen();
54
  }
55
}

von MeinerEiner (Gast)


Lesenswert?

Reicht es nicht, das LCD nur 1x beim Programmstart zu initialisieren?

von Stefan E. (sternst)


Lesenswert?

Und wenn du es noch ein wenig korrekter machen möchtest, dann änderst du 
die 250 in 249.

von holger (Gast)


Lesenswert?

Nimm das lcd_init() aus anzeigen() raus und pack es vor diesen Befehl
in main():

  sei();                          //3)Interrupts aktivieren

von Steffan (Gast)


Lesenswert?

>anzeigen();

Gehört nicht in die ISR.

von HerrBrause (Gast)


Lesenswert?

Jo, nimm einen zweiten Timer und lass anzeigen() regelmäßig aufrufen.

von Patrick R. (pat711)


Lesenswert?

achso also prakrisch durch den 2. Timer dann bestimmen wie oft die 
anzeige aktualisiert wird?

edit:  hab nu die Änderungen ( bis auf das mit der anzeigen funktion) 
vorgenommen aber jetzt ist der irgendwie zu schnell????

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> nimm einen zweiten Timer
Wenn anzeigen() gerade ausgeführt wird, und länger als 1 ms dauert, dann 
hilft auch ein zweiter Timer nichts...

Richtigerweise wird lcd_init() genau 1 mal gemacht. Und dann in der 
Hauptschleife das anzeigen(). Für das Ausführen von anzeige() wird in 
der ISR ein Flag gesetzt.
Etwa so:
1
volatile char updateanzeige;
2
:
3
main () {
4
   while(1)
5
   {
6
     if (updateanzeige) {
7
        anzeigen();
8
        updateanzeige=0;  // fertig, Flag löschen
9
     }
10
   }
11
12
}
13
:
14
ISR (TIMER2_COMP_vect)              //4)Führe diese ISR bei Overflow von TCNT0 aus
15
{
16
  if (millisekunden == 1000)
17
  {
18
    sekunde ++;
19
    millisekunden = 0;
20
  }
21
  if(millisekunden % 100 == 0)
22
  {
23
    updateanzeige=1;  // Flag setzen
24
  }
25
}

von Stefan E. (sternst)


Lesenswert?

Patrick R. schrieb:
> edit:  hab nu die Änderungen ( bis auf das mit der anzeigen funktion)
> vorgenommen aber jetzt ist der irgendwie zu schnell????

Um welchen AVR geht es denn genau?
Beim Mega8 z.B. sind CS20+CS21 ein Teiler von 32 (und nicht 64).

von Patrick R. (pat711)


Lesenswert?

ah ok dann is klar warums net geht is nemmich genau der ^^. Tja das war 
wohl ein blick ins datenblatt zu wenig ^^ thx


edit: hab nu im datenblatt folgendes gefunden:
The prescaled clock has a frequency of either f/8, f/64, f/256 or f/1024

also müsse der doch stimmen...

von Stefan E. (sternst)


Lesenswert?

Patrick R. schrieb:

> edit: hab nu im datenblatt folgendes gefunden:
> The prescaled clock has a frequency of either f/8, f/64, f/256 or f/1024

Jede Wette, das Zitat stammt aus den Kapitel:
Timer/Counter0 and Timer/Counter1 Prescalers
(du verwendest Timer2)

Kann hier aber keiner wirklich kontrollieren, da wir ja immer noch nicht 
wissen, welcher AVR.

von Patrick R. (pat711)


Lesenswert?

hab vorher das geschrieben:
>ah ok dann is klar warums net geht is nemmich genau der<
-> also n ATmega8

hab den code nun überarbeitet und (1<<CS22) gesetzt, nun zählt er im 
richtigen tempo ^^

Vielen Dank nochmal für eure hilfe

von Stefan E. (sternst)


Lesenswert?

Sorry, das "is nemmich genau der" hatte ich übersehen.

von Patrick R. (pat711)


Lesenswert?

war au leich zu übersehn ^^ sry nächstes mal machichs deutlicher

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.