Forum: Mikrocontroller und Digitale Elektronik Atmega32 - 8-Bit-Timer


von Dietmar P. (dietmar2)


Lesenswert?

Hallo,

wieder einer, der seine Hausaufgaben nicht alleine machen kann.

Ich taste mich an den Timer im Atmega 32 ran und habe ein kleines 
Testprogramm dazu geschrieben, nur tut es nicht. Die C-Syntax ist wohl 
richtig, aber die Timer-Logik nicht.

Habe versucht nach dem Datenblatt folgende Aufgabe zu lösen:
- Taktfrequenz Prozessor intern 1 Mhz
- Prescaler auf 1024 setzen
- Overflow zählen
- bei jeweils vierten Überlauf LED an Pin 0 von PORTA an- bzw. 
ausschalten
  (Ergebnis sollte ein Blinkimpuls von ca. einer Sekunde sein)

Hier mein Code:
1
// Timer Testprogramm
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <stdint.h>
6
7
  volatile unsigned int Counter = 0;  // Zähler für Timer
8
  uint16_t i = 0;           // Zähler bei Bedarf verwendet
9
10
  ISR(SIG_OUTPUT_COMPARE0)    // Timer 0 overflow ISR
11
  {
12
    Counter++;
13
  }
14
15
int main(void)
16
{  
17
  
18
  DDRA = 0xff;    // PORTA auf Ausgang
19
  PORTA = 0xff;    // internal pullup on 
20
  
21
// ********** Timer init ******
22
23
  TCNT0 = 0x00;        //Timer 0 mit Null initialisieren
24
  TCCR0 = ( 1 << CS02 ) | ( 1 << CS00 ); // Teiler: 1024
25
  TIMSK = ( 1 << TOIE0 );     // Overflow Interrupt einschalten
26
  TIMSK |= (1 << OCIE1A);     // Vergleichsregister Interrupt für Timer einschalten
27
  sei();         // Interrupts aktivieren
28
  
29
 
30
  // ***** HAUPTROUTINE ******
31
32
  while(1){
33
34
//    _delay_ms(100);    // Verzögerung 
35
36
  if (Counter >= 4){
37
  Counter = 0;
38
  if (i==0){
39
    PORTA |= (1<<1);    // PortA Pin1 auf high 
40
    i=1;
41
    }
42
  else{
43
    i=0;
44
    PORTA &= ~(1<<1);    // PortA Pin1 auf low 
45
  }
46
     }
47
  }  //while 
48
}//main

Könnt Ihr mir bitte helfen?

von Justus S. (jussa)


Lesenswert?

Dietmar P. schrieb:

> - bei jeweils vierten Überlauf LED an Pin 0 von PORTA an- bzw.

<->
1
>     PORTA |= (1<<1);    // PortA Pin1 auf high

?

von Ziegenpeter (Gast)


Lesenswert?

>> Könnt Ihr mir bitte helfen?
Wobei?

P.S.:
>> Overflow zählen  !=  ISR(SIG_OUTPUT_COMPARE0)

von Dietmar P. (dietmar2)


Lesenswert?

Hallo,

danke für Eure Info's.

@ Justus:

Klar hatte mich vertippt, muss natürlich Pin 1 heißen.

@ Ziegenpeter:

Da ich noch keinen Timer programmiert habe, wäre eine Ergänzung / 
Korrektur der Timer Zeilen sinnvoll.

>> Overflow zählen  !=  ISR(SIG_OUTPUT_COMPARE0)

Wie setze ich das syntaktisch um?

Conter != ISR(SIG_OUTPUT_COMPARE0)

Zählt er dann so?

von Hc Z. (mizch)


Lesenswert?

Nein.  Du hast mehrere Probleme auf einmal.
1
  TIMSK = ( 1 << TOIE0 );     // Overflow Interrupt einschalten
2
  TIMSK |= (1 << OCIE1A);     // Vergleichsregister Interrupt für Timer einschalten
Hiermit schaltest Du 2 Interrupts frei (der Kommentar in der zweiten 
Zeile ist schlicht verkehrt).  Nur für einen dieser 2 gibt es eine 
Interruptroutine.  Für den anderen gibt es keine, und das heißt, dass 
der Default-Handler dafür in Aktion tritt, denn angesprungen wird eine 
Interrupt-Routine ja trotzdem.  Und der Default-Handler macht einen 
Soft-Reset.

Und dann schau Dir mal genau an, für was Du eine Interrupt-Routine 
gebaut hast.  Das "was" steckt im Argument zu ISR(), wo Du eine 
veraltete und nicht mehr empfohlene Bezeichnung gewählt hast:
1
ISR(SIG_OUTPUT_COMPARE0)
Die funktioniert aber trotzdem noch, nur passt „Output Compare“ nicht zu 
Deiner Beschreibung, wonach Du Overflows zählen möchtest.  Für letztere 
hast Du nichts vorgesehen (was den besagten Soft-Reset ergibt).

von Karl H. (kbuchegg)


Lesenswert?

* Welchen Interrupt willst du eigentlich?

  Den Overflow

  oder den Compare Interrupt

* du solltest dir schleunigst angewöhnen, nur die Interrupts
  freizugeben, für die du auch Handler hast!
  Tritt ein Interrupt Ereignis auf, das du freigegeben hast und
  hast du keinen Handler dafür, dann wird der µC resettet.

von Dietmar P. (dietmar2)


Lesenswert?

Leute seid gnädig, ich habe ja geschrieben, dass ich mich heran taste. 
Das Datenblatt vom Atmega32 ist für einen Einsteiger schon etwas 
verwirrend. Einen Teilhabe ich aus dem Netz, offenbar verkehrt.

Nur den Overflow Interrupt wollte ich.
Ist ISR() selbst veraltet, oder das Argument in der Klammer?

Ich möchte als Test im ca. Sekundentakt den Pin1 von PortA abwechselnd 
auf high bzw. low schalten, um für weitere Anwendungen den Timer 
einsetzen zu können.
Dabei bin ich davon ausgegangen, dass 1MHz/1024/256/4 ca. 1 Hz ergibt.

von Karl H. (kbuchegg)


Lesenswert?

Dietmar P. schrieb:
> Leute seid gnädig, ich habe ja geschrieben, dass ich mich heran taste.
> Das Datenblatt vom Atmega32 ist für einen Einsteiger schon etwas
> verwirrend. Einen Teilhabe ich aus dem Netz, offenbar verkehrt.

Nein nicht verkehrt.

> Nur den Overflow Interrupt wollte ich.

Warum nimmst du dann nicht den Overflow Interrupt?
AVR-GCC-Tutorial
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR#Overflow_Interrupt

von Hc Z. (mizch)


Lesenswert?

> Ist ISR() selbst veraltet, oder das Argument in der Klammer?

Das Argument.  Siehe AVR-libc-Dokumentation, z.B. 
http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html .

von Dietmar P. (dietmar2)


Lesenswert?

Danke für Eure Hinweise und Links,
jetzt kann ich wieder weiter basteln.

von Lutz (Gast)


Lesenswert?

Dietmar P. schrieb:
> DDRA = 0xff;    // PORTA auf Ausgang
> PORTA = 0xff;    // internal pullup on

Ist übrigens auch verkehrt. Mit der zweiten Zeile schaltest Du in diesem 
Fall alle Pins in Port A auf 1, da Du Port A auch komplett als Ausgang 
definiert hast. Die zweite Zeile würde stimmen, wenn Du Port A komplett 
als Eingang geschaltet hättest (mit DDRA = 0;)

von Dietmar P. (dietmar2)


Lesenswert?

Das hatte ich wohl viel zu kompliziert gemacht.
Habe den Code gem. Eurer Hinweise geändert und läuft!
LED taktet mit ca. einer Sekunde.

Hier mein bereinigter Code:
1
// Timer Testprogramm
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <stdint.h>
6
7
  volatile unsigned int Counter = 0;  // Zähler für Timer
8
  uint16_t i = 0;           // Zähler bei Bedarf verwendet
9
10
  ISR (TIMER0_OVF_vect)
11
  {
12
    Counter++;
13
  }
14
15
int main(void)
16
{  
17
  
18
  DDRA = 0xff;    // PORTA auf Ausgang
19
  
20
// ********** Timer init ******
21
22
  TCCR0 = ( 1 << CS02 ) | ( 1 << CS00 ); // Teiler: 1024
23
  TIMSK = ( 1 << TOIE0 );     // Overflow Interrupt einschalten
24
  sei();         // Interrupts aktivieren
25
  
26
 
27
  // ***** HAUPTROUTINE ******
28
29
  while(1){
30
31
  if (Counter >= 4){
32
  Counter = 0;
33
  if (i==0){
34
    PORTA |= (1<<1);    // PortA Pin1 auf high 
35
    i=1;
36
    }
37
  else{
38
    i=0;
39
    PORTA &= ~(1<<1);    // PortA Pin1 auf low 
40
  }
41
     }
42
  }  //while 
43
}//main

von Mario G. (mario)


Lesenswert?

Es geht aber auch schicker mit dem Timer 1 (16-bit). Da kannst du dir 
nämlich den Compare ausrechnen lassen und den CTC-Mode benutzen (die 
Sekund ist allerdings nicht ganz genau, da 1Mhz nicht glatt durch 1024 
teilbar ist):
1
// Timer Testprogramm
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <stdint.h>
6
7
ISR (TIMER1_COMPA_vect)
8
{
9
   PORTA ^= (1 << PA0); 
10
}
11
12
int main(void)
13
{  
14
  
15
  DDRA = 0xff;    // PORTA auf Ausgang
16
  
17
  TCCR1B = (1<<WGM12) | (1 << CS12) | (1 << CS10); // CTC und Teiler:1024
18
  OCR1A  = (uint16_t)(F_CPU/1024);     // Overflow-Wert (gerundet)
19
  TIMSK  = (1 << OCIE1A);;             // Overflow Interrupt einschalten
20
21
  sei();         // Interrupts aktivieren
22
  
23
  for(;;)
24
  {
25
  }
26
27
}

Einfach mal in Ruhe durchgehen...

von Dietmar P. (dietmar2)


Lesenswert?

Hallo Mario,

sicher das ist eleganter, danke.
Die Sekunde muss auch nicht genau stimmen.
Schrittchen für Schrittchen wächst das Atmega- Wissen.

Gruß
Dietmar

von Mario G. (mario)


Lesenswert?

Mach dir nichts draus, hat bei mir auch ne Weile gedauert bis ich die 
umfangreichen Funktionen des Timers verstanden habe.

Gruß
Mario

von jrraid (Gast)


Lesenswert?

hat das schon mal jemand mit dem Pollin Board versucht? Bei mir 
funktioniert der code nicht. PORTS und DDR hab ich entsprechend dem 
board aufbau geändert aber nix passiert.

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.