PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LCD-Kontroll-ATmega8 macht mir Probleme



Zarathustra
12.04.2007, 10:36
Hallo!

Ich habe ein Problem.
Ich bin dabei einen LCD- Kontroll-ATmega8 zu programmieren. Kann ihn über I2C erreichen und die Fleury Bibliothek von aussen ansprechen.
Nun will ich auch noch Eingaben über den mega8 ermöglichen. Dazu habe ich 4 Taster, wovon alle mit dem INT1, und 3 mit jeweils einem eigenen Port verbunden sind um die Interrupts zu identifizieren.

Das Problem:
Kombinationen von gedrückten Tasten werden anscheinend nicht richtig erkannt. Hier ein paar Beispiele:

1) START drücken -> Admin Modus (klappt)
2) LINKS oder RECHTS drücken -> alles hängt sich auf

- halte ich nach 1) START gedrückt passiert garnichts obwohl er den Prüfmodus starten müsste
- wenn ich statt 2) nochmal START drücke, MACHT er den Prüfmodus und:
- wenn ich DANACH LINKS oder RECHTS drücke, hängt er sich nicht mehr auf!
- LINKS und RECHTS zusammen: er geht nicht in den SUADMIN Modus sondern krebst fröhlich weiter im ADMIN Modus herum.
- Verlassen des Admin Modus durch SELECT, LINKS und RECHTS zusammen klappt auch nicht.


Ich poste einfach mal den Code hier hinein, Unwichtiges habe ich aus den Klammern herausgenommen:

die Interruptroutine:


// Pinbelegung der Buttons

// Start: INT1 (D3)
// Select: INT1 (D3) & D4
// Left: INT1 (D3) & D0
// Right: INT1 (D3) & D1

#define BUTTON_START (!(PIND&(1<<PD3))&&(PIND&(1<<PD0))&&(PIND&(1<<PD1))&&(PIND&(1<<PD4)))
#define BUTTON_SELECT (!(PIND&(1<<PD4)))
#define BUTTON_LEFT (!(PIND&(1<<PD0)))
#define BUTTON_RIGHT (!(PIND&(1<<PD1)))



ISR(INT1_vect)
{
if(mode == IDLE && BUTTON_START) // Admin Modus betreten
{
// I²C wird deaktiviert um Störung von aussen zu vermeiden
mode = ADMIN;
}

else if(BUTTON_RIGHT && BUTTON_LEFT && !BUTTON_SELECT) // SuAdmin Modus betreten/verlassen
{
if(mode == ADMIN)
{
mode = SUADMIN;
// Optionen werden angezeigt
}
else if(mode == SUADMIN)
{
mode = ADMIN;
}
}

else if(mode == SUADMIN && BUTTON_START) // SuAdmin: Auswahl
{
// Mit dem Cursor ausgewählte Optionen können hiermit bestätigt werden
}

else if(mode == ADMIN && BUTTON_START) // Selbsttest
{
// einige Registerinhalte werden ausgegeben
}

else if(mode != IDLE && BUTTON_LEFT && !BUTTON_RIGHT && !BUTTON_SELECT) // Display links
{
lcd_command(LCD_MOVE_DISP_RIGHT);
}

else if(mode != IDLE && BUTTON_RIGHT && !BUTTON_LEFT && !BUTTON_SELECT) // Display rechts
{
lcd_command(LCD_MOVE_DISP_LEFT);
}

else if(mode != IDLE && BUTTON_SELECT && BUTTON_LEFT && !BUTTON_RIGHT) // Cursor links
{
lcd_command(LCD_MOVE_CURSOR_LEFT);
}

else if(mode != IDLE && BUTTON_SELECT && BUTTON_RIGHT && !BUTTON_LEFT) // Cursor rechts
{
lcd_command(LCD_MOVE_CURSOR_RIGHT);
}

else if(mode == ADMIN && BUTTON_SELECT && BUTTON_LEFT && BUTTON_RIGHT) // Adminmodus verlassen
{
modus = IDLE;
}
// Entprellung & Zeitabstand, 150ms warten
warte_ds(15);
}


int main()



.... einige Zuweisungen und Initialisierungen ....


while(1)
{
switch(mode)
{
case IDLE:
ledSwitch(led_modus, led_color, led_aktion);
break;
case ADMIN:
ledSwitch(STANDBY, BLUEWHITE, 50);
break;
case SUADMIN:
ledSwitch(BLUE1, BLUE2, 40);
ledSwitch(STATIC, ALL, OFF);
ledSwitch(STATIC, DBLUE, ON);
warte_ds(40);
break;
}



Es passieren also Dinge, die an sich nicht passieren dürften weil es theoretisch geht, auch der AVR Simulator macht es so wie ich will.

Ist die INT Routine vielleicht zu voll?

Hoffe, jemand kann mir ne Antwort geben, Fehler finden oder Vorschläge machen,

Gruß,
Markus

Hubert.G
12.04.2007, 11:34
Also die ISR ist sicher zu voll, du rufst ja auch die LCD-Routine aus der ISR auf und hast am Ende noch ein Wait drinnen. Bist du sicher das du da keinen Stack-Überlauf produzierst?

jar
12.04.2007, 15:10
Also die ISR ist sicher zu voll, du rufst ja auch die LCD-Routine aus der ISR auf und hast am Ende noch ein Wait drinnen. Bist du sicher das du da keinen Stack-Überlauf produzierst?

ohne mir das im Detail angesehen zu haben

ich bin auch fürchterlich auf die Nase gefallen mit LCD Ausgaben in der ISR ! nun setze ich ein Flag und gebe ans LCD aus wenn ISR abgearbeitet und Ruhe ist....

und nicht vergessen variable die in der ISR hochzählen auch mal passend zu clearen ;) sonst gibt es Datenmüll, oder halt Überläufe

Zarathustra
12.04.2007, 21:58
Bist du sicher das du da keinen Stack-Überlauf produzierst?

Ich habe mich bislang noch nicht allzu viel mit dem Stack beschäftigt. Es wird ein Stapel (Stack) an der hintersten RAM Adresse angelegt, der nach "innen" hin wächst. Aber ist der RAM nicht groß genug um die paar Rücksprungadressen aufzustapeln?
Wo könnte ich sehen wie voll der Stack ist?


nun setze ich ein Flag und gebe ans LCD aus wenn ISR abgearbeitet und Ruhe ist....

Mein Problem an dieser Methode ist, dass z.B. die "WARTE" Befehle nach dem Interrupt weiter ausgeführt werden bevor in die entsprechende Wunsch - Unterroutine gesprungen wird. Wenn ich aber nach links scrollen will, soll das sofort geschehen und nicht erst nachdem die blaue LED nach ner halben Sekunde ausgegangen ist. Gibt es da andere Möglichkeiten?


Danke für eure Antworten,
Markus

Hubert.G
12.04.2007, 22:19
Was ist wenn deine Tasten prellen, was sie fast sicher tun, wieviele ISR löst du aus?
Schau dir mal den Thread an: www.mikrocontroller.net/topic/12176

Zarathustra
14.04.2007, 17:36
Was ist wenn deine Tasten prellen, was sie fast sicher tun, wieviele ISR löst du aus?
Schau dir mal den Thread an: www.mikrocontroller.net/topic/12176

Gegen Prellung habe ich eine Verzögerung von 100 ms drin, das sollte reichen.

Etwas stört mich an der Stack-Überlauf-Geschichte in einer ISR Routine:
sind es im Zweifel nicht nur ein paar Bytes mehr wenn ein Unterprogramm in einer Interruptroutine läuft anstatt im main() Programm? Nämlich die Bytes, die beschreiben, wo in main() der Programmzeiger vor dem Interrupt war?

Ich würde das alles gern weiterhin in einer ISR laufen lassen, zumal ich nichtmal sicher bin ob das wirklich der Fehler ist.
Ich hoffe, hier gibt es jemanden, der mir da weiterhelfen kann.

Gruß,
Markus