Hallo Leute Habe mir mal eine leichten Code zusammengebastelt, beí dem über die ISR Overflow Routine vier Taster abgefragt werden. Diese sollen anschließend eine LED toggeln. Ohne Interrupt funzt es und auch mit Interrupt, aber nur, wenn ich diesen zusammen mit einer lcd_init IN die while(1) schleife tue. Leider erhalte ich dabei starke Displayfehler, da das Display dadurch ja immer neu initialisiert wird. Packe ich das ganze außerhalb der while(1) Schleife kann ich die LED nicht mehr toggeln. habe mir auch die lcd_init mal näher betrachtet und bei dieser werden zu Beginn die Interrupts ausgeschalten cli() und am Ende wieder eingeschalten sei()! kann es damit zusammenhängen? also hier mal mein Code! // Deklarationen ============================================================== // Festlegung der Quarzfrequenz #ifndef F_CPU // optional definieren #define F_CPU 18432000UL // MiniMEXLE mit 18,432 MHz Quarz #endif // Include von Header-Dateien #include <avr/io.h> // I/O-Konfiguration (intern weitere Dateien) #include <stdbool.h> // Bibliothek fuer Bit-Variable #include <avr/interrupt.h> // Definition von Interrupts #include <util/delay.h> // Definition von Delays (Wartezeiten) #include "lcd_lib_de.h" // Header-Datei fuer LCD-Anzeige // Makros #define SET_BIT(PORT, BIT) ((PORT) |= (1 << (BIT))) // Port-Bit Setzen #define CLR_BIT(PORT, BIT) ((PORT) &= ~(1 << (BIT))) // Port-Bit Loeschen #define TGL_BIT(PORT, BIT) ((PORT) ^= (1 << (BIT))) // Port-Bit Toggeln // Konstanten #define ON_TIME 50 // "Ein-Zeit" in Inkrementen zu 100 ms #define OFF_TIME 10 // "Aus-Zeit" in Inkrementen zu 100 ms #define ENABLE 7 // Variable bool sw1a = 1; // Bitspeicher fuer Taste 1 alt bool sw2a = 1; // Bitspeicher fuer Taste 2 alt bool sw3a = 1; // Bitspeicher fuer Taste 3 alt bool sw4a = 1; // Bitspeicher fuer Taste 4 alt bool sw1n = 1; // Bitspeicher fuer Taste 1 neu bool sw2n = 1; // Bitspeicher fuer Taste 2 neu bool sw3n = 1; // Bitspeicher fuer Taste 3 neu bool sw4n = 1; // Bitspeicher fuer Taste 4 neu bool Taste_x = 0; bool Taste_4 = 0; unsigned int Lux_Ausgabe(void); unsigned int Interruptzeit = 900; int i; int x; void initDisplay_Timer1(void); // Initialisierung Display und Timer1 void sound(void); // Unterprogramm für Piepton und Countdown Ausgabe void initTimer0(void); // Timerfunktion für Soundausgabe void countDown(void); // 30sec-CountDown mit Displayausgabe void Tastenabfrage(void); //====================================================================== == // Hauptprogramm========================================================== int main(void) { initDisplay_Timer1(); sei(); while(1) { if(Taste_x==1) { Taste_x=0; SET_BIT(DDRB, DDB2); TGL_BIT(PORTB, PB2); } } //countDown(); } //====================================================================== === // Interruptroutine======================================================== // Interrupt Timer 2 18432000/256=72000hz / pre8 = 9000hz => 0,11111ms/OVF ISR (TIMER2_OVF_vect) { --Interruptzeit; // Interruptzeit 900*0,111ms=0,1s bis Tastenabfrage if(Interruptzeit==0) { Interruptzeit=900; Tastenabfrage(); } } //==================================================================== // Tastenabfrage=========================================================== void Tastenabfrage() { CLR_BIT(PORTD, ENABLE); // Enable-Signal auf 0 DDRC = DDRC & 0xF0; // Port C auf Eingabe schalten PORTC = 0x0F; // Pullup-Rs eingeschaltet _delay_us(10); // Wartezeit Umstellung Hardware-Signal sw1n = (PINC & (1 << PC0)); sw2n = (PINC & (1 << PC1)); sw3n = (PINC & (1 << PC2)); sw4n = (PINC & (1 << PC3)); if ((sw1n==0)&(sw1a==1)) // wenn Taste 1 soeben gedrueckt wurde: Taste_x = 1; // Flankenbit Taste 1 setzen if ((sw2n==0)&(sw2a==1)) // wenn Taste 2 eben gedrueckt wurde: Taste_x = 1; // Flankenbit Taste 2 setzen if ((sw3n==0)&(sw3a==1)) // wenn Taste 3 eben gedrueckt wurde: Taste_x = 1; // Flankenbit Taste 3 setzen if ((sw4n==0)&(sw4a==1)) // wenn Taste 4 eben gedrueckt wurde: Taste_4 = 1; // Flankenbit Taste 4 setzen sw1a = sw1n; // aktuelle Tastenwerte speichern sw2a = sw2n; // in Variable f?r alte Werte sw3a = sw3n; sw4a = sw4n; DDRC = DDRC | 0x0F; // Port C auf Ausgabe schalten } //===================================================================== // Initialisierung Display und Timer1=============================== void initDisplay_Timer1() // Start der Displayinitialisierung { lcd_init(); // Initialisierungsroutine aus der lcd_lib lcd_clearDisplay(); TCCR2A = 0; // Timer 1 auf "Normal Mode" schalten TCCR2B |= (1<<CS21); // mit Prescaler /8 betreiben TIMSK2 |= (1<<TOIE2); // Overflow-Interrupt aktivieren } Vielen Dank schonmal für eure Ratschläge!
oh hier noch der Auszug aus der lcd_init! void lcd_init (void) { cli(); //globale Interrupts deaktivieren DDRC = 0x0f; // Port C, Bit 0..3 (LCD-Daten) auf Output DDRD |= ((1<<E) | (1<<RS)); PORTC = 0x0f; // Port C, Bit0..3 (LCD-Daten) SET // Steuersignale auf LOW P_STEUER &=~((1<<E) | (1<<RS)); // E und RS auf 0 setzen _delay_ms (20); // Display in 4-bit Modus initialisieren P_DATA &=0xf0; P_DATA |=0x03; lcd_enable(); _delay_ms (10); lcd_enable (); _delay_ms (10); lcd_enable (); P_DATA &=1; _delay_ms (2); lcd_enable(); _delay_us (50); // 2 Zeilen, 5 x 7 Pixel lcd_write (0x28); _delay_us (40); // Display einschalten lcd_write (0x0C); _delay_us (50); // Curser increment mode lcd_write (0x02); _delay_us (50); //Display loeschen (funktioniert nur, wenn es 2x aufgerufen wird) lcd_write (0x01); _delay_ms (3); lcd_write (0x01); _delay_ms (3); sei(); // globale Interrrupts aktivieren }
Du machst zu Beginn von Tastenabfrage()
1 | DDRC = DDRC & 0xF0; // Port C auf Eingabe schalten |
2 | PORTC = 0x0F; // Pullup-Rs eingeschaltet |
Eine gedrückte Taste legt offensichtlich eines der unteren 4 Bits auf 0. Am Ende von Tastenabfrage() machst Du dann
1 | DDRC = DDRC | 0x0F; // Port C auf Ausgabe schalten |
Damit werden die Tastenpins auf Output geschaltet; sie geben jetzt 'high' aus (denn nach PORTC hast Du 0xf geschrieben). Jetzt hast Du bei gedrückter Taste einen sauberen Kurzschluss des Ausgangs. Wozu die ganze In/Out-Umschalterei? Weiter habe ich nicht geschaut.
Die Sache ist die, das die Steuersignale des Displays auch auf Port C liegen. Deswegen werden sie zu Beginn auf Eingang geschalten für die Abfrage der Taster und anschließend auf Ausgang, damit wieder Daten zum Display gespeist werden können.
Was den Kurzschluss auch nicht besser macht. Und je mehr Leitungen da dran hängen, umso knapper wird die _delay_us(10). Die scheint mir eh so schon knapp (und ist im Interrupt auch recht unpraktisch, aber geht wohl nicht anders). Vieles blieb mir auch sonst völlig unklar, z.B. > Ohne Interrupt funzt es und auch mit Interrupt, aber nur, wenn ich > diesen zusammen mit einer lcd_init IN die while(1) schleife tue. Wie tut man einen Interrupt in die Hauptschleife? Dann das Übliche, wenn eine Interruptroutinen-Übergabe nicht funktioniert: Taste_x ist nicht volatile. EDIT: Sperrst Du auch bei sämtlichen Display-Ausgaben die Interrupts, bis der Transfer komplett ist?
Schau mal nach dem Zauberwort "volatile" Die Taster hängen an den gleichen Ports wie das LCD?
@ Zimmerer: Sorry das war etwas missverständlich ausgedrückt. Ich meinte das so, die Interrupteinstellungen muss man ja eigentlich nur einmal definieren oder? Deswegen habe ich sie zusammen mit der lcd_init in das Unterprogramm initDisplay_Timer1 gepackt. Wenn man nun dieses Unterprogramm außerhalb der while-Schleife aufruft, klappt das mit der LED nicht, ruft man sie dagegen in der while-Schleife auf, klappt das mit dem Umschalten der LED, dafür hat aber das Display starke Fehler, da es ja in jedem Schleifendurchgang neu geladen wird. @ Johann: Ich habe jetzt die bool'schen Variablen so gesetzt: volatile bool Taste_x = 0; volatile bool Taste_4 = 0; Und siehe da, es funktioniert... Ich hoffe ich hab des jetzt so richtig gemacht und es war net nur Zufall, dass es jetzt klappt :P Zu den Ein-und Ausgängen... wir benutzen in unserer FH das MINIMexle mit einem ATmega88 und dort hängt an PortC sowohl die Taster als auch die Steuerleitungen fürs LCD. Gruß und danke an alle :)
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.