Anfänger Timer Interrupt Problem

OP #1524685
Hi!

Ich hab hier eine Lesliesteuerung, wo das Programm funktioniert und will 
es um eine Funktion erweitern, nämlich dass die Leds je nach Zustand des 
Leslie (AUS-SLOW-FAST) nicht, langsam oder schnell blinken.

Ich würde das gerne mit einem Interrupt lösen. Das Problem ist aber, 
sobald ich den Interrupt- Initialisierungsblock einfüge, funktioniert 
das ganze Programm nicht mehr. D.h.: Das Drücken der jeweiligen Taster 
hat zur Folge, dass sich das Programm zunächst richtig verhält- in die 
jeweilige Subroutine springt-, aber dann wieder AUS() durchläuft. Das 
versteh ich nicht, weil AUS() ja nicht in der while(1) Schleife steht, 
sondern nur als Bedingung auf den Schalterzustand.
Es scheint so, als ob ein Interrupt main() neu durchlaufen lässt, was ja 
nicht sinnvoll wäre.

Bitte kann mir das jemand erklären? LSR ist leer, sollte eigentlich kein 
Eigenleben haben.


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


ISR(Timer0_COMPvect){
  }

int main(){
DDRD=0b00011111;//bit0-4 auf Ausgang, Bit 5-7 auf Eingang 
(Schalter1,2,3)
int volatile SCHALTER1, SCHALTER2, SCHALTER3;
SCHALTER1=(PIND & (1<<PIND5));
SCHALTER2=(PIND & (1<<PIND6));
SCHALTER3=(PIND & (1<<PIND7));

 // Prescaler = FCPU/1024    <--------------OHNE DEN BLOCK GEHT´S
TCCR0|=(1<<CS02)|(0<<CS00);
 //Enable Overflow Interrupt Enable
TIMSK|=(1<<TOIE0);
 //Initialize Counter
TCNT0=0;
sei();

AUS();//Initialisierung



while(1){ //HAUPTSCHLEIFE
//Wird irgendein Schalter gedrückt?
if (SCHALTER1!=(PIND&(1<<PIND5))){
  AUS();
  SCHALTER1=(PIND&(1<<PIND5));//Schalter1 = neue Schalterstellung
  }
if (SCHALTER2!=(PIND&(1<<PIND6))){
  SLOW();
  SCHALTER2=(PIND&(1<<PIND6));//Schalter2 = neue Schalterstellung
  }
if (SCHALTER3!=(PIND&(1<<PIND7))){
  FAST();
  SCHALTER3=(PIND&(1<<PIND7));//Schalter3 = neue Schalterstellung
  }
}
}

AUS(){
  PORTD &= ~(1<<PORTD0);//Ausgang1 ausschalten
  PORTD &= ~(1<<PORTD1);//Ausgang2 ausschalten
  PORTD |= (1<<PORTD2);//LED1 einschalten
  PORTD &= ~(1<<PORTD3);//LED2 auschalten
  PORTD &= ~(1<<PORTD4);//LED3 auschalten
  }

SLOW(){
  PORTD |= (1<<PORTD0);//Ausgang1 einschalten
  PORTD &= ~(1<<PORTD1);//Ausgang2 ausschalten
  PORTD &= ~(1<<PORTD2);//LED1 auschalten
  PORTD |= (1<<PORTD3);//LED2 einschalten
  PORTD &= ~(1<<PORTD4);//LED3 auschalten
  }

FAST(){
  PORTD &= ~(1<<PORTD0);//Ausgang1 ausschalten
  PORTD |= (1<<PORTD1);//Ausgang2 einschalten
  PORTD &= ~(1<<PORTD2);//LED1 auschalten
  PORTD &= ~(1<<PORTD3);//LED2 auschalten
  PORTD |= (1<<PORTD4);//LED3 einschalten
  }
OP
So, es funktioniert jetzt.

Was ich nicht verstehe sind 2 Dinge:

1.Warum wird die Variable LEDSPEED nur mit volatile (int volatile 
LEDSPEED;) übernommen?

2.Warum wird, wenn ich schnell auf Taster2 oder 3 drücke der Interrupt 
neu gestartet dh. die Led bleibt an (wenn man schnell genug drückt).

Hier gehts echt um Grundlagenforschung für mich, deshalb danke ich 
vielmals für Antworten!

Hier das veränderte Programm dazu:


#include <avr/io.h>
#include<avr/delay.h>
#include<avr/interrupt.h>
int i,j=0;
int volatile LEDSPEED;

ISR(TIMER0_OVF_vect){
  switch (LEDSPEED){
    case 0:break;
    case 1:i++; if(i==8){PORTD ^= (1<<PORTD3);i=0;}//
    break;
    case 2:j++; if(j==1){PORTD ^= (1<<PORTD4);j=0;}//
    break;
  }
}

int main(){
DDRD=0b00011111;//bit0-4 auf Ausgang, Bit 5-7 auf Eingang 
(Schalter1,2,3)
int volatile SCHALTER1, SCHALTER2, SCHALTER3;
SCHALTER1=(PIND & (1<<PIND5));
SCHALTER2=(PIND & (1<<PIND6));
SCHALTER3=(PIND & (1<<PIND7));
TCCR0|=(1<<CS02)|(0<<CS00); // Timer Prescaler
TIMSK|=(1<<TOIE0); //Enable Overflow Interrupt Enable
TCNT0=0;//Initialize Counter
sei();
INIT();//Initialisierung des Programms
while(1){ //Wird irgendein Schalter gedrückt?
if (SCHALTER1!=(PIND&(1<<PIND5))){
  AUS();
  LEDSPEED=0;
  SCHALTER1=(PIND&(1<<PIND5));//Schalter1 = neue Schalterstellung
  }
if (SCHALTER2!=(PIND&(1<<PIND6))){
  SLOW();
  LEDSPEED=1;
  SCHALTER2=(PIND&(1<<PIND6));//Schalter2 = neue Schalterstellung
  }
if (SCHALTER3!=(PIND&(1<<PIND7))){
  FAST();
  LEDSPEED=2;
  SCHALTER3=(PIND&(1<<PIND7));//Schalter3 = neue Schalterstellung
  }
}
}

INIT(){
int delaytime=80; //vor dem debuggen auf 0 stellen! (Sonst 80)
PORTD=0b00000100;
_delay_ms(delaytime);
PORTD=0b00001000;
_delay_ms(delaytime);
PORTD=0b00010000;
_delay_ms(delaytime);
PORTD=0b00000100;
_delay_ms(delaytime);
PORTD=0b00001000;
_delay_ms(delaytime);
PORTD=0b00010000;
_delay_ms(delaytime);
PORTD=0b00000100;
_delay_ms(delaytime);
PORTD=0b00001000;
_delay_ms(delaytime);
PORTD=0b00010000;
_delay_ms(delaytime);
AUS();
}

AUS(){
  PORTD &= ~(1<<PORTD0);//Ausgang1 ausschalten
  PORTD &= ~(1<<PORTD1);//Ausgang2 ausschalten
  PORTD |= (1<<PORTD2);//LED1 einschalten
  PORTD &= ~(1<<PORTD3);//LED2 auschalten
  PORTD &= ~(1<<PORTD4);//LED3 auschalten
  }

SLOW(){
  PORTD |= (1<<PORTD0);//Ausgang1 einschalten
  PORTD &= ~(1<<PORTD1);//Ausgang2 ausschalten
  PORTD &= ~(1<<PORTD2);//LED1 auschalten
  PORTD |= (1<<PORTD3);//LED2 einschalten
  PORTD &= ~(1<<PORTD4);//LED3 auschalten
  }

FAST(){
  PORTD &= ~(1<<PORTD0);//Ausgang1 ausschalten
  PORTD |= (1<<PORTD1);//Ausgang2 einschalten
  PORTD &= ~(1<<PORTD2);//LED1 auschalten
  PORTD &= ~(1<<PORTD3);//LED2 auschalten
  PORTD |= (1<<PORTD4);//LED3 einschalten
  }
Gast
[Titel]volatile[/Titel]..ist ein c-Schlüsselwort und bedeutet "flüchtig" 
und bedeutet     nichts anderes, dass sie durch Ereignisse, die extern 
passieren (=sprich Interrupts) verändert werden können.
Der Compiler arbeitet bei mit volatile deklarierten Variablen ohne jede 
Optimierung, d.h. läßt die entsprechenden Werte bei jedem Zugriff neu 
aus dem Hauptspeicher laden und sorgt bei Veränderungen dafür, daß die 
neuen Werte ohne Verzögerung dort sofort abgelegt werden.
Andernfalls optimiert der avrgcc compiler dir die globale Variable weg 
(außer du schaltest die Optimierung aus).



2)Gegenfrage: Soll bei der INIT-Funktion schon durch den Timerinterrupt 
gesprungen werden?

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 16 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

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.