Timerstart

OP #285393
Lesenswert?
• ▲
▼
Hi,
ich habe zum Lernen und Verstehen des ATMega8's auf einem myAVR-Board
ein Programm geschrieben, das die 3 Leuchtdioden binärmäßig
sekundnweise schalten soll:

#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>

#define TL 0xf7
#define TH 0xc2

unsigned char i=0;

int main(void)
{
DDRD = 0x00;
PORTD |= (1<<PD2) | (1<<PD3);
DDRB = 0xff;
PORTB = 0x00;
TCCR1B |= (1<<CS00) | (1<<CS02);
TCNT1L = TL;
TCNT1H = TH;
TIMSK |= (1<<TOIE1);
TCNT1L = TL;
TCNT1H = TH;
sei();

while (1) {}

return 0;
}

SIGNAL(SIG_OVERFLOW1)
{
i = PINB;
i++;
if (i==8) i=0;
PORTB =i;
TCNT1L = TL;
TCNT1H = TH;
}

Meine Frage bezieht sich auf die Zeilen
TCNT1L = TL;
TCNT1H = TH;
TIMSK |= (1<<TOIE1);
TCNT1L = TL;
TCNT1H = TH;

Es kommt mir dämlich vor, zweimal die TCNT1x initialisieren zu müssen,
ansonsten (egal, welche der beiden ich weglasse) zählt der Timer
erstmal von FFFF runter, d.h. die erste LED geht (bei 16MHz) erst nach
ca. 4s an.
Mache ich was falsch?

Gruß, Axel
Gast #285394
Lesenswert?
• ▲
▼
Hi,

der Teil außerhalb der while(1)-Schleife deines main-Programmes läuft
ja nur einmal. Dort wird der Timer mit TL/TH vorgeladen und beim Setzen
des Prescalers läuft der Timer los. Nach 1 Sekunde kommt der gewollte
Überlauf. Zu diesem Zeitpunkt ist der aktuelle Zählerstand (TL/TH) = 0.


Wenn du innerhalb der Überlauf-ISR (SIGNAL(OVERFLOW)) den Timer nicht
wieder mit den Standardwerten lädst, zählt er keine Sekunde mehr
sondern von 0...65535 (0...0xFFFF).

In deinem Programm setzt du den Timer bei einem Überlauf immer wieder
auf 0xC2F7 (49911). Von diesem Wert zählt der Timer dann wieder bis
0xFFFF (65535). Du wirst mir Recht geben, dass hier der Überlauf
schneller kommt, als wenn er von 0 bis 65535 zählen müsste.

Mfg
Tommy
Gast #285395
Lesenswert?
• ▲
▼
Sorry, war etwas zu schnell. Ich habe mir gerade nochmal deine Quelle
angeschaut.

Hast du das Programm selber geschrieben oder irgendwo abgetippt? Ich
gehe immer wie folgt vor.

(1) Timer stoppen (Prescaler ausschalten)
(2) Zählerwert (TH/TL) setzen
(3) Konfigurationen in den Registern setzen
(4) Prescaler-Bits via "OR-Verknüpfung" setzen -> Timer wird
gestoppt

Also denke ich, dass du problemlos bei deinem Quelltext die letzten
beiden Zeilen auskommentieren.
TCNT1L = TL;
TCNT1H = TH;
TIMSK |= (1<<TOIE1);
//TCNT1L = TL;
//TCNT1H = TH;

Also einfach mal probieren...

Viele Grüße
Tommy
Moderator Persönliche Seite #285397
Lesenswert?
• ▲
▼
Mal diverse Anmerkungen in wahlloser Reihenfolge.
1
#define TL 0xf7
2
#define TH 0xc2
3
...
4
TCNT1L = TL;
5
TCNT1H = TH;

Sorry, aber das würde ich als ,,Assemblerprogrammierung mit
C-Syntax''
bezeichnen.  (Selbst in Assembler kann man das besser formulieren.)

Ich würde das so schreiben:
1
#include <stdint.h>
2

3
#include <avr/io.h>
4

5
#define F_CPU 16000000ul
6

7
#define TMR1_PRESCALER 1024
8
/* 1-second overflow preset value */
9
#define TMR1_PRESET ((uint16_t)(-(F_CPU / TMR1_PRESCALER)))
10

11
void ioinit(void)
12
{
13
  ...
14
  TCNT1 = TMR1_PRESET;
15
}
1
unsigned char i=0;

Diese Variable sollte static innerhalb der ISR sein, denn nur dort
wird sie gebraucht.
1
TCCR1B |= (1<<CS00) | (1<<CS02);

Schönheitsfehler: du setzt Timer 1, aber nimmst die Definitionsbits
von Timer 0.

Meine Variante:
1
#include <stdint.h>
2

3
#include <avr/interrupt.h>
4
#include <avr/io.h>
5
#include <avr/sleep.h>
6

7
#define F_CPU 16000000ul
8

9
#define TMR1_PRESCALER 1024
10
/* 1-second overflow preset value */
11
#define TMR1_PRESET ((uint16_t)(-(F_CPU / TMR1_PRESCALER)))
12

13
void ioinit(void)
14
{
15
  /* Enable pullups */
16
  PORTD |= (1<<PD2) | (1<<PD3);
17
  /* LED outputs */
18
  DDRB = 0xff;
19

20
  /* Prepare timer 1... */
21
  TCNT1 = TMR1_PRESET;
22
  TIMSK |= (1<<TOIE1);
23
  /* ...and kick it. */
24
  TCCR1B |= (1<<CS10) | (1<<CS12);
25

26
  sei();
27
}
28

29
ISR(TIMER1_OVF_vect)
30
{
31
  uint8_t i;
32

33
  TCNT1 = TMR1_PRESET;
34
  i = PORTB;
35
  PORTB = (i & ~7) | (((i & 7) + 1) & 7);
36
}
37

38
int
39
main(void)
40
{
41
  ioinit();
42
  for (;;)
43
    sleep_mode();
44
  return 0;
45
}

(Für avr-libc < 1.4.x musst du ISR durch SIGNAL ersetzen und den alten
Vektornamen benutzen.)

Im Simulator blinkt zumindest die LED im Sekundentakt.

Das Ganze hat natürlich rein akademischen Wert: in der Praxis würde
ich statt der umständlichen und mit Jitter behafteten Methode des
Overflow-Interrupts den CTC-Modus des Timers nehmen.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

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.