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 }
Deine Timer-Interrupt-Routine muss einen bestimmten Namen haben. Der von Dir verwendete gehört nicht zu den möglichen. Welche Namen gelten, sagt Dir die Dokumentation zu <avr/interrupt.h>.
Noch was anderes: Timer0_COMPvect gibt es nicht: Das muss Timer0_COMP_vect heißen. Probiers aus! Und guck nächstes mal einfach ins Datenblatt unter Interruptvektoren. Valentin
Danke für die Tips!! Ja hab ich tatsächlich falsch geschrieben. Funktioniert aber auch nicht mit Unterstrich. Ich hab jetzt den richtigen Namen gefunden: TIMER0_OVF_vect der gilt für den Mega8. Ich hab da eine Liste mit allen möglichen Namen für alle AVRs gefunden. Sehr praktisch glaub ich: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
Ist sicher was anderes, mir gings nur um irgendeinen Namen, der funktioniert. Für den Mega8 gibts zB auch: TIMER1_COMPA_vect
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 }
[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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.