PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LCD - Menu-Navigation



testone
11.11.2008, 22:36
Hallo Zusammen

Ich versuche auf einem LCD Display ein kleines Menu zu erstellen und anhand von Tasten zu "steuern".

D.h. ich habe mir in einem struct eine Art hierarchisches Menu designed.

Für die Navigation "durch" dieses Menu habe ich 4 Funktionen geschrieben. Jede dieser Funktionen gibt den "nächsten" Menu-Punkt zurück (falls vorhanden). Also eine Funktion für "unten", "oben" links" und "rechts".

Nun möchte ich wissen, ob überhaupt Interrupts die richtige Lösung sind, um anhand der Taster des Asuro durch dieses "struct" Menu zu navigieren.

Wenn ja, wie würde eine super einfaches Programm aussehen, welches auf 2 verschiedene Taster reagiert und jeweils im "Interrupt-Code" eine Funktion aufruft?
Ich habe ein wenig geforscht, bin aber bereits bei der Frage stehen geblieben: Welcher Übergabeparameter muss ich dem SIGNAL geben, damit der Interrupt auf meinen Taster reagiert?

Ich hoffe Ihr könnt mir helfen 8-[


Ich bedanke mich schon im Voraus!

Ciaooo
Michele

radbruch
11.11.2008, 22:45
Hallo Michele,

willkommen im RN-Forum.

Muss es unbedingt eine Interruptlösung sein? Würde nicht ein Polling (=regelmässiges Abfragen) der Taster ausreichen?

Gruß

mic

Pierce466
11.11.2008, 23:20
Hallo Michele,

also ich habe in einem Projekt in dem ich einen Auto und einen Handbetrieb habe das ganze so gelöst...

Funktion LCD:


void fnLCDAusgabe(int iTemperature)
{
if (bBetriebsart==1) //Handbetrieb
{


switch(uiMenuCounter)
{

case 0: //wird nur zur Kurzzeitigen Anzeige auf Display benötigt

lcd_clear();

//-----LCD Zeile 1-----

lcd_putsf("HANDBETRIEB"); //... schreibe ""
delay_ms(1500);
//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("durchs Menue mit"); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy
lcd_putsf("Taster 1"); //... schreibe ""
delay_ms(1500);

//-----LCD Zeile 1-----

lcd_clear();
lcd_putchar(225); // "ä" auf Display ausgeben
lcd_putsf("ndern mit "); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);//gehe an Position xy
lcd_putsf("Taster 2"); //... schreibe ""
delay_ms(1500);

uiMenuCounter++;

break;

case 1:
break;

case 2: // Stunden erhöhen

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Std erh"); //... schreibe ""
lcd_putchar(239); //"ö" auf Display ausgeben
lcd_putsf("hen"); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy
itoa(uiStunde,strTemp); // Integer Wert in AScii Zeichen umwandeln
if (uiStunde<10) // Wenn wert für Stunde kleiner 10(einstellig) ...
{
lcd_putsf("0"); //... schreibe eine Null davor
}
lcd_puts(strTemp); //String Strunde auf Display ausgeben
break;


case 3: // Stunden verringern

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Std verringern"); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy
itoa(uiStunde,strTemp); // Integer Wert in AScii Zeichen umwandeln
if (uiStunde<10) // Wenn wert für Stunde kleiner 10(einstellig) ...
{
lcd_putsf("0"); //... schreibe eine Null davor
}
lcd_puts(strTemp); //String Stunde auf Display ausgeben
break;

case 4: // Minuten erhöhen

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Min erh");//... schreibe ""
lcd_putchar(239); //"ö" auf display ausgeben
lcd_putsf("hen"); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy

itoa(uiMinute,strTemp); //Integer Wert in AScii Zeichen umwandeln
if (uiMinute<10) // Wenn wert für Minute kleiner 10(1-Stellig)...
{
lcd_putsf("0"); //... schreibe eine Null davor
}
lcd_puts(strTemp); //String Minute auf Display ausgeben
break;


case 5: // Minuten verringern

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Min verringern"); //... schreibe "zeit"

//-----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy

itoa(uiMinute,strTemp); //Integer Wert in AScii Zeichen umwandeln

if (uiMinute<10) // Wenn wert für Minute kleiner 10(1-Stellig)...
{
lcd_putsf("0"); //... schreibe eine Null davor
}
lcd_puts(strTemp); //String Minute auf Display ausgeben
break;



case 6: // Intervall für Themperaturmessung erhöhen

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Interv. erh"); //schreibe ""
lcd_putchar(239); //"ö" auf display schreiben
lcd_putsf("hen"); //... schreibe ""

//----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy

itoa(uiIntervall,strTemp); //Integer Wert in AScii Zeichen umwandeln
if (uiIntervall<10) // Wenn wert für Minute kleiner 10(1-Stellig)...
{
lcd_putsf("0"); //... schreibe eine Null davor
}
lcd_puts(strTemp); //String Minute auf Display ausgeben
break;

case 7: // Intervall für Themperaturmessung verringern

//-----LCD Zeile 1-----

lcd_clear();

lcd_putsf("Interv. verring"); //... schreibe ""

//----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy

itoa(uiIntervall,strTemp); //Integer Wert in AScii Zeichen umwandeln
if (uiIntervall<10) // Wenn wert für Minute kleiner 10(1-Stellig)...
{
lcd_putsf("0"); //... schreibe eine Null davor
}
lcd_puts(strTemp); //String Minute auf Display ausgeben

break;


case 8: // Ringspeicher Start

//-----LCD Zeile 1-----

if(bStartStop==0)
{
lcd_clear();
lcd_putsf("Ringsp Start"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy
lcd_putsf("<Ringsp steht>"); //schreibe ""
break;
}
else
{
lcd_clear();
lcd_putsf("Ringsp Start"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy

lcd_putsf("<Ringsp l"); //schreibe ""
lcd_putchar(225); // "ä" auf Display ausgeben
lcd_putsf("uft>"); //schreibe ""
}

break;

case 9: //Ringspeicher Stop
lcd_clear();

if(bStartStop==0)
{
//-----LCD Zeile 1-----

lcd_putsf("Ringsp Stop"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1); //gehe an Position xy

lcd_putsf("<Ringsp steht>"); //schreibe ""
break;
}
else
{
//-----LCD Zeile 1-----

lcd_putsf("Ringsp Stop"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);

lcd_putsf("<Ringsp l"); //schreibe ""
lcd_putchar(225); //"ä" auf Display ausgeben
lcd_putsf("uft>"); //schreibe ""
}
break;


case 10: //Ringspeicher löschen

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Ringsp l"); //schreibe ""
lcd_putchar(239); // "ö" auf Display ausgeben
lcd_putsf("schen"); //schreibe ""
break;

case 11: //Thermostat unteren Grenzwert erhöhen

if (iHystereseMin >= iHystereseMax)
{
//-----LCD Zeile 1-----
lcd_clear();
lcd_putsf("HystereseMin >"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("HystereseMax"); //schreibe ""
delay_ms(1500);

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Min wurde auf "); //schreibe ""

//-----LCD Zeile 1-----

lcd_gotoxy(0,1);
lcd_putsf("Max - 2 gesetzt"); //schreibe ""
break;
}
else
{
//-----LCD Zeile 1-----

lcd_clear();

lcd_putsf("Hysterese Min ++"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
itoa(iHystereseMin,strTemp);
lcd_puts(strTemp);
}

break;

case 12: //Thermostat unteren Grenzwert verringern
if (iHystereseMin >= iHystereseMax)
{
//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("HystereseMin >"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("HystereseMax"); //schreibe ""
delay_ms(1500);

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Min wurde auf "); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("Max - 2 gesetzt"); //schreibe ""
break;
}
else
{
//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Hysterese Min --"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
itoa(iHystereseMin,strTemp);
lcd_puts(strTemp);

}
break;

case 13: //Thermostat oberen Grenzwert erhöhen
if (iHystereseMax <= iHystereseMin)
{

lcd_clear();

//-----LCD Zeile 1-----

lcd_putsf("HystereseMax <"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("HystereseMin"); //schreibe ""

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Max wurde auf "); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("Min + 2 gesetzt"); //schreibe ""
break;

}
else
{
//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Hysterese Max ++"); //schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
itoa(iHystereseMax,strTemp);
lcd_puts(strTemp);
}

break;

case 14: //Thermostat oberen Grenzwert verringern
if (iHystereseMax <= iHystereseMin)
{

lcd_clear();

//-----LCD Zeile 1-----

lcd_putsf("HystereseMax <"); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("HystereseMin"); //... schreibe ""

//-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Max wurde auf "); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("Min + 2 gesetzt"); //... schreibe ""
break;
}

//-----LCD Zeile 1-----
else
{
lcd_clear();
//lcd_gotoxy(0,0);
lcd_putsf("Hysterese Max --"); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
itoa(iHystereseMax,strTemp);
lcd_puts(strTemp);
}

break;
case 15: if(bDS1621Contakt==0)
{
lcd_clear();

//-----LCD Zeile 1-----

lcd_putsf("konfig 1621 Outp"); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("<konfig = "); //... schreibe ""
itoa(bDS1621Contakt,strTemp);
lcd_puts(strTemp);
lcd_putsf(">"); //... schreibe ""
break;
}
else
{
lcd_clear();

//-----LCD Zeile 1-----

lcd_putsf("konfig 1621 Outp"); //... schreibe ""

//-----LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf(" <konfig = "); //... schreibe ""
itoa(bDS1621Contakt,strTemp);
lcd_puts(strTemp);
lcd_putsf(">"); //... schreibe ""

}
break;
default:

}
}


else //Automatikbetrieb
{

switch(uiAutoCounter)
{
case 0: //-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("AUTOMATIK"); //... schreibe ""
delay_ms(1500);
uiAutoCounter++;
break;

case 1: //-----LCD Zeile 1-----

lcd_clear();
lcd_putsf("Zeit "); //... schreibe "zeit"
itoa(uiStunde,strTemp); // Integer Wert in AScii Zeichen umwandeln
if (uiStunde<10) // Wenn wert für Stunde kleiner 10(einstellig) ...
{
lcd_putsf("0"); //... schreibe eine Null davor
}
lcd_puts(strTemp); //String Strunde auf Display ausgeben
lcd_putsf(":"); //Doppelpunkt auf LCDausgeben
itoa(uiMinute,strTemp); //Integer Wert in AScii Zeichen umwandeln
if (uiMinute<10) // Wenn wert für Minute kleiner 10(1-Stellig)...
{
lcd_putsf("0"); //... schreibe eine Null davor
}
lcd_puts(strTemp); //String Minute auf Display ausgeben
lcd_putsf(":"); //Doppelpunkt auf LCDausgeben
itoa(uiSekunde,strTemp); //Integer Wert in AScii Zeichen umwandeln
if (uiSekunde<10) // Wenn wert für Sekunde kleiner 10 (1-Stellig) ...
{
lcd_putsf("0"); // schreibe eine Null davor
}
lcd_puts(strTemp); //String Sekunde auf Display ausgeben


//------LCD Zeile 2-----

lcd_gotoxy(0,1);
lcd_putsf("Temp "); //... schreibe ""
itoa(iTemperature/10, strTemp); // Vorkommastellen
lcd_puts(strTemp);
lcd_putchar('.');
itoa(iTemperature%10, strTemp); // Nachkommastellen
lcd_puts(strTemp);
lcd_putchar(223); // °Zeichen
lcd_putchar('C');

} //switch ende

delay_ms(200); //ohne Delay flackert Display...
} //else ende
}


und eine Funktion für die Tastenabfrage

Pierce466
11.11.2008, 23:21
Son mist... meine Nachrichtdarf nicht mehr als 20000 zeichen enthalten...XD Also hier die fortsetzuung...

************************************************** ****************
** Handbetrieb **
************************************************** *****************/


void fnHand(void)
{
if(bMenue==1)
{
if(TASTER1)
{
uiMenuCounter++;
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
delay_ms(200);
}
switch (uiMenuCounter)
{
case 0:
break;

case 1:
break;

case 2: //Stunde erhöhen

if (TASTER2)
{
delay_ms(200); //Taster entprellen

uiStunde=uiStunde+1;

if (uiStunde>=24)
{
uiStunde =0;
}
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;

case 3: //Stunde verringern

if (TASTER2)
{
delay_ms(200); //Taster entprellen

uiStunde=uiStunde-1;

if (uiStunde <= 0)
{
uiStunde = 23;
}
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;

case 4: //Minuten erhöhen

if (TASTER2)
{
delay_ms(200); //Taster entprellen

uiMinute++;
if (uiMinute >= 60)
{
uiMinute =0;
}
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;

case 5: //Minuten verringern

if (TASTER2)
{
delay_ms(200); //Taster entprellen

uiMinute=uiMinute-1;

if (uiMinute <= 0)
{
uiMinute =59;
}

fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;


case 6: // Intervall erhöhen

if (TASTER2)
{
delay_ms(200); //Taster entprellen
uiIntervall++;
if (uiIntervall>=60)
{
uiIntervall =0;
}
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;

case 7: // Intervall verringern

if (TASTER2)
{
delay_ms(200); //Taster entprellen
uiIntervall--;
if (uiIntervall <=0)
{
uiIntervall =59;
}
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;


case 8: //Messung Starten

if (TASTER2)
{
delay_ms(200); //Taster entprellen
bStartStop=1;
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;

case 9: // Messung stoppen
if (TASTER2)
{
delay_ms(200); //Taster entprellen
bStartStop=0;
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;

case 10:// Ringspeicher leeren
if (TASTER2)
{
delay_ms(200); //Taster entprellen
fnSpeicherLeeren();
//fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;

case 11: // Untere Temp.Schwelle Thermostat erhöhen

if (TASTER2)
{
delay_ms(200); //Taster entprellen

iHystereseMin=iHystereseMin+1;
if (iHystereseMin>=125)
{
iHystereseMin = -25;
}
if (iHystereseMin >= iHystereseMax)
{
iHystereseMin = iHystereseMax-1;
}
fnLCDAusgabe(iTemperature); //Funktion für LCD aufrufen und Variable übergeben
}
break;

case 12: // Untere Temp.Schwelle Thermostat verringern
if (TASTER2)
{
delay_ms(200); //Taster entprellen

iHystereseMin=iHystereseMin-1;

if (iHystereseMin<=-25)
{
iHystereseMin=125;
}
if (iHystereseMin >= iHystereseMax)
{
iHystereseMin = iHystereseMax-1;
}
fnLCDAusgabe(iTemperature); //Funktion aufrufen und LCD aktualisieren
}
break;

case 13: // Obere Temp.Schwelle Thermosthat erhöhen
if (TASTER2)
{
delay_ms(200); //Taster entprellen

iHystereseMax=iHystereseMax+1;

if (iHystereseMax>=125)
{
iHystereseMin = -25;
}
if (iHystereseMax <= iHystereseMin)
{
iHystereseMax = iHystereseMin+1;
}
fnLCDAusgabe(iTemperature); //Funktion aufrufen und LCD aktualisieren
}
break;

case 14: // Obere Temp.Schwelle Thermosthat verringern

if (TASTER2)
{
delay_ms(200); //Taster entprellen

iHystereseMax=iHystereseMax-1;

if (iHystereseMax<=-25)
{
iHystereseMin=125;
}
if (iHystereseMax <= iHystereseMin)
{
iHystereseMax = iHystereseMin+1;
}
fnLCDAusgabe(iTemperature); //Funktion aufrufen und LCD aktualisieren
}
break;
case 15: if (TASTER2)
{
delay_ms(200); //Taster entprellen

if (bDS1621Contakt==0) //wenn bDS1621Contakt Null ist...
{
bDS1621Contakt=1; //...bDS1621Contakt auf 1 setzen
}
else //ansonsten...
{
bDS1621Contakt=0; //...bDS1621Contakt auf 0 setzen
}
fnLCDAusgabe(iTemperature); //Funktion aufrufen und LCD aktualisieren

}
default:

} //switch Ende

}

if (uiMenuCounter==ANZAHLMENUPUNKTE)
{
uiMenuCounter=2;
}
}

Für die Menuführung brauche ich auch nur 2 Tasten eine mit der ich durch das Menu "gehe" und eine um die WErte zu ändern.

Eins noch, bei der Funktion für die Tasten habe ich immer die gleiche Variable übergeben weil die Funktion eine Variable erwartet, ist aber für die Ausgabe unwichtig da ich die Variablen global definiert habe...

Vielleicht nicht unbedingt die beste Lösung aber funktioniert. Vielleicht hilft dir das ja

Gruß Pierce

testone
12.11.2008, 13:35
Vielen Dank für dein Beispiel :)

Ich wollte es eigentleich mit Interrupts lösen, damit ich in diesem Thema auch ein wenig Knowhow aufbauen kann.

Warum würdest du keine Interrupts gebrauchen? Gibt es einen bestimmten Grund?

Danke für dein Feedback! :-)

Ciaooo
Michele

vajk
12.11.2008, 14:24
So als Anregung gegen die Tastenprellung:

Wenn Taste gerdückt wird, setze ein Flag für die Taste, wenn das Flag gesetzt ist, könnte ein Timer hochzählen und je nach länge des Tastendrucks oder -gedrückt halten weitere Flags pro Taste setzen (kurz, mittel, lang) ... beim Loslassen wird dann ausgewertet :-)

Tja, es gibt nicht beliebig viele Interrupts, kommt natürlich auch drauf an, wieviele Tasten man anschließen möchte. Ein Drehgeber ist gerade bei Menüfunktionen auch was feines ;-)

Delays sind uggly!

radbruch
12.11.2008, 15:55
Polling oder Interrupt:

Natürlich kann man auch Interrupts verwenden wenn man einen Tastendruck auswerten möchte. Ich habe für mein Display mit 5 Tasten zwar noch kein Menue geschrieben, aber an eine Interruptlösung habe ich bei der Planung überhaupt nicht gedacht. Es ist nicht nötig ungewöhnlich schnell auf einen Tastendruck zu reagieren, es gibt nicht so viele nutzbare Interrupts bzw. interruptfähige Eingänge, Interrupts sind manchmal zickig und gelegentlich auch gefährlich und lenken beim Menuebau möglicherweise vom eigentlichen Projekt ab.

hululu
12.11.2008, 19:24
Hier findes du eine Routine um gleichzeitig bis zu 8 Tasten auszuwerten.http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29

Es kann unterschieden werden zwischen Langem und Kurzem Tastendruck und hat auch eine Wiederholfunktion was sehr praktisch ist bei Menuführung.

Pierce466
12.11.2008, 21:46
Natürlich sind delays "ugly"... beiu meiner anwendung allerdingsrelativ irrelevant gewesen, da es um eine Temperaturmessung ging und da sind schnelle reaktionen ja bekanntlich nicht wirklich wichtig... Mit dem Thema Flags hab ich mich noch nicht beschaftigt und kann daher nicht wirklich etwas sagen...

vajk
12.11.2008, 22:32
ja ein Flag ist ja nichts anderes als eine Variable, die einen Zustand speichert ... und delays sind bei einer Beispielanwendung mit 5 Zeilen angebracht, sonst normalerweise nicht, da hab ich meine eigene Meinung zu diesem Thema (ich leb von uC-Entwicklung).

Und wenn Du delays genau hier dazu benutzt, Tasten zu entprellen, solltest Du Dich zunächst mit der Entprellung beschäftigen, als die übergeordneten Programmfunktionen zu durchdenken.

Ist nicht böse gemeint, hululu hat Dir ja mit dem Link schon die Möglichkeit gegeben, aus dem Code anderer zu lernen. Ein Schritt mehr, als mein Versuch, Dir nur eine Idee zu liefern.

Im Zusammenhang mit Tastaturentprellung nutze ich einzelne Bits des Flags ... spart u.a. Platz.

Viel Erfolg noch, ich klink mich aus.