Forum: Mikrocontroller und Digitale Elektronik ATMEGA8: LED über Timer-Interrupt blinken lassen funktioniert nicht


von Dennis (Gast)


Lesenswert?

Hallo,

ich habe folgenden Code programmiert:
1
#include <avr/io.h>      // Header-Dateien definieren
2
#include <avr/interrupt.h>
3
4
#define int overflow=0;
5
6
int main (void)
7
{
8
  DDRB = 00000000;   // PORTB als Ausgang setzen
9
  PORTB = 00000000;  // Die Pins am PortB auf Null setzen
10
  
11
  TIMSK = 00000001;  // Overflow Interrupt aktivieren
12
  TCCR0 = 00000101;  // Prescaler auf 1024 setzen, Takt = 8MHz
13
  TCNT0 = 00000000;  // Timer auf 0 setzen
14
  sei();             // Globale Interrupts aktivieren
15
  while (1)
16
  {
17
  }
18
}
19
20
ISR(TIMER0_OVF_vect)
21
{
22
  if (overflow <= 130)  // Wenn Overflow-Variable <= 130 dann
23
  {
24
    overflow ++;        // Erhöhe Overflow um 1
25
  }
26
  else
27
  {
28
    PORTB = ~PORTB;     // Invertiere die Ausgänge an PORTB
29
    overflow = 0;       // Setze Overflow wieder auf 0
30
  }
31
  
32
}
Leider bleibt die LED die ganze Zeit dunkel. Die Verdrahtung stimmt 
soweit, da ich die LED über die Main-Funktion einschalten kann. 
Anscheinden wir die Interrupt-Routine nicht ausgelöst.

Hat Jemand ein Idee was das sein kann? Die SuFu hat mich leider nicht 
weiter gebracht.

Vielen Dank im Voraus
Dennis

von Morgenmuffel (Gast)


Lesenswert?

Ist das Absicht, dass die Deklaration von overflow mit einem #define 
beginnt?

von Karl H. (kbuchegg)


Lesenswert?

> #define int overflow=0;

was macht das #define hier?

>   DDRB = 00000000;   // PORTB als Ausgang setzen

0 ist nicht Ausgang.
Ausserdem denke ich, dass du da sicher keine Oktalzahl angeben wolltest

>   PORTB = 00000000;  // Die Pins am PortB auf Null setzen

>  TIMSK = 00000001;  // Overflow Interrupt aktivieren

gewöhn dir so einen Mist gleich gar nicht an. Benutze die Bitnamen

>  TCCR0 = 00000101;  // Prescaler auf 1024 setzen, Takt = 8MHz

Das hier macht garantiert nicht das, was du haben willst


Wie gesagt: Benutze die Bitnamen, dann passiert dir so ein Scheiss nicht


  DDRB = 0xFF;   // Alle Bits an Port B auf Ausgang

  TIMSK |= ( 1 << TOIE0 );
  TCCR0 |= ( 1 << CS02 ) | ( 1 << CS00 );
1
TOIE0       _T_imer _O_verflow _I_nterrupt _E_nable für den Timer 0
2
CS02, CS00  Das sind die Prescaler Bits laut Datenblatt

An welcher Bitposition die Bits sitzen, will ich gar nicht wissen. Aus 
dem Datenblatt zum µC erfahre ich, wie die Bits heißen und diese Namen 
werden auch im Programm benutzt. Du benutzt ja auch die Registernamen, 
wie im Datenblatt.

von Dennis S. (dennnis)


Lesenswert?

Das ich soviel haue kriege, damit hab ich nicht gerechnet. Aber zu Recht 
:-)
Hier nur der Vollständigkeit halber der finale, funktionierende! Code:

#include <avr/io.h>         // Header-Dateien definieren
#include <avr/interrupt.h>

uint16_t overflow=0;
                                     // 8000000 Takte / 256 ZählerMax
                                     // = 31250 >> 1 Interrupt pro 
Sekunde
uint16_t LED_Freq = 3125;       // 31250 / ZielLEDFrequenz, z.B. 10
                                     // = 31250/10 => 3125

int main (void)
{
  DDRB = 0x01;         //Pin1 an PORTB auf Ausgang setzen
  PORTB &= ~(1<<0);       //Pin1 am PORTB auf Null setzen

  TIMSK |= (1<<TOIE0);         //Overflow Interrupt aktivieren
  TCCR0 |= (1<<CS00);       // Prescaler auf 1 setzen, Takt = 8MHz
  sei();           // Globale Interrupts aktivieren
  while (1)
  {
  }
}

ISR(TIMER0_OVF_vect)
{
  if (overflow <= LED_Freq)// Wenn Overflow-Variable <= LED_Freq dann
  {
    overflow ++;       // Erhöhe Overflow um 1
  }
  else
  {
    PORTB ^= (1<<PB0)   // Invertiere die Ausgänge an PORTB
    overflow = 0;      // Setze Overflow wieder auf 0
  }

Danke für den Hinweis, für mich schien es einfacher das in binärer 
Schreibweise zu schreiben. Nach der Auseinandersetzung mit der 
Bitmanipulation ist jetzt alles Roger :-)

Gruß
Dennis

von Karl H. (kbuchegg)


Lesenswert?

Dennis Scholz schrieb:

> Danke für den Hinweis, für mich schien es einfacher das in binärer
> Schreibweise zu schreiben.

Tja.
Das Problem ist, dass
1
  TCCR0 = 00000101;  // Prescaler auf 1024 setzen, Takt = 8MHz
keine Binärschreibweise ist.
Damit hast du die Bits 6 und 0 gesetzt und nicht 2 und 0.

Das ist nämlich Oktalschreibweise und nicht Binär. Binär wäre gewesen
1
  TCCR0 = 0b00000101;  // Prescaler auf 1024 setzen, Takt = 8MHz

und das ist was ganz anderes. Siehst du das kaum zu sehende 0b am Anfang 
der Zahl? Das macht den Unterschied.

Aber mit den Bitnamen stellt sich dieses Problem gleich erst gar nicht. 
Mit den Bits musst du gar nicht wissen, dass zb TOIE0 das Bit 0 ist. Bei 
einem anderen Prozessor ist TOIE0 vielleicht das Bit 5 im TIMSK. Ist dir 
aber egal, denn mit
1
  TIMSK |= (1<<TOIE0);
wird immer das richtige Bit gesetzt, egal ob es jetzt 0 oder 5 ist. Es 
muss nur im TIMSK sein.

von Dennis (Gast)


Lesenswert?

Super Erklärung, verstehe was Du meinst.

Vielen Dank

von Electronics'nStuff (Gast)


Lesenswert?

Gibt es eigentlich einen bestimmten Grund, dass Zahlen ohne "Vornamen" 
wie 0x.. oder eben 0b automatisch oktal sind? Wäre dezimal nicht ein 
wenig einleuchtender?

von Karl H. (kbuchegg)


Lesenswert?

Electronics'nStuff schrieb:
> Gibt es eigentlich einen bestimmten Grund, dass Zahlen ohne "Vornamen"
> wie 0x.. oder eben 0b automatisch oktal sind?

Es ist nicht 'der Vorname'. Zumindest nicht der, den du meinst.

Es ist die 'führende 0', die aus einer dezimalen 13 eine oktale 013 
(=dezimal 11) macht.

Hätte seine 'Binärzahl'
1
  TCCR0 = 10000101;  // Prescaler auf 1024 setzen, Takt = 8MHz
gelautet, dann wäre das dezimal 10 Millionen einhundert eins gewesen.

C ist voll mit so 'kleinen Fallen'.
Genau das ist der Grund, warum ich unermüdlich predige: Kauft euch ein 
ordentliches C-Buch und arbeitet es durch!
Denn da sind diese Dinge alle beschrieben - die muss man nur wissen, 
dann sind sie kein Problem mehr. Aber nur durch Versuch&Irrtum und 
halbseidenen Online-Tutorien bei denen man immer nur das interessierende 
Kapitel liest, kriegt man solche Dinge nie raus.

von Alex (Gast)


Lesenswert?

Habe einen ganz ähnlichen Code, der auch das gleiche machen soll. Nur 
wenn ich den Simulator anschmeiße geht der nie in den Interrupt. Wenn 
ich mir einen Breakpoint setze, wird gleich angezeigt, dass der nicht 
erreicht wird. Selbst wenn ich exakt diesen Code verwende. Achso, 
AtmelStudio 6 :)

Sry, dass ich diesen alten Thread wieder ausgrabe.

von Karl H. (kbuchegg)


Lesenswert?

Alex schrieb:
> Habe einen ganz ähnlichen Code,


Na dann passt es doch!
Dann wird die Antwort bzw. die Erklärung auch irgendwie ganz ähnlich 
sein.

> Sry, dass ich diesen alten Thread wieder ausgrabe.
Anstatt einen himmel alten Thread auszugraben, hättest du auch einen 
neuen anfangen können (denn dein Problem hat mit einiger Sicherheit 
nichts mit dem Problem des TO zu tun) und du hättest deinen Code zeigen 
können.
Das hätte allen, inklusive dir, wesentlich mehr geholfen.

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.