Forum: Mikrocontroller und Digitale Elektronik ATMega128 Timer zu langsam


von kalhou (Gast)


Lesenswert?

Hi..

Ich habe folgendes Problem. Und zwar versuche ich einen einen Timer 
einzustellen, der alle 25ms einen Interrupt auslöst.Im Betrieb ist der 
Timer allerdings zu langsam und mir schenint nicht klar warum.

Der Controller wird mit 14745600 Hz betrieben
1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
//Interrupt definieren
5
#define system_tick()  ISR(TIMER1_OVF_vect) 
6
7
system_tick()  {  
8
  
9
  //LEDS invertieren
10
  PORTA ^= 0xFF;  
11
}
12
13
int main(void){
14
15
  DDRA  = 0xFF;  
16
  PORTA = 0;
17
  
18
  //Timer Register auf 360 setzen
19
  TCNT1H = 0x01;
20
  TCNT1L = 0x68;
21
  
22
  //Overflow Interrupt aktivieren
23
  TIMSK |= (1<<TOIE1); 
24
  
25
  //TIMER1 Prescaler von 1024 einstellen und starten
26
  TCCR1B  |= (1<<CS12) | (1<<CS10); 
27
  
28
  //Interrupts Enable
29
  sei();
30
  
31
  for(;;){
32
  }
33
  
34
  //Interrupts Disable
35
  cli();
36
37
}

Wie man sieht ist der Prescaler auf 1024 eingestellt.

14745600  / 1024  = 14400
14400  / 360 = 40
1 / 40 = 0.025[s]

also sollte das soweit stimmen. Jedoch ist die Dauer im Test ca. 1 
Sekunde lang.

Hat Jemand eine Ahnung woran das liegen könnte?

von Johannes M. (johnny-m)


Lesenswert?

Erstens zählt der Timer aufwärts und macht also bei einem Preload von 
360 immerhin 65536 - 360 = 65176 Schritte bis zum Überlauf, was ungefähr 
dem 180-fachen des gewünschten Wertes entspricht. Zweitens macht man 
sowas beim AVR nicht mit Timer-Vorladen, sondern mit der Compare-Einheit 
im CTC-Modus. So wie es oben steht wird das ganze sowieso nur einmal mit 
der gewünschten Zeit laufen, weil Du in der ISR das Timer-Zählregister 
nicht wieder lädst. Und da steht dann sowieso Null drin. Mit CTC 
brauchst Du nur einmal den Wert ins Compare-Register zu schreiben, den 
Rest macht der µC selbst.

BTW:
Weiß der µC überhaupt, dass er mit dem Quarz arbeiten soll (Fusebits 
korrekt gesetzt)?

von kalhou (Gast)


Lesenswert?

1
#include <avr\io.h>
2
#include <avr\interrupt.h>
3
4
//Interrupt definieren
5
#define system_tick()  ISR(SIG_OUTPUT_COMPARE1A)  //Compare Interrupt
6
7
system_tick()  {  
8
  //Timer zurücksetzen
9
  TCNT1H = 0x00;
10
  TCNT1L = 0x00;
11
  
12
  //LEDS invertieren
13
  PORTA ^= 0xFF;  
14
  
15
}
16
17
int main(void){
18
19
  DDRA  = 0xFF;  
20
  PORTA = 0;
21
  
22
  //Compare Register A  auf 360 setzten
23
  OCR1AH = 0x01;
24
  OCR1AL = 0x68;
25
  
26
  
27
  //Compare Interrupt aktivieren
28
  TIMSK |= (1<<OCIE1A);
29
  
30
  //TIMER1 Prescaler von 1024 einstellen und starten
31
  TCCR1B  |= (1<<CS12) | (1<<CS10); 
32
  
33
  //Interrupts Enable
34
  sei();
35
  
36
  for(;;){
37
  }
38
  
39
  //Interrupts Disable
40
  cli();
41
42
}

hat sich erledigt ;)

vielen dank

von Johannes M. (johnny-m)


Lesenswert?

kalhou wrote:
>
1
> system_tick()  {
2
>   //Timer zurücksetzen
3
>   TCNT1H = 0x00;
4
>   TCNT1L = 0x00;
5
>
Timer Zurücksetzen kannst Du Dir sparen (und solltest Du auch, weil 
dadurch die Genauigkeit leidet). Im CTC-Modus wird der Timer automatisch 
beim Compare-Ereignis zurückgesetzt.

>
1
>   //Compare Register A  auf 360 setzten
2
>   OCR1AH = 0x01;
3
>   OCR1AL = 0x68;
4
>
Warum so kompliziert? Ein einfaches
1
OCR1A = 360;
tut's auch. Und vor allem nimmt der Compiler Dir dabei die Sache mit der 
richtigen Reihenfolge ab.

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.