Projektvorstellung: Library für das Erstellen von Menus für LCD Displays

Hi,

bei deinem Beispielcode taucht bei mir ein "geistiges Fragezeichen" auf:
Was passiert bei readButton = 50 (oder 195 oder 380) ?

Grüßle Bernd

Ich wünsche mir ein Menü - System, das im Flash liegt und somit schon fertig kompiliert geladen wird.
Wieviel RAM brauchen deine MenuItem-Elemente? Verbrät ein addItem () - Aufruf noch etwas zusätzlich? (Wohl nicht, aber geht nur mit Variablen im RAM)

Ein int im RAM, das den aktuellen Zustand des gesamten MenüSystems kennzeichnet, sollte eigentlich reichen.
Der statische Teil des aktuellen MenuItem sollte natürlich nur jeweils einmal ausgegeben werden, das passt auch noch in die Status-Variable.

Wie passen Wert-Einstell Funktionen (z.B. über up/down Taster) in dein Menü-System?

Das Ganze aus einfach konfigurierbaren Bausteinen zusammenzustellen, ist ein guter Ansatz!

Guter Ansatz, gut strukturiert. Detailliert kann man aber erst was dazu sagen, wenn wir einen Blick auf die Lib selbst geworfen haben.
Was ich noch für Praktisch halten würde wäre ein dynamischer Aufbau. Also wenn man statt mit den Integer-IDs gleich mit den Zeigern auf die Child- und Parent-Elemente arbeitet.
Toll wäre auch, wenn man die select()-Funktion eines Menuitems gleich beim Anlagen als Funktionspointer "void (*p)(void )" übergeben könnte. Der Parameter "void" kann dann wieder ein Zeiger auf ein beliebiges Objekt sein.

Mario.

Hallo und danke für das Intresse,
ich habe nun den oberen Beitrag bearbeitet und die Lib als .zip angehängt also alle die Intresse haben einfach downloaden. Zudem hab ich vor, ein paar fragen zu beantworten :wink:

BerndJM:
Hi,

bei deinem Beispielcode taucht bei mir ein "geistiges Fragezeichen" auf:
Was passiert bei readButton = 50 (oder 195 oder 380) ?

Grüßle Bernd

Dieser Abschnitt bezieht sich komplett auf das Benutzen eines KeyPadShields (Arduino_LCD_KeyPad_Shield__SKU__DFR0009_-DFRobot) Letztendlich ist dieser Code nur dafür da, um zu ermitteln welcher Button gedrückt wurde und somit durch das Menü zu navigieren.

michael_x:
Wieviel RAM brauchen deine MenuItem-Elemente? Verbrät ein addItem () - Aufruf noch etwas zusätzlich?

Wie viel RAM es genau verbrät kann ich die leider nicht sagen.
Ja addItem() benötigt auch noch Speicher. Allerdings hab ich vor, wie auch schon andere sagten, per Zeiger auf die Items zu zeigen.
Weiter Infos solltest du dir aber aus der Lib holen können.

michael_x:
Das Ganze aus einfach konfigurierbaren Bausteinen zusammenzustellen, ist ein guter Ansatz!

Danke, das war meine Motivation eine solche Lib zubasteln. Es freut mich das ich das anscheinend geschafft habe.

Am Ende möchte ich nochmals sagen das ich mich sehr über Verbesserungsvorschläge freue. Ich hoffe das mein Code nicht ganz so grausam ist und keine hoch heiligen unaufgeschriebenen Programmierregeln bricht.
Also dann viel Spass mit der Lib :wink:

Der Anhang ist der am ersten Post ?

Ich hoffe das mein Code nicht ganz so grausam ist und keine hoch heiligen unaufgeschriebenen Programmierregeln bricht.

Wenn du ohne String arbeitest, ist es "nicht ganz so grausam" :wink:

Wie gesagt, ein Menu im PROGMEM Flash-Speicher aber "konfiguriert statt programmiert", wäre gut.

Hmm doch die String Klasse. Die würde ich auf jeden Fall entsorgen. Da Du mit den Strings selbst nichts machst, außer sie zu speichern, sollte einfach "String" gegen "char*", oder sogar "const char*" ausgetauscht werden.

Als nächstes würde ich auf jeden Fall von den "künstlichen" Indizes auf Zeiger umstellen, dann sparst Du Dir die Funktion getNeighbour(), da jeder Eintrag von forward, back, up und down gleich der passende Zeiger auf das nächste Item ist. Damit man einen definierten Start hat, würde ich ein "root" Element im Menu-Objekt definieren, welches immer den ersten Eintrag liefert. Zusätzlich sollte jedes MenuItem entsprechende Methoden getForward(), getBack(), getUp und getDown() haben, damit man auf die angehängten Elemente zugreifen und damit durch den Baum / Graph navigieren kann.

Mario.

michael_x:
Der Anhang ist der am ersten Post ?

Wie gesagt, ein Menu im PROGMEM Flash-Speicher aber "konfiguriert statt programmiert", wäre gut.

1.) Ja aus dem ersten Post.
2.) Wie soll ich dieses "konfiguriert statt programmiert" verstehen?

mkl0815:
Hmm doch die String Klasse. Die würde ich auf jeden Fall entsorgen. Da Du mit den Strings selbst nichts machst, außer sie zu speichern, sollte einfach "String" gegen "char*", oder sogar "const char*" ausgetauscht werden.

Okay, dazu Fragen. Warum sind Strings schlecht? Sind das nicht letztendlich auch nur Char arrays? Was haben Chars als Vorteil gegenüber Strings?
Und wenn ich jetzt von String auf Char wechsel ist das doch für den User "relativ" aufwendig da er einen Namen z.B. so anlegen muss:

char name[5] = {'H', 'a', 'l', 'l', 'o'};

mkl0815:
Als nächstes würde ich auf jeden Fall von den "künstlichen" Indizes auf Zeiger umstellen, dann sparst Du Dir die Funktion getNeighbour(), da jeder Eintrag von forward, back, up und down gleich der passende Zeiger auf das nächste Item ist. Damit man einen definierten Start hat, würde ich ein "root" Element im Menu-Objekt definieren, welches immer den ersten Eintrag liefert. Zusätzlich sollte jedes MenuItem entsprechende Methoden getForward(), getBack(), getUp und getDown() haben, damit man auf die angehängten Elemente zugreifen und damit durch den Baum / Graph navigieren kann.

Das wäre der nächste Schritt gewesen, allein Schon damit ein Item nicht zwei mal existiert.

Unterm Strich: Würdet ihr diese Lib benutzen wenn ihr gerade ein Projekt amlaufen habt, bei dem ihr deratige Menüs braucht?

cr0n0s1:
Okay, dazu Fragen. Warum sind Strings schlecht? Sind das nicht letztendlich auch nur Char arrays? Was haben Chars als Vorteil gegenüber Strings?
Und wenn ich jetzt von String auf Char wechsel ist das doch für den User "relativ" aufwendig da er einen Namen z.B. so anlegen muss:

char name[5] = {'H', 'a', 'l', 'l', 'o'};

Strings sind "schlecht", die Klasse bei jeder String-Operation den knappen Speicher fragmentiert und am Ende jeder String mehr Platz weg nimmt, als der gleiche char*.

Einen C-String kann man auch folgendermaßen deklarieren:

char* name1 = "Hallo";
char name2[] = "Hallo";

Beide Variablen enthalten auch schon das abschliessende '\0' Zeichen. Was Dein "char name[5]" nicht macht. Dein "Hallo" hat als C-String kein Ende.
Und ein char* name = "Hallo" ist genau so aufwändig wie ein String-Objekt zu erzeugen.
Mario.

mkl0815:

char* name1 = "Hallo";

char name2[] = "Hallo";



Beide Variablen enthalten auch schon das abschliessende '\0' Zeichen. Was Dein "char name[5]" nicht macht. Dein "Hallo" hat als C-String kein Ende. 
Und ein char* name = "Hallo" ist genau so aufwändig wie ein String-Objekt zu erzeugen.
Mario.

Ahh super, das war mir vorher nie so bewusst, dann seh ich auch kein problem dadrin das ganze mit Chars zu machen :wink:

Ahh super, das war mir vorher nie so bewusst, dann seh ich auch kein problem dadrin das ganze mit Chars zu machen

Sorry, hätt' ich vielleicht vorher besser erklären sollen. Vermutlich kannst du dir gar nicht vorstellen, was passiert, wenn du schreibst:

String text = "Hallo";
text = text + "!";

text liefert zwar jetzt "Hallo!", aber der alte String("Hallo") liegt immer noch als Müll rum, weil er zu klein für den neuen text ist.

Ein char array ausreichender Größe ist im Endeffekt einfacher, wenn du erstmal dran gewöhnt bist, wie es zu benutzen ist.

Und wenn du dir dann angewöhnst, feste Texte gar nicht in den RAM zu legen :wink:

Wie soll ich dieses "konfiguriert statt programmiert" verstehen?

So wie du es machst, mit einer Liste von MenuElementen, die quasi in einer Tabelle definiert haben, wie sie zusammenhängen und welche Texte sie anzeigen, statt alles per Programm zu codieren.

Nur hab ich in meinem 328 nur noch 800 byte RAM frei, und ein SD Card Sektor ist halt mal 512 byte groß, da bin ich etwas knickig. Ausserdem geht's auch um's Prinzip, aus sportlichem Ehrgeiz...

Eure Erläuterungen zu Strings sind sehr interessant und gut zu Wissen.

Wie würde denn die richtige Implementierung der PROGMEM in die Lib aussehen?

Lib_X.h

const char **_flashText;

Lib_X.cpp

char ProgMemBuffer[20];
strcpy_P(ProgMemBuffer, (char*)pgm_read_word(_flashText));

*.ino

prog_char strServo1[]               PROGMEM = {"Servos AN"};

PROGMEM const char *MenServo_Strings[] = 
{   
  strServo1
};

KlasseX._flashText = &MenServo_Strings[0];

Funktionieren tuts, ist das auch die optimalste Art ohne Verbesserungsmöglichkeiten??

Könnte man evtl. die neue Funktion F("") irgendwie mit benutzen?
Damit wäre die Einbindung leichter.

Z.B.:

KlasseX.InitText(F("Servos AN"));

Könnte man evtl. die neue Funktion F("") irgendwie mit benutzen?
Damit wäre die Einbindung leichter.

Na klar, F("text") ist zwar keine Funktion sondern ein Makro in WString.h; der einzige Sinn ist, aus "text" den Pseudo-VariablenTyp __FlashStringHelper* zu machen, und als PSTR("text") im Flash abzulegen.

Musst du nur eine Methode InitText(const __FlashStringHelper* ptext) hinzufügen.
Zum Verwenden auf const prog_char* casten, oder einfach mit print() ausgeben.

So habe jetzt meine

Init(const __FlashStringHelper* Text)
{
	_Text3 = Text;
}

jetzt möchte ich den übergebenen Wert in der Klasse abspeichern, komme aber nicht weiter.
Ist das richtig?
const __FlashStringHelper* _Text3;

Ich möchte den Wert später an anderer Stelle wieder verarbeiten:
sprintf(Text, "%s", _Text3);

Brauche nochmals Hilfe, komme nicht weiter...

jetzt möchte ich den übergebenen Wert in der Klasse abspeichern, komme aber nicht weiter.
Ist das richtig?
const __FlashStringHelper* _Text3;

Ja, nur der Name _Text3 ist nicht sehr schön :wink:

Ich möchte den Wert später an anderer Stelle wieder verarbeiten:
sprintf(Text, "%s", _Text3);

sprintf kennt keinen __FlashStringHelper ( und auch kein PROGMEM )
print(_Text3); geht direkt, sonst schau nach den Funktionen, mit denen char aus dem PROGMEM geladen oder kopiert werden

Ja, Text3 auch nur deshalb, weil meine Lib momentan mehrere "Textformate" unterstützt. Wird dann später bereinigt :wink:

Die Fuunktion für PROGMEM ist klar: strcpy_P(Text, (char*)pgm_read_word(_Text2));

Dann werde ich mal suchen, was den __FlashStringHelper in ein char Array klopfen kann.

den __FlashStringHelper

... gibt es so gar nicht "wirklich".
Von einem Pointer auf einen __Flashstringhelper weiss man, dass print() es drucken kann, und dass man diesen Pointer als einen prog_char* ( oder einen PGM_P ) verwenden kann.

also z.B. strcpy_P(rambuffer, (prog_char*)Text3 );

--> arduino-1.0.1\hardware\tools\avr\avr\include\avr\pgmspace.h

Einsame Klasse - so gehts!

mkl0815:
Damit man einen definierten Start hat, würde ich ein "root" Element im Menu-Objekt definieren, welches immer den ersten Eintrag liefert. Zusätzlich sollte jedes MenuItem entsprechende Methoden getForward(), getBack(), getUp und getDown() haben, damit man auf die angehängten Elemente zugreifen und damit durch den Baum / Graph navigieren kann.

So ein ROOT Element halte ich auch für wichtig. Da beim Menü sich um eine Baum-Datenstruktur handelt. Und die Baumstruktur braucht immer eine Wurzel.

Siehe hier: