Wenn du auf das LCD ein Leerzeichen schreibst wird nichts angezeigt. Das ist als String " " oder ASCII Code 0x20.
Du musst dann deine Sachen draufschreiben und dann nach 3 Sekunden auf die gleichen Adressen Leerzeichen. Wenn du sonst nichts anzeigst kannst du auch lcd.clear() machen, aber das löscht alles und dauert lange. Wenn dein Text 7 Zeichen lang ist kannst du natürlich gleich lcd.print(" ") machen. Davor natürlich die Adresse auf das erste Zeichen stellen, das der Display-Controller die Adresse bei jedem Schreiben automatisch inkrementiert.
Wenn du irgendeine Anzeige hin-und-her schalten willst (manuell und nicht zeitgesteuert) musst du dir wie oben gesagt den Zustand einmal in einer bool-Variablen merken. Ich habe das gerade mit einem Häkchen wo ich eine Funktion ein und ausschalten kann. Sieht dann bei mir so aus:
if (_input.check)
{
_lcd.printByte(0x20); //Haken ist gesetzt -> löschen
}
else
{
_lcd.printByte(CHECK_MARK);
}
_input.check = !_input.check;
Bei mir ist die ganze Sache in einer riesigen if/else/switch Konstruktion.
Ich gebe Zeiten für einen Alarm ein. Also habe ich diese Zustände. Wie oben gesagt eine State-Machine. Man kann das natürlich auch eine richtige Klasse schreiben und alles objekt-orientiert machen. Das muss aber auf einem Mikrocontroller nicht unbedingt sein.
#define TIME_H10 0
#define TIME_H1 1
#define TIME_M10 2
#define TIME_M1 3
#define TIME_PROG 4
#define TIME_CHECK 5
Dann eine Variable "uint8_t _timeDigitIndex = TIME_H10". Die Zehner-Stelle ist meine Ausgangssituation. Wenn ich dann auf die nächste Ziffer schalte (geht bei mir mit der Stern-Taste, aber man kann es auch automatisch machen) muss ich nur "_timeDigitIndex++" machen.
Ich will dann z.B. abfragen, dass man die Zehnerstellen nur von 0-2 schreiben kann. Geht dann einfach so:
if(_timeDigitIndex == TIME_H10)
{
if(key <= '2')
{
_input.h10 = key - 0x30; //Umwandlung ASCII -> Dezimal
_lcd.print(key);
_lcd.moveCursorLeft(); //macht das Auto-Inkrement rückgängig. Ich will nicht immer alle Zeiten neu eingeben müssen
}
}
Darüber liegt nochmal eine Abfrage in welcher Menüfunktion ich mich befinde. Dafür gibts "uint8_t _menuFunction" und dann defines wie:
#define MENU_CURSOR 0
#define MENU_SET_ALARM 1
Ich will dann mit der Raute-Taste die Zeit oder einen der Alarms bestätigen:
if(_menuFunction == MENU_SET_ALARM || _menuFunction == MENU_SET_TIME)
{
if(key == '#')
{
if(_menuFunction == MENU_SET_ALARM)
{
...
}
}
else if(key >= '0')
{
//hier ist der Code von oben wie ich Abfrage auf welcher Stelle ich bin
}
{
Switch ist ja nur ein einfacher lesbares if/else. Aber auch nicht so toll wenn du viele Anweisungen ausführst, da es gleich unübersichtlich wird. Das mache ich für den Cursor, da ich da den Code in andere Methode ausgelagert habe.
if(_menuFunction == MENU_CURSOR)
{
switch(key)
{
case '2':
printCursor(CURSOR_UP);
break;
case '4':
printCursor(CURSOR_LEFT);
break;
case '6':
printCursor(CURSOR_RIGHT);
break;
case '8':
printCursor(CURSOR_DOWN);
break;
case '#':
case '5':
_menuFunction = MENU_SET_ALARM; //hier wird dann in einen anderen Menü Zustand umgeschaltet und wenn das nächste mal eine Taste
//gedrückt wird hat sie eine andere Funktion
break;
}
}
Wenn du für jede Taste nur eine Methode und die Anzeige aufrufst kannst du das auch mit einem if/if else/if else... machen. Du kannst z.B. eine Methode schreiben, der die Nummer/ID der Taste übergibst. Die Methode setzt dann die Nummer in eine Display Adresse um und schreibt die entsprechende Stelle.
Wegen dem Timing der Anzeige musst du halt aufpassen, da du das nicht mit Warten/Delay machen kannst. Schau dir das Beispiel "BlinkWithoutDelay" an wie man eine Zeit zählt und dabei noch andere Sachen erledigt. Ein oneshot Timer (der nur einmal läuft und dann neu gestartet werden muss) wäre auch eine elegante Möglichkeit. Der würde dann die entsprechenden Display-Stellen löschen wenn er seine Zeit erreicht hat.