Forum: Mikrocontroller und Digitale Elektronik LED Lauflicht mit Timer ATMEGA8


von Stefan (Gast)


Lesenswert?

Hallo zusammen,

ich möchte 8 LEDs im Sekunden-Abstand nacheinander an- und wieder 
ausschalten. Der Plan ist den Timer1 und den Interrupt bei overflow zu 
nutzen. Ich betreibe den ATM @ 1Mhz und habe den Prescaler auf 64 
eingestellt, also 15625 Zähler pro Sekunde. Im Interrupt lade ich die 
Differenz bis zum Overlow-Wert in den Counter des Timers (65536-15625 = 
49911).

Im AVR-Studio läuft das auch alles Prima, auf meinen Versuchsaufbau 
blinkt mal hier ein LED, mal dort ...

Hat da jemand eine Idee, woran es liegen könnte?

Vielen Dank und Gruß
Stefan

Hier der Code:

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

//LEDs
#define LED1 PC4
#define LED2 PC3
#define LED3 PD0
#define LED4 PD1
#define LED5 PD2
#define LED6 PD3
#define LED7 PD4
#define LED8 PD5
#define LED9 PD6
#define LED10 PD7

volatile unsigned int sec;

ISR(TIMER1_OVF_vect)
{
  sec++;
  if (sec==9) {sec = 0;}

  // ATMEGA8 @ 1MHz; Prescaler 64 => 15625 Takte/sec
  // Vorzähler auf 65536 - 15625 = 49911 einstellen
  // ==> Hochzählen alle 1 sec

  TCNT1 = 49911;
}

int main(void)
{
  TIMSK |= (1<<TOIE1);    //Interrupt bei OVF
  TCCR1B |= (1<<CS10 | 1<<CS11);  //Prescaler 64
  TCNT1 = 0xFFFF;      //starte sofort mit Interrupt
  sei();
  DDRD = 0xFF;

  //Initialwerte
  PORTD = 0x00;
  sec = 0;

  while(1)
  {
    if (sec==1) {PORTD ^= (1<<LED3);}
    if (sec==2) {PORTD ^= (1<<LED4);}
    if (sec==3) {PORTD ^= (1<<LED5);}
    if (sec==4) {PORTD ^= (1<<LED6);}
    if (sec==5) {PORTD ^= (1<<LED7);}
    if (sec==6) {PORTD ^= (1<<LED8);}
    if (sec==7) {PORTD ^= (1<<LED9);}
    if (sec==8) {PORTD ^= (1<<LED10);}
  }

  return(0);
}

von spess53 (Gast)


Lesenswert?

Hi

Was denkst du denn, wie oft deine While-Schleife in einer Sekunde 
durchlaufen wird?

MfG Spess

von Stefan (Gast)


Lesenswert?

Hoppla ;-) Danke.

von anfaenger (Gast)


Lesenswert?

Guten Abend,

Ich programmiere seit kurzer Zeit auch ein bisschen auf dem Atmega8 und 
habe eine Frage zu deinem Code.

Das Problem liegt, wenn ich das richtig sehe, dadran, dass du ^= 
schreibst und damit den Ausgang invertierst und die While-Schleife ja 
einige male mehr in der Sekunde durchläufst.
Meine Lösung wäre, die Ausgänge im Interrupt zu invertieren.

Und meine Frage dazu: Macht das Sinn, oder was ist die einfachste/beste 
Lösung an dieser Stelle?

Grüße

von Sam .. (sam1994)


Lesenswert?

anfaenger schrieb:
> Das Problem liegt, wenn ich das richtig sehe, dadran, dass du ^=
> schreibst und damit den Ausgang invertierst und die While-Schleife ja
> einige male mehr in der Sekunde durchläufst.
> Meine Lösung wäre, die Ausgänge im Interrupt zu invertieren.
Wäre möglich und bei der kleinen Aufgabe auch sinnvoll (außer es gibt 
noch andere wirklich zeitkritische Interrupts / Aufgaben)
> Und meine Frage dazu: Macht das Sinn, oder was ist die einfachste/beste
> Lösung an dieser Stelle?
Das ganze möglichst ohne if machen. Das kostet Zeit. Lieber ein Array 
mit den ganzen Led-Pins nehmen.

z.B.

uint8_t *ports[]= {&PORTD, &PORTD, &PORTD, &PORTC};
uint8_t pins[] = {1, 2, 4, 32}; //2^pin

//ISR
*(ports[sec]) ^= pins[sec++];
sec &= 0x03; //sec == 4 -> sec = 0


Einfacher wäre es wenn die Pins nebeneinander liegen.

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.