Hallo,
gibt es in C sowas wie verkettete listen?
Mein Problem: Hab ein Display und verschiedene Menüpunkte die ich
aufrufen will. zum beilspiel wenn der cursor auf hauptmenü steht soll
das hauptmenü sich öffnen, und da gibts dann weitere untermenüs
ich hab damals mein LCD-Menü mit einer einfachen State-Machine
aufgebaut.
D.h. wenn auf einem bestimmten Menüpunkt <Enter> gedrückt wird, wird
eine Variable x auf 1 gesetzt, beim nächsten Schleifendurchlauf wurde
dann für x=1 das entsprechende Menü auf dem LCD ausgegeben.
gruß
natürlich geht das!
ich habe das so gelöst, dass ich mir eine tabelle angelegt habe, welche
einen Datentyp (struct) mit den Informationen fuer jedes Menü-Element
enthaelt.
z.b.
typedef struct menu_item_stag{
u8 u8_current_id;
u8 u8_next_menu_id;
u8 u8_prev_item_id;
u8 u8_prev_menu_id;
const u8* str_Titel;
/* ... */
}menu_item_s;
Mit dieser einfachen Struktur in einer Tabelle kannst du bereits deine
erste Menue-Ebene aufbauen.
Jedes Elemente muss wissen, zu welcher Menue-Ebene es gehört und welche
Position es innerhalb dieser Menue-Ebene einnimmt.
Somit kannst du mit entsprechenden Funktionen schön dein Menü aufbauen
und durch das Menü navigieren.
Ich habe z.b. ein 2.zeilen display.
es werden gleichzeichtig jeweils 2 Menü Punkte dargestellt.
Über einen Dreh-encoder navigiere ich hoch/runter durch das menü, wobei
der oberste eintrag als ausgewählt markiert ist.
das menü rotiert beim letzten wieder auf den ersten eintrag.
MFG
Also, ich habs auch in C gemacht. Dazu hab ich ein struct verwendet,
welches insgesamt fünf Einträge hat. Vier verweisen einfach auf weitere
structs desselben Typs, sind also im Prinzip nur Adressen, mit denen ein
Pointer geladen wird. Die Verweise gelten für den über- bzw.
untergeordneten sowie für den Eintrag drüber/drunter.
Der fünfte Eintrag ist ein Funktionspointer, welcher entsprechend dem
Menü-Eintrag eine Funktion aufruft. Diese Funktion übernimmt dann eben
die Display-Anzeige/Eingabe von Daten usw.
Die Menü-Implementation hab ich über ne Tabelle mit den entsprechenden
Einträgen realisiert.
Funktioniert recht gut.
Bin grad nicht zuhause, sonst könnt ich n bisschen genauer beschreiben,
wie ich's gelöst habe.
Ralf
Ja, bin noch da :)
Sorry, aber bin gestern nicht mehr dazu gekommen, nachzuschauen. Und
jetzt bin ich wieder nicht am Rechner.
Im Prinzip hab ichs wie Preller gemacht. Was hast du denn bereits an
Code? Kannst du den mal posten?
Ralf
@art
ich schlage vor, bevor wir ins Detail gehen, die beiden
Tinykon-Programmbeispiele 'mal runterzuladen und auszuprobieren.
Es handelt sich um kurze Simulationen, in denen verschiedene
Menüsituationen, wie sie zB auf einem Mikrocontrollerdisplay vorkommen,
demonstriert werden und die eigentlich auf jedem PC laufen sollten.
Dann sehen wir weiter.
mfg
> wie erstell ich in C tabellen
wie auch alle anderen Objekte:
- Datentypen definieren
- variablen des definierten Datentypen deklarieren
Dann per Zeiger auf die deklarierten Objekte zugreifen.
Villeicht solltest du dir erst mal ein Standardbuch über "Algorithmen
und Datenstrukturen" besorgen ...
Eine dynamische Liste sehe ich auch nicht gerade als sinnvoll für ein
Menue an, da das Menue vom Programmnutzer während der Laufzeit sicher
nicht verändert werden soll.
Aber versuchs mal hiermit, habe ich aus meinem Windows-Programm kopiert,
ist ein Teil der Kundekartei, aber vom Prinzip müsste es funktionieren.
kunAnker ist der Startzeiger und über aktKun kann man die aktuelle
Listenposition ermitteln.
Kann man sicherlich etwas eleganter machen, aber bei mir funktioniert es
soweit.
Jörg
mh, aber ich muss doch das ganze irgendwie dann in der main funktion so
aufrufen das es dann auch auf dem display erscheint. ich stell mich zwar
vielleicht jetzt mich dumm an, aber ich weiss es wirklich nicht.
Hab hier mal bei youtube ein Video von meinem LCD Menü reingestellt.
--> http://www.youtube.com/watch?v=GhUI7uQmt_c
das ganze ist auch in C mit structs und Tabellen realisiert.
Wie es auch meine Vorposter schon genannt haben.
Gesteuert wird das ganze über einen Dreh-Encoder und Taster.
Viel Spaß beim Entwickeln.
Ob Du eine verkettete Liste oder ein Array (ist sicherlich einfacher)
benutzt , beide müssen mit Inhalt gefüllt werden. Da Du ja sicherlich
schon weißt, wie das Menue aussehen soll, machst Du dir ein passendes
Array z.B.: static char *menue[]{... die einezelnen Menuepunkte, durch
Komma trennen..}; (array eindimensional), deklarierst das global vor
Deiner main-Funktion und schreibst die einzelnen Menuepunkte da rein.
In main kannst Du dann z.B.menue[0] an Deine LCD-Ausgabefunktion
übergeben,
die dann den ersten Eintrag aus deinem Menue auf dem Display darstellen
sollte.
@art
was genau "weißt" du denn über Menues? (ist wahrscheinlich einfacher,
daß du uns mitteils was du weißt als das was du nicht weißt, sonst wirds
zu lang)
Dir ist sicherlich bewußt, daß du
- irgendwas zur Eingabe brauchst, um innerhalb des Menues zu navigieren
- Irenendwas zur Ausgabe brauchst, welches dir den aktuellen Menuepunkt
anzeigt
- irgendeine Funktion hast, welche durch den jeweiligen Menuepunkt
aufgerufen wird.
Fangen wir doch mal ganz von vorne an:
- Wie lautet deine Menue-Grundstruktur, z.B.
1. Irgendwas
1.1 Irgendwas spezielles
1.1.1 Irgedwas spezielles lesen
1.1.2 Irgendwas spezielles löschen
2. was_anderes
2.1 was_anderes_Unterpunkt
3. noch_was_anderes
d.h. wieviele Ebenen, wieviele Unter-Menuepunkte?
- was nutzt du zur Eingabe? Welche "Tasten" stehen dir zur Verfügung?
(Cursor hoch/runter, eingabe, ESC)
zu welchem Menuepunkt soll unter welchen Bedingungen wann wohin
navigiert werden ?
- Was nutzt du zur Ausgabe?
Welche Ausgabegröße hat dein display,
ist scrollen notwendig (horizontal, Vertikal)
wie erfolgt die Darstellung des vorgewählten Menuepunkts?
Diese Grundfunktionalität kannst du gerne in Pseudosprache formulieren,
und dan in eine beliebige Hochsprahce deiner Wahl zu codieren, Unter
Zuhilfenahme von allen möglichen Sprachkonstrukten die die Sprache so
bietet (z.B. Listen, Zeiger, Arrays oder sonstewas)
erstmal das display: das hat vier zeilen.
habe ein pfeilkreuz (rechts, links, oben, unten) zur verfügung und eine
ok-taste.
also mein menü soll folgendermassen aufgebaut sein:
ich hab ein fenster nachdem ich das gerät einschalte.
und in der vierten zeile steht dann links hauptmenü und rechts modus.
wenn der cursor auf einen der beiden punkte steht. soll er ein neues
menüfenster aufmachen bei dem in der 1. zeile die überschrifft des
jeweiligen menüpunktes steht und da drunter weitere menüpunkte.
beispiel
wenn aber im ersten fenster nach dem einschalten cursor auf modus steht
und ok-taste wird gedrückt dann soll er in das menü modus wählen
springen
Displayanzeige:
1.zeile: Modus wählen.
2.zeile: xy
3.zeile: xy.
4.zeile: xy.
5.zeile: xy.
6.zeile: zurück.
anmerkung: da das display nur 4 zeilen hat brauch ich noch eine funktion
die dann das ganze routiert.
wenn cursor auf hauptmenü und ok-taste gedrückt
dann zeige das hauptmenü
Displayanzeige:
1.zeile: Hauptmenü
2.zeile: modus wählen
3.zeile: Einstellungen.
4.zeile: zurück.
wenn in dem hauptmenü cursor auf modus wählen und ok-taste gedrückt
dann zeige modus wählen:
Displayanzeige:
1.zeile: Modus wählen.
2.zeile: xy
3.zeile: xy.
4.zeile: xy.
5.zeile: xy.
6.zeile: zurück.
und noch eine anmerkung zum schluss. wenn man in dem untersten untermenü
ist und wenn der cursor dann auf einer bestimmten position steht und die
ok - taste gedrückt wird. soll er das oberste menüfenster aufmachen.
hoffe es ist einigermassen verständlich. wenn nicht mall ich euch mal
ein bild.
ach was ich noch vergessen hab zu sagen das ich unter Einstellungen
im menüpunkt helligkeit zum beispiel dann mit hilfe eines drehknopfes
die helligkeit des displays steuere zum beispiel
art wrote:
> ach was ich noch vergessen hab zu sagen das ich unter Einstellungen> im menüpunkt helligkeit zum beispiel dann mit hilfe eines drehknopfes> die helligkeit des displays steuere zum beispiel
du kannst auch die ganze Navigation durch das Menü mit einem Drehknopf
lösen "a la iPod" ;-)
--> http://www.youtube.com/watch?v=GhUI7uQmt_c
alles mit drehknopf
und einem zusätzlichen BACK Knopf
kannst aber stattdessen auch hoch/runter taster verwenden, die andere
art fand ich eleganter, aber ist geschmackssache.
da ich viele werte mit drehknopf einstelle... frequent, tastgrad,
ausgangsspannung, helligkeit, war es für mich nahe liegend auch die
navigation: hoch/runter über diesen drehknopf zu erledigen.
das ganze system kommt dann mit dem drehknopf(mit integriertem schalter
für "OK") und einer "zurück" taste aus!
Sebastian B. wrote:
> das ganze system kommt dann mit dem drehknopf(mit integriertem schalter> für "OK") und einer "zurück" taste aus!
Du solltest aber dringend was an der Frequenzeinstellweise ändern *dreh
dreh dreh ;)
Ich habs mal so gemacht, dass man jede Zehnerstelle einzeln einstellen
kann. Also: Zehnerstelle aussuchen -> Bestätigen -> Einen Wert aus 0-9
wählen -> Bestätigen -> Stelle fertig eingegeben.
Simon K. wrote:
> Sebastian B. wrote:>> das ganze system kommt dann mit dem drehknopf(mit integriertem schalter>> für "OK") und einer "zurück" taste aus!>> Du solltest aber dringend was an der Frequenzeinstellweise ändern *dreh> dreh dreh ;)>> Ich habs mal so gemacht, dass man jede Zehnerstelle einzeln einstellen> kann. Also: Zehnerstelle aussuchen -> Bestätigen -> Einen Wert aus 0-9> wählen -> Bestätigen -> Stelle fertig eingegeben.
hehe, naja, ne drehgeschwindigkeitserkennung hab ich schon drin, man
sieht ja das die hunderter stelle dann etwa im sekunden takt springt.
aber das mit der stellenauswahl hab ich auch drin, man kann die
einzelnen stellen über "links" und "rechts" auswählen. Das sollte nur
ein Beispiel für die Drehgeschwindigkeitserkennung sein.
ich muss gestehen das video ist eher sub-optimal ;-) aber war ja auch
mein erstes.
ich finde aber, ganz allgemein, das eine navigation über den drehknopf
gerade durch sehr verschachtelete menü-strukturen auf dauer angenehmer
ist, als über ein steuerkreuz.
MFG
art wrote:
> und was nützt mir das video wenn da keine listdatei ist.
kann später den source-code online stellen.
Ich denke die Grundfunktionen, wie den Aufbau der Menü-Struktur, den
Aufbau des rotierenden Menü-Anzeige, den Funktionsaufruf kannst du dir
da abschauen.
Ich habe allerdings viele verschiedene Menü-Elemente.
D.h. du musst den Code dann soweit verstehen um ihn entsprechend auf
deine BEdürfnisse "abzuspecken" da er so nicht compilierbar ist auf
Grund fehlender Header-Dateien.
Aber ich werde das heute abend mal soweit vorbereiten, dass du damit was
anfangen kannst!
WIe sieht denn dein Display aus? AUch 2-zeilig?
art wrote:
> nein mein display hat 4 zeilen und 18 zeichen in jeder zeile.> wäre dir sehr dankbar.
Hab gerade leider keine Zeit den code abzuspecken, aber schau dir mal
die Funktionen:
void MENU_StateMachine ();
void Show_current_Items ();
diese 2 Funktionen "erklären" eigentlich wie die Navigation durch das
Menü und der Aufbau der Anzeige funktioniert.
Wie gesagt: So ist das ganze NICHT compilierbar, aber es beschreibt
zumindest wie man es realisieren kann.
Wenn du fragen haben solltest kannst du dich ja melden.
MFG
So, hab jetzt mal kurz nachgeforscht. Folgendes hat sich mein Hirn
damals ausgedacht. Zuerst einmal das struct zur Definition der
Menu-Einträge:
1
typedefstructm_item{
2
structm_item*Up;
3
structm_item*Down;
4
structm_item*Left;
5
structm_item*Right;
6
void(code*fpPtr)(void);
7
}_stMenu;
Wie man sieht, sind die vier ersten Einträge einfach Pointer auf weitere
structs dieser Art. Der fünfte Eintrag ist ein Funktions-Pointer, mit
dessen Hilfe ich die durchzuführende Funktion aufrufe. Das kann
einerseits das Aktualisieren das Displays sein, oder einfach ein Reset,
oder, oder, oder...
Desweiteren ist eine Tabelle notwendig, welche die Menü-Struktur
definiert. Für ein Menü mit dem Aufbau:
- Menü 1
- Menü 11
- Menü 111
- ...
- Menü 12
- Menü 121
- ...
- Menü 13
- Menü 131
- ...
- Menü 2
- Menü 21
- ...
muss man dann sowas anlegen:
Diese Tabelle ist nicht komplett, sie soll nur das Konzept
verdeutlichen!
NULL ist durch #define NULL ((void *) 0) definiert, das sagt dann
einfach aus, dass es dort nicht mehr weitergeht, somit kann man Grenzen
für das Menü in die Tabelle eintragen. Möchte man einen "Wrap-Around"
realisieren, muss man eben anstatt NULL den entsprechenden Menü-Eintrag
hinschreiben.
Der fünfte Eintrag enthält jeweils die Adresse der aufzurufenden
Funktion.
Der dritte Teil des Ganzen ist die Menü-Routine:
1
voidMENU(void){
2
static_stMenu*stMenu={&stMenues[0]};
3
4
if(btMenuBusy==0){
5
if(KBRD_GETSKEY(KBRD_ARR_UP)==1){
6
if(stMenu->Up!=NULL){
7
stMenu=stMenu->Up;
8
LCD_CLEAR();
9
}
10
}
11
elseif(KBRD_GETSKEY(KBRD_ARR_RI)==1){
12
if(stMenu->Right!=NULL){
13
stMenu=stMenu->Right;
14
LCD_CLEAR();
15
}
16
}
17
elseif(KBRD_GETSKEY(KBRD_ARR_DN)==1){
18
if(stMenu->Down!=NULL){
19
stMenu=stMenu->Down;
20
LCD_CLEAR();
21
}
22
}
23
elseif(KBRD_GETSKEY(KBRD_ARR_LE)==1){
24
if(stMenu->Left!=NULL){
25
stMenu=stMenu->Left;
26
LCD_CLEAR();
27
}
28
}
29
}
30
stMenu->fpPtr();
31
}
Ich verwende nur vier Pfeiltasten, um durch das Menü zu navigieren. Die
jeweils aufgerufene Funktion entscheidet, ob z.B. durch einen Druck auf
Enter etwas aktiviert, oder ob die Taste Clear etwas löscht, ...
Das erschien mir schön flexibel :)
Da ich das ganze so geschrieben habe, dass nicht auf einen Tastendruck
gewartet werden muss, kann die Software noch andere Sachen nebenbei
machen, in meinem Fall z.B. eine DCF77-Auswertung, usw.
Das heisst, meine main-Funktion sieht grob geschrieben etwa so aus:
1
voidmain(void){
2
INIT_UART();
3
INIT_TIMER();
4
INIT_LCD();
5
while(1){
6
MENU();
7
DCF77_DECODE();
8
...
9
}
10
}
Hierfür ist es notwendig, dass der Pointer *stMenu static ist, damit
beim nächsten Aufruf von MENU() wieder dasselbe Menü angezeigt wird.
Den Aufruf von LCD_CLEAR() kann man weder vor dem Funktions-Aufruf noch
in der jeweiligen Funktion machen, da das Display ansonsten flackert.
Man könnte ihn höchstens hinter den letzten else-if-Block setzen.
Eine Möglichkeit wäre, sich über ein Flag zu merken, ob das Menü bereits
gezeigt wurde. Da meine ganze Software darauf basiert, dass niemals
irgendwo auf etwas gewartet wird, habe ich das auch nicht gebraucht.
Das globale Flag btMenuBusy kann in einer aufgerufenen Funktion gesetzt
werden, um das Navigieren des Menüs zu unterbinden (hilfreich bei
Eingaben) bzw. um die vier Pfeiltasten für die aufgerufene Funktion
freizumachen.
Jo, das wär dann mein Anteil zu der Sache... Hoffe, ich hab nichts
vergessen zu beschreiben.
Ralf
Mal ein anderes konzept:
wenn ich mir zu jedem einzelnen menüpunkt eine funktion schreibe, also
ein const char funktion, und dann ruf ich sie über einen zeiger auf wenn
der cursor auf der jeweiligen position steht und die ok taste gedrückt
wird.
würde das funktionieren?
> wenn ich mir zu jedem einzelnen menüpunkt eine funktion schreibe, also> ein const char funktion, und dann ruf ich sie über einen zeiger auf wenn> der cursor auf der jeweiligen position steht und die ok taste gedrückt> wird.
Das würde ich dann so lösen, dass du bei jedem Weiterschalten im Menü
eine Variable in-/dekrementierst, die quasi der Menü-Nummer entspricht,
beginnend bei 0 fürs erste Menü. Mit dieser Variablen als Index gehst du
in eine Tabelle, welche die zugehörigen Funktionsadressen beinhaltet,
und lädst damit den Funktionspointer, also so, wie ich es in meinem
Beitrag von gestern abend geschrieben habe.
Wenn du es über if-else if oder switch/case löst, dann wird das ein
riesiges Konstrukt, welches schlecht erweiterbar ist.
Ralf
ja aber du hast ja in deiner tabelle arrays drin die noch gefühlt werden
müssen mit inhalt oder nicht?
weil bei mir muss dann auf dem display konkrett sowas stehen:
1. zeile: name des menüs z.b hauptmenü
2. zeile: untermenü z.b Einstellungen
3. zeile: untermenü2 z.b Modus wählen
und in die untermenüs müssen auch anwählbar sein
> ja aber du hast ja in deiner tabelle arrays drin die noch gefühlt werden> müssen mit inhalt oder nicht?
Ja, klar. Anders gehts ja nicht. Bei meiner Variante bestimmt die
Tabelle, wie das Menü aufgebaut ist.
Was macht dir an dem Füllen sorgen? Ich weiss, dass es je nach Menügröße
ein Aufwand ist, das zu füllen, deswegen arbeite ich parallel an einem
Windows-Programm, mit dem ich die Menü-Tabelle automatisch erstellen
kann. Aber fürs manuelle Füllen der Tabelle für insgesamt 39 Menüs habe
ich etwa 20 Minuten gebraucht.
Du musst dir erstmal das Menü aufmalen, also:
- Menü 1 //0, Stufe 0
- Menü 1, Eintrag 1 //1, Stufe 1
- Menü 1, Eintrag 2 //2, Stufe 1
- Menü 1, Eintrag 2, Eintrag 1 //2, Stufe 2
- Menü 2 //3, Stufe 0
- Menü 2, Eintrag 1 //4, Stufe 1
- ... //5, ...
Das Durchnummerieren hilft beim Tabellen-Füllen, weil es dem Index
entspricht, an dem der jeweilige Eintrag hinterlegt werden muss.
Und dann schreibst du eben in die Tabelle die entsprechenden Einträge.
So steht dann an Index 0 für DOWN der Index von Menü 2, für UP das
letzte Menü der Stufe 0.
Umgekehrt für UP des Menü 2 der Index 0 -> Menü 1.
LEFT von Menü 1 erhält NULL, weils links daneben ja nix mehr gibt, und
RIGHT von Menü 1 zeigt auf Index 1, weil dort der erste Untereintrag von
Menü 1 steht.
Wenn du an der höchsten Stufe eines Zweiges angelangt bist, bekommt
RIGHT NULL zugewiesen, weil auch da gehts ja nimmer weiter.
Ralf
Nachtrag:
Da du das ganze Cursorgesteuert machst und mehrere Auswahlmöglichkeiten
pro angezeigtem Menü hast, müsstest du im Prinzip bei meiner Lösung
folgendes machen:
1. Die Einträge der Tabelle müssen so angeordnet sein, dass die
anzuzeigenden Untermenüs direkt hintereinander in der Tabelle liegen.
2. Du verwendest wie ich heute morgen geschrieben habe, eine Variable,
die dir anzeigt, auf welchen Eintrag du mit dem Cursor zeigst, beginnend
bei Null. Die Funktion "Zurück" liegt demnach immer bei 3.
3. Ist die Variable = drei, gehst du ins übergeordnete Menü zurück, bei
Null bis zwei addierst du diese Variable zum entsprechenden Index des
ersten Untermenüs dazu, und rufst den entsprechenden Funktionspointer
auf.
Habe ich so aber nicht getestet, da ist sicher noch austesten nötig!
Ralf
> also anstatt der zahlen in den klammern z.b [0] kann ich den menünamen> reinschreiben oder wie?
Nein, die Zahlen bleiben. Aber wenn du das Menü erstmal aufmalst (Papier
oder Texteditor) und die Zahlen dahinterschreibst, weisst du welche Zahl
in welche Klammer muss.
Ralf
und wie ich das so verstehe, wählst du die untermenüs mit dem
fadenkreutz aus, ich will es aber so machen das ich nur dann in das
nächste untermenü springe wenn ich die ok taste drücke.
ja aber meine menüpunkte müssen auch verschieden heißen
das obermenü z.b hauptmenü:
und dann darunter stehen auch noch menüpunkte wie einstellungen die nur
dann angewählt dürfen wenn der cursor sich darauf befindet und die ok
taste gedrückt wird
> und wie ich das so verstehe, wählst du die untermenüs mit dem> fadenkreutz aus, ich will es aber so machen das ich nur dann in das> nächste untermenü springe wenn ich die ok taste drücke.
Okay, bei mir wechselt man zwischen den Menüs direkt beim Druck auf eine
der Pfeiltasten. Aktionen wie Eingaben usw. werden wie bei dir durch
Druck auf die Enter-Taste ausgeführt, das entscheidet wie gesagt die
jeweilige Funktion.
Für dich wäre die notwendige Änderung dann, dass du beim Druck auf die
Pfeiltasten den Funktionspointer neu lädst, die Funktion aber nur dann
aufrufst, wenn Enter gedrückt wird.
> ja aber meine menüpunkte müssen auch verschieden heißen>> das obermenü z.b hauptmenü:> und dann darunter stehen auch noch menüpunkte wie einstellungen die nur> dann angewählt dürfen wenn der cursor sich darauf befindet und die ok> taste gedrückt wird
Wie gesagt, die Anzeige übernimmt die jeweils aufgerufene Funktion. In
deinem Fall musst du eben eine Funktion aufrufen, die einerseits die
Anzeige übernimmt, und zusätzlich das Abfragen/Bearbeiten der
Cursorposition.
> ist das deine funktion zur return taste? KBRD_GETSKEY(KBRD_ARR_UP)
Fast. Diese Funktion prüft, ob die aktuell gedrückte Taste dem Wert
KBRD_ARR_UP (Pfeil oben) entspricht. Wenn ja, löscht sie den
Tastaturpuffer, damit beim nächsten Aufruf nicht nochmal die gleiche
Taste erkannt wird, und gibt 1 zurück.
Ist es nicht die gewünschte Taste, wird auf die nächste Taste geprüft,
usw.
Ralf
art wrote:
> Ralf was ich nicht verstehe ist: wo du den einzelnen menüpunkten namen> gibst wie sie heissen sollen.
@Ralf:
Ja, das ist eine gute Frage von art: Wo weist du den Einträgen die Namen
zu?
Ich habe einen Post darüber gelesen, dass die aufzurufende Funktion dies
übernimmt. Aber ich finde das etwas unsauber - also vom Modul-Gedanken
her. Es mag ja alles schön funktionieren und aussehen, aber
übersichtlich ist das meiner Meinung nach nicht. Da die Funktion dies
wie eine "Black-Box" übernimmt.
Wäre es nicht sinniger dein struct um einen String-Eintrag für den Titel
zu erweitern?
Was mich auch etwas stutzig gemacht hat ist folgendes:
in deiner Funktion MENU() wird diese Zeile immer ausgeführt:
stMenu->fpPtr();
und MENU wiederum wird in der while(1) Schleife von main() aufgerufen.
Das bedeutet, dass die aktuelle Funktion permanent aufgerufen wird, wenn
nichts am Menü verändert wird.
Liegt dies im Sinne des Erfinders???
Ich würde die Funktion nur OnEvent aufrufen, also wenn tatsächlich ein
Tastendruck statt gefunden hat, ansonsten muss die Funktion dies
abfangen, was wiederum unschön ist und nicht dem Modul-Gedanken
entspricht.
MFG
mal eine andere frage wieso kennt der compiler das wörtchen debounce
nicht?
ich hab an den PD2 einen taster angeschlossen
und damit möcht ich ausdrücken wenn er gedrückt worden ist soll er den
cursor um eine zeile weiter nach unten bewegen.
so und jetzt nach dem ich die neuere version installiert hab kennt er
das nicht mehr der compiler
debounce(&PIND, PD2)
Entschuldige, aber irgendwie werde ich das Gefuehl nicht los, das ist
dein erstes Programm? Moechtest du nicht lieber beim C-Buch auf der
ersten Seite anfangen?
Wie gesagt, die Anzeige wird bei mir komplett von der jeweils
aufgerufenen Funktion übernommen. Das entspricht meiner Vorstellung von
Modularisierung. Es macht m.E. keinen Sinn, einmal einen String aus
einem Struct auszugeben, und den Rest des Menüs durch die aufgerufene
Funktion.
Dass die Funktion ständig durchlaufen wird, hat ebenfalls seinen Sinn,
da ich in einigen, aber nicht allen Menüs z.B. die Uhrzeit ausgebe, das
wird somit erschlagen. Ausserdem mache ich in den Funktionen jeweils die
Tastenauswertung. Wird keine Taste gedrückt, wird sie wieder verlassen,
ansonsten wird eben die Taste ausgelesen und entsprechend verwertet. Wie
gesagt, das entspricht meiner Vorstellung von Modularisierung, ich lasse
mich aber gerne eines besseren belehren.
Ralf
art wrote:
> mal eine andere frage wieso kennt der compiler das wörtchen debounce> nicht?>> ich hab an den PD2 einen taster angeschlossen> und damit möcht ich ausdrücken wenn er gedrückt worden ist soll er den> cursor um eine zeile weiter nach unten bewegen.> so und jetzt nach dem ich die neuere version installiert hab kennt er> das nicht mehr der compiler>> debounce(&PIND, PD2)
Warum sollte er das Wörtchen "debounce" kennen?
Debounce heißt meines Wissens nach Entprellen, ich würde nun vermuten,
dass dies eine Funktion zur Entprellung der Taster ist.
Ausserdem wüsste ich nicht wie man das Entprellen eines Tasters sauber
über eine Funktion lösen sollte. Da Entprellen etwas mit "waren" zu tun
hat... und warten in einer Funktion ist nie eine gute Idee.
Timer-gesteuert ist das etwas anderes.
Ist das dein erstes Mikrocontroller-Projekt? (nicht als Kritik
verstehen, aber wenn man mehr zu deinen Hintergründen erfährt kann man
dir auch mehr helfen)
ja das erste grössere, bzw programmier das erste mal in c einen µc,
davor auf assembler programmiert aber auch nicht sowas grosses.
ja aber debounce ist eine funktion die in einer library doch enthalten
sein soll von avr studio.
Ralf wrote:
> Wie gesagt, die Anzeige wird bei mir komplett von der jeweils> aufgerufenen Funktion übernommen. Das entspricht meiner Vorstellung von> Modularisierung. Es macht m.E. keinen Sinn, einmal einen String aus> einem Struct auszugeben, und den Rest des Menüs durch die aufgerufene> Funktion.
Ja, ok, die Funktion übernimmt die Anzeige des Strings, welcher mit der
Funktion verbunden ist. Aber wer übernimmt die Anzeige der eigentlichen
Menü-Struktur?
Z.B.:
"1. Menü-Punkt 1"
"2. Menü-Punkt 2" usw. ... ?
> Dass die Funktion ständig durchlaufen wird, hat ebenfalls seinen Sinn,> da ich in einigen, aber nicht allen Menüs z.B. die Uhrzeit ausgebe, das> wird somit erschlagen.
Ist das ganze denn deterministisch, also zeitlich konstant? Denn mal
dauert ein Aufruf vielleicht 30 Mikrosekunden dann mal 33 Mikrosekunden
oder noch länger, wenn dir ein Interrupt dazwischen haut. Wie willst du
damit eine saubere Zeitbasis für die Uhrzeit bekommen, wenn du so einen
zeitlichen Jitter drin hast?
>Ausserdem mache ich in den Funktionen jeweils die> Tastenauswertung. Wird keine Taste gedrückt, wird sie wieder verlassen,> ansonsten wird eben die Taste ausgelesen und entsprechend verwertet.
das meinte ich mit OnEvent.
>Wie> gesagt, das entspricht meiner Vorstellung von Modularisierung, ich lasse> mich aber gerne eines besseren belehren.>
Ja, Modularisierung hat ja als grundlegende Konzepte:
- die Funktion eines Moduls z.b. Menü in sich "zu binden", d.h. intern
Funktion bereitstellen um alles realisieren zu können, was zur
Darstellung und Steuerung des Menüs benötigt wird. Hier darf z.b. keine
Display-Ansteuerung oder Taster-Auswertung erfolgen... dies geschieht
über Schnittstellen, welche das Modul Display und das Modul Taster
bereit stellt.
Das wäre dann die "Kopplung", die Schnittstellen zu den anderen Modulen
sollen möglichst "schmal" sein (also möglichst wenige Parameter
beinhalten) damit die Module gut austauschbar oder erweiterbar sind.
art wrote:
> ja das erste grössere, bzw programmier das erste mal in c einen µc,> davor auf assembler programmiert aber auch nicht sowas grosses.> ja aber debounce ist eine funktion die in einer library doch enthalten> sein soll von avr studio.
sorry benutze kein avr studio. Kann dir da also nicht weiterhelfen.
Hast du denn die Header-Datei richtig inkludiert? Befindet sich die Lib
im richtigen Verzeichnis?
ansonsten Entprellung über Timer-Funktion realisieren.
> Ja, ok, die Funktion übernimmt die Anzeige des Strings, welcher mit der> Funktion verbunden ist. Aber wer übernimmt die Anzeige der eigentlichen> Menü-Struktur?
Okay, also mal ganz von vorne:
- Die Anzeige der einzelnen Menü-Inhalte wird von der jeweils zum
Menü-Eintrag gehörenden Funktion übernommen
- Die Struktur des Menüs, also welcher Eintrag unter/über/links/rechts
von einem anderen Eintrag steht, wird durch die Einträge in der Tabelle
übernommen -> das entspricht den Zahlen in den eckigen Klammern
- Die Funktion MENU() übernimmt nur das navigieren zwischen den
einzelnen Elementen und den Aufruf der zum jeweiligen Menü-Eintrag
gehörenden Funktion
- Das Auswerten von nicht der Navigation dienenden Tastatureingaben ist
Aufgabe der jeweiligen Funktion
Soweit ich das verstanden habe, habt ihr ein Menü, in dem ihr einen
Cursor dazu verwendet, auf den jeweils nächsten Eintrag zu zeigen.
Ich dagegen habe etwas in der Art:
Betriebsart
+- Autonom
+- Starten
+- Konfigurieren
+- Online
+- Verbinden
+- Upload
+- Download
+- Offline
Einstellungen
+- System
+- Schnittstelle
+- Baudrate
+- Zeit/Datum
+- Uhrzeit
+- Datum
+- ...
Jeder Eintrag bringt wie gesagt seine eigene Displaymaske mit. Das soll
jetzt nur mal dem besseren Verständnis dienen, warum meine Funktionen so
sind, wie sie sind :)
Um wieder zu eurem Menü zurück zu kommen:
Ihr wollt also etwas in der Art auf dem Display:
[1. Menü]
--- Hauptmenu ---
* 1. Einstellungen
2. Starten
3. Stoppen
4. ---
[2. Menü]
--- Einstellungen ---
* 1. Uhrzeit
2. Datum
3. Schnittstelle
4. zurück
Hab ich das so richtig verstanden?
Das Sternchen markiert jetzt mal den Cursor. Durch die Pfeiltasten setzt
ihr also den Cursor hoch/runter, Enter geht ins entsprechende Menü bzw.
einen Zweig zurück. Soweit richtig?
Ich kann das jetzt leider nicht eben "mal schnell" hinzaubern, ich muss
mir erstmal überlegen, ob das mit meiner Software so überhaupt möglich
ist.
> Ist das ganze denn deterministisch, also zeitlich konstant? Denn mal> dauert ein Aufruf vielleicht 30 Mikrosekunden dann mal 33 Mikrosekunden> oder noch länger, wenn dir ein Interrupt dazwischen haut. Wie willst du> damit eine saubere Zeitbasis für die Uhrzeit bekommen, wenn du so einen> zeitlichen Jitter drin hast?
Ja, weil die Uhrzeit in einem Timer-Interrupt läuft. Da ich das auf
einem 8051-Derivat mache, habe ich natürlich unterschiedliche Zeiten pro
Befehl, dies wird jedoch vom Timer-Interrupt beachtet, indem er nicht
einfach mit einem festen Wert neu geladen wird, sondern den Reload-Wert
aufaddiert bekommt.
Kurze Erläuterung: von Eintreten des Interrupts in die Service-Routine
bis zum Laden des Timers vergehen noch eine Befehlszyklen fürs Pushen
der Register usw. Der Timer läuft ja derweil noch weiter. Indem der
Reload-Wert drauf addiert wird, wird der "Jitter" wieder ausgeglichen.
Bzgl. der Modularisierung, ich finde das eigentlich gut modularisiert:
- Es gibt Funktionen für Tastatur und Display
- Die MENU()-Funktion und zugehörige Tabelle sowie die aufgerufenen
Funktionen kapseln die jeweils notwendigen Schritte für das Darstellen
und Ausführen des Menüs.
Ralf
Zunächst: Vielen Dank für die ausführliche Erläuterung.
Ralf wrote:
>> Ja, ok, die Funktion übernimmt die Anzeige des Strings, welcher mit der>> Funktion verbunden ist. Aber wer übernimmt die Anzeige der eigentlichen>> Menü-Struktur?> Okay, also mal ganz von vorne:>> - Die Anzeige der einzelnen Menü-Inhalte wird von der jeweils zum> Menü-Eintrag gehörenden Funktion übernommen
Ja, das war soweit klar.
> - Die Struktur des Menüs, also welcher Eintrag unter/über/links/rechts> von einem anderen Eintrag steht, wird durch die Einträge in der Tabelle> übernommen -> das entspricht den Zahlen in den eckigen Klammern
Ok, das habe ich auch verstanden.
> - Die Funktion MENU() übernimmt nur das navigieren zwischen den> einzelnen Elementen und den Aufruf der zum jeweiligen Menü-Eintrag> gehörenden Funktion> - Das Auswerten von nicht der Navigation dienenden Tastatureingaben ist> Aufgabe der jeweiligen Funktion
Das ist soweit auch völlig verständlich und i.O.
> Soweit ich das verstanden habe, habt ihr ein Menü, in dem ihr einen> Cursor dazu verwendet, auf den jeweils nächsten Eintrag zu zeigen.> Ich dagegen habe etwas in der Art:>> Betriebsart> +- Autonom> +- Starten> +- Konfigurieren> +- Online> +- Verbinden> +- Upload> +- Download> +- Offline> Einstellungen> +- System> +- Schnittstelle> +- Baudrate> +- Zeit/Datum> +- Uhrzeit> +- Datum> +- ...
Wo ist da jetzt der Unterschied zu einem Menü mit cursor? Wie wechselst
du beispielsweise zwischen Betriebsart und Einstellungen? Meiner Meinung
nach sollte es da ein "Hauptmenü" geben das ein Wechseln zwischen diesen
Untermenüs zulässt.
> Jeder Eintrag bringt wie gesagt seine eigene Displaymaske mit. Das soll> jetzt nur mal dem besseren Verständnis dienen, warum meine Funktionen so> sind, wie sie sind :)
Das mit der Display-Maske und Verarbeitung in der Funktion ist auch
völlig ok und sinnig.
> Um wieder zu eurem Menü zurück zu kommen:> Ihr wollt also etwas in der Art auf dem Display:>> [1. Menü]> --- Hauptmenu ---> * 1. Einstellungen> 2. Starten> 3. Stoppen> 4. --->> [2. Menü]> --- Einstellungen ---> * 1. Uhrzeit> 2. Datum> 3. Schnittstelle> 4. zurück>> Hab ich das so richtig verstanden?
Ja, das ist doch der Sinn eines Menüs ?! Eine Navigation durch
verschiedene System-Funktionalitäten.
Das mit den display-Masken und so weiter ist klar! Aber wenn du das
System startest was zeigst du dann auf dem Display an?
Interessant wäre ja auch was für ein Display du hast? Bei dir klingt es
so als wird bei dir kein "Menü" dargestellt, sondern immer nur der
aktuell aktive menü-punkt! Du hast sozusagen ein "virtuelles Menü".
Was Art aber will ist doch ein sichtbares Menü?
Du hingegen wechselst doch nur zwischen den Funktionen deines Systems,
oder?
>> Ist das ganze denn deterministisch, also zeitlich konstant? Denn mal>> dauert ein Aufruf vielleicht 30 Mikrosekunden dann mal 33 Mikrosekunden>> oder noch länger, wenn dir ein Interrupt dazwischen haut. Wie willst du>> damit eine saubere Zeitbasis für die Uhrzeit bekommen, wenn du so einen>> zeitlichen Jitter drin hast?> Ja, weil die Uhrzeit in einem Timer-Interrupt läuft. Da ich das auf> einem 8051-Derivat mache, habe ich natürlich unterschiedliche Zeiten pro> Befehl, dies wird jedoch vom Timer-Interrupt beachtet, indem er nicht> einfach mit einem festen Wert neu geladen wird, sondern den Reload-Wert> aufaddiert bekommt.> Kurze Erläuterung: von Eintreten des Interrupts in die Service-Routine> bis zum Laden des Timers vergehen noch eine Befehlszyklen fürs Pushen> der Register usw. Der Timer läuft ja derweil noch weiter. Indem der> Reload-Wert drauf addiert wird, wird der "Jitter" wieder ausgeglichen.
Ok, dann ist es soweit klar! Ich hätte mir nur Gedanken gemacht, wenn
das ganze ohne Timer realisiert wäre.
Aber warum nutzt du nicht einfach den Timer um das Menü z.b. nur alle 50
ms aufzurufen. Das würde doch völlig reichen, da der Benutzer ja sowieso
nicht schneller die Tasten betätigen kann... (?)
> Bzgl. der Modularisierung, ich finde das eigentlich gut modularisiert:> - Es gibt Funktionen für Tastatur und Display> - Die MENU()-Funktion und zugehörige Tabelle sowie die aufgerufenen> Funktionen kapseln die jeweils notwendigen Schritte für das Darstellen> und Ausführen des Menüs.
Ja, das ist auch meine Meinung. Es klingt modularisiert. Nur weiß ich
nicht ob das Modul "Menü" schon eine vollständige Menü Realisierung in
sich trägt oder nur Navigationsmöglichkeiten.
Ist deine Menü-Tabelle eigentlich const? Und wo weißt du die
Funktionspointer zu?
(das würde art vielleicht zum besseren Verständnis dienen)
Das was du dargestellt hast war ja nur die Menü-Struktur mit den
Pointern in einer Tabelle, aber auf die Initialisierung der Strukturen
bist du nicht eingegangen ;-) ganz so funktioniert die Tabelle dann eben
auch nicht..
MFG
> Das mit den display-Masken und so weiter ist klar! Aber wenn du das> System startest was zeigst du dann auf dem Display an?
Der Menü-Pointer ist static und wird auf den ersten Eintrag der Tabelle
initialisiert. Ich habe keinen Ober-Menüeintrag, nur einen "obersten"
Eintrag, der zuerst angezeigt wird.
> Interessant wäre ja auch was für ein Display du hast? Bei dir klingt es> so als wird bei dir kein "Menü" dargestellt, sondern immer nur der> aktuell aktive menü-punkt!> ...> Du hingegen wechselst doch nur zwischen den Funktionen deines Systems,> oder?
Das ist im Prinzip korrekt. Wobei ich dazu sagen muss, dass mir die
Variante, die ihr haben möchtest, gleichwertig zusagen würde. Die hatte
ich anfangs auch im Sinn, ich habe mich deswegen dagegen entschieden,
weil es mir zu aufwendig vorkam, einerseits das Cursor-Menü und
andererseits auch noch die Eingabemasken separat zu machen.
> Du hast sozusagen ein "virtuelles Menü".> Was Art aber will ist doch ein sichtbares Menü?
Deswegen grübel ich bei Gelegenheit mal nach, wie sich das geschickt
lösen lässt, damit es für ART brauchbar ist.
Was mir auf die schnelle einfällt: Ließe es sich lösen, wenn man mein
struct so abwandelt, dass es:
1. einen Pointer auf den auszugebenden Menütext enthält
Der Text wird entsprechend bei einem Menüwechsel ausgegeben
2. Vier Unions enthält, welche jeweils aus einem Funktionspointer und
einem Pointer auf das struct gebildet werden
Punkt 1. ist denke ich klar.
Zu Punkt 2, der Funktionspointer soll verwendet werden, wenn der
entsprechende Menü-Punkt eine "richtige" Funktion enthält, also z.B.
eine Tastatureingabe. Der Pointer auf ein struct soll verwendet werden,
wenn sich unter dem Menüpunkt noch ein weiteres Menü befindet.
Das war jetzt wirklich mal in zwei Minuten zusammengedacht, aber könnte
prinzipiell klappen. Was meint ihr dazu?
> Aber warum nutzt du nicht einfach den Timer um das Menü z.b. nur alle 50> ms aufzurufen. Das würde doch völlig reichen, da der Benutzer ja sowieso> nicht schneller die Tasten betätigen kann... (?)
Korrekt, das wäre eine Möglichkeit, mehr Rechenzeit freizuschaufeln.
Falls jemand das Prinzip mal brauchen kann:
Der Timer läuft auf einer Zeitbasis von 3,333ms. Innerhalb der ISR gibt
es eine State-Variable, welche bei jedem Durchlauf erhöht wird, bis sie
den Wert drei erreicht, in diesem Fall wird sie auf Null zurückgesetzt.
Das heisst, ich habe drei Abschnitte der ISR, welche jeweils alle 10ms
abgearbeitet werden, mit einem Versatz von eben 3,333ms zueinander. Hier
mache ich dann z.B. die Tastaturabfrage und die Uhrzeit sowie ein paar
Software-Timer.
> Ja, das ist auch meine Meinung. Es klingt modularisiert. Nur weiß ich> nicht ob das Modul "Menü" schon eine vollständige Menü Realisierung in> sich trägt oder nur Navigationsmöglichkeiten.
Die Funktion MENU() an sich bietet noch kein Menü, das ist richtig,
meine Lösung besteht aus den drei Teilen MENU(), der Tabelle und den
jeweils aufgerufenen Funktionen.
> Ist deine Menü-Tabelle eigentlich const? Und wo weißt du die> Funktionspointer zu? (das würde art vielleicht zum besseren Verständnis> dienen)
Ja, die Tabelle ist im Code-Speicher abgelegt. Die Funktionspointer sind
im letzten Eintrag zugewiesen:
m1 und m11 wären dann die Adressen der aufzurufenden Funktionen.
> Das was du dargestellt hast war ja nur die Menü-Struktur mit den> Pointern in einer Tabelle, aber auf die Initialisierung der Strukturen> bist du nicht eingegangen ;-) ganz so funktioniert die Tabelle dann eben> auch nicht..
Sorry, da versteh ich jetzt nicht, was du mit Initialisieren meinst. Die
Tabelle ist fix im Code-Speicher hinterlegt, und da die Tabelle ein
Array des Menü-Structs ist, sind die Strukturen ja initialisiert.
So, ich klopp mich jetzt in die Falle, bis morgen dann. Ich glaube, wenn
wir so weitermachen, wird da am Ende ein schönes Stück Code rauskommen,
welches wir dann in die Code-Sammlung stellen können :)
Ralf
also ich hab jetzt folgendes gemacht Ralf:
void hauptmenue()
{
lcd_clear();
set_cursor(0, 1);
lcd_string("Hauptmenue:");
set_cursor(0, 2);
lcd_string("1/4 Modus waehlen");
set_cursor(0, 3);
lcd_string("2/4 Einstellungen");
set_cursor(0, 4);
lcd_string("zurueck");
set_cursor(4, 2);
}
void modus_waehlen()
{
lcd_clear();
set_cursor(0, 1);
lcd_string("Modus wählen:");
set_cursor(0, 2);
lcd_string("1/4 xy");
set_cursor(0, 3);
lcd_string("2/4 xy");
set_cursor(0, 4);
lcd_string("zurück");
set_cursor(4 , 2);
}
void einstellungen()
{
lcd_clear();
set_cursor(0, 1);
lcd_string("Einstellungen:");
set_cursor(0, 2);
lcd_string("1/3 Spannung");
set_cursor(0, 3);
lcd_string("2/3 Helligkeit");
set_cursor(0, 4);
lcd_string("zurück");
}
char (*menuestruktur[])() = {
hauptmenue, modus_waehlen, einstellungen
};
habe char funktionen gemacht und eine tabelle
so und jetzt hab ich schonmal angefangen in die main funktion zu
schreiben
static char a;
if (debounce(&PIND, PD3))
a = (*menuestruktur[0])();
so jetzt brauch ich aber noch einen zeiger mit dem ich hin und her
springen kann oder? damit ich in das nächste untermenü komme vom
hauptmenü
kommt aber auch ein warning, kann damit aber nichts anfangen:
warning: initialization from incompatible pointer type
heisst es das ich einen pointer vom typ habe der nicht kompatibel ist zu
dem was ich mache?
>> m1 und m11 wären dann die Adressen der aufzurufenden Funktionen.
Ah, ok das hatte ich übersehen, dann ist das auch klar!
Zusammenfassen müsste ein Menü-Element nun folgendes behinhalten:
- unsigned char * p_MenueEintragTitel;
- menu_struct * p_Vorgaenger_MenueEintrag;
- menu_struct * p_Nachfolger_MenueEintrag;
- void (* p_Funktionszeiger) (void);
- menu_sturct * p_Naechstes_Menue;
-> nennen wir es einfach mal menu_struct;
Ist das soweit ok?
Damit koennte man schon mal ein Menue in der Hauptebene definieren.
menu_struct ErsteMenueEbene[3]={
{"Hauptmenue", &(ErsteMenueEbene[2]), &(ErsteMenueEbene[1]),NULL,
&(ZweiteMenueEbene[0])},
{"Modus waehlen", &(ErsteMenueEbene[0]), &(ErsteMenueEbene[2]),NULL,
&(DritteMenueEbene[0])},
{"Einstellungen", &(ErsteMenueEbene[1]), &(ErsteMenueEbene[0]),NULL,
&(VierteMenueEbene[0])}
};
Das ganze nur mal als Prinzip-Aufbaue der ersten Menue-Ebene.
Die übrigen Menue-Ebenen müssten jetzt nicht in einzelne Tabellen,
sondern die Menue Tabelle koennte einfach 2D werden.
also
menu_struct Menue_Tabelle[MENUE_EBENEN][MENUE_EINTRAEGE];
MFG
Ralf prinzip von der tabelle verstanden. aber jetzt brauch ich noch in
der main funktion einen pointer der dann nach jedem tastendruck hoch bzw
runtergezählt werden oder nicht?
art wrote:
> Ralf prinzip von der tabelle verstanden. aber jetzt brauch ich noch in> der main funktion einen pointer der dann nach jedem tastendruck hoch bzw> runtergezählt werden oder nicht?
Du brauchst einen Zeiger, der auf den aktuellen Menue-Eintrag zeigt, das
ist richtig.
z.b.
noch nicht sehr weit, und wie geb ich das ganze auf dem display aus? da
muss ich dann praktisch ne neue funktion schreiben, weil momentan kann
ich nur strings an des lcd display senden
menu_struct ErsteMenueEbene[3]={
{"Hauptmenue", &(ErsteMenueEbene[2]), &(ErsteMenueEbene[1]),NULL,
&(ZweiteMenueEbene[0])},
{"Modus waehlen", &(ErsteMenueEbene[0]), &(ErsteMenueEbene[2]),NULL,
&(DritteMenueEbene[0])},
{"Einstellungen", &(ErsteMenueEbene[1]), &(ErsteMenueEbene[0]),NULL,
&(VierteMenueEbene[0])}
};
Das ganze nur mal als Prinzip-Aufbaue der ersten Menue-Ebene.
Die übrigen Menue-Ebenen müssten jetzt nicht in einzelne Tabellen,
sondern die Menue Tabelle koennte einfach 2D werden.
also
menu_struct Menue_Tabelle[MENUE_EBENEN][MENUE_EINTRAEGE];
wo menü_eintrag steht also bei dem menu struct menue_tabelle ist das
dann die ebene wo ich die unterpunkte zu den einzelnen menüs
reinschreibe?
Hi art,
> habe versucht das zu implementieren bekomme aber errors und warnings
Mit der Aussage wirst du keinen Erfolg haben ;)
Poste den Code, den du aktuell verwendest, und die Warnings/Errors dazu.
Ralf
das ist der ausschnitt
struct menu_struct
{
unsigned char *MenueEintragTitel;
struct menu_struct *Vorgaenger_MenueEintrag;
struct menu_struct *Nachfolger_MenueEintrag;
void (* p_Funktionszeiger) (void);
struct menu_sturct *Naechstes_Menue;
}
struct menu_struct ErsteMenueEbene[3]={
{"Hauptmenue", &(ErsteMenueEbene[2]), &(ErsteMenueEbene[1]),NULL,
&(ZweiteMenueEbene[0])},
{"Modus waehlen", &(ErsteMenueEbene[0]), &(ErsteMenueEbene[2]),NULL,
&(DritteMenueEbene[0])},
{"Einstellungen", &(ErsteMenueEbene[1]), &(ErsteMenueEbene[0]),NULL,
&(VierteMenueEbene[0])}
};
und das sind die errors und warnings die ich dazu bekomme:
../Menü-Funktionen.c:49: error: two or more data types in declaration
specifiers
../Menü-Funktionen.c:50: warning: pointer targets in initialization
differ in signedness
../Menü-Funktionen.c:50: error: 'ZweiteMenueEbene' undeclared here (not
in a function)
../Menü-Funktionen.c:51: warning: pointer targets in initialization
differ in signedness
../Menü-Funktionen.c:51: error: 'DritteMenueEbene' undeclared here (not
in a function)
../Menü-Funktionen.c:52: warning: pointer targets in initialization
differ in signedness
../Menü-Funktionen.c:52: error: 'VierteMenueEbene' undeclared here (not
in a function)
Wenn das direkt der Code ist, den du verwendest, und nicht Copy&Paste
vom obigen Beitrag, dann hast du einen Schreibfehler in deinem struct:
> struct menu_struct> {> unsigned char *MenueEintragTitel;> struct menu_struct *Vorgaenger_MenueEintrag;> struct menu_struct *Nachfolger_MenueEintrag;> void (* p_Funktionszeiger) (void);> struct menu_sturct *Naechstes_Menue; <-- hier steht stu_rc_t!> }
Zu den anderen Fehlern/Warnings, sind denn 'ZweiteMenueEbene,
DritteMenueEbene, VierteMenueEbene' überhaupt irgendwo definiert? Das
ist jetzt hier nicht ersichtlich...
Ralf
nein sind nirgendswo definiert aber hab auch schon versucht sie zu
definieren aber dann kommen andere errors. kannst mir sagen wie ich die
definieren soll?
AUTSCH!
A: das sind die errors und warnings die ich dazu bekomme: [ ...
Fehlermeldungen zu verschiedenen Objekten ... ]
R: sind denn [ ... verschiedene Objekte ... ] überhaupt irgendwo
definiert?
A: nein sind nirgendswo definiert aber hab auch schon versucht sie zu
definieren aber dann kommen andere errors
@art
Bist du dir ganz sicher daß du die richtige systematische Vorgehensweise
zur Programmentwicklung drauf hast? Vielleicht solltest du mal stärker
drüber nachdenken WIE du Probleme löst / programmierst, und weniger
WELCHE Algorithmen du implementieren willst.