Hallo ich bin Anfänger in Programmierung und der Mikrocontroller Welt.
Nun versuche ich ein Menu für ein Lcd zu schreiben, bekomme es aber
leider nicht zum laufen.
Genutzt wird :
Atmel Studio 6 (Version: 6.0.1843 - ) GCC 4.6.1
1
typedefvoid(*MenuFnct)(int);
2
3
voiddummy_menu_func(intarg)
4
{
5
6
}
7
8
typedefstruct{
9
constcharSubLabel[16];
10
MenuFnctFunction;
11
intArgumentToFunction;
12
}SubMenu;
13
14
typedefstruct
15
{
16
constcharMainLabel[16];
17
SubMenu*SubMenues[10];
18
intsubLength;
19
}MainMenu;
20
21
SubMenusubMenu1[]=
22
{
23
{"sub0_1",dummy_menu_func,0},
24
{"sub0_2",dummy_menu_func,0},
25
{"sub0_3",dummy_menu_func,0}
26
};
27
28
SubMenusubMenu2[]=
29
{
30
{"sub1_1",dummy_menu_func,0},
31
{"sub1_2",dummy_menu_func,0}
32
};
33
34
MainMenuMMenu[]=
35
{
36
{"Main_eins",subMenu1,2},
37
{"Main_zwei",subMenu2,2},
38
};
Folgende Warnungen werden ausgespuckt :
Warning 5 missing braces around initializer [-Wmissing-braces]
Warning 9 initialization makes pointer from integer without a cast
Warning 10 (near initialization for 'MMenu[1].SubMenues[1]') [enabled
by default]
Durch das Hauptmenu kann ich ohne Probleme Scrollen, allerdings gibt es
Probleme bei den Submenueintraegen:
MMenu[0].SubMenues[0]->SubLabel - Ausgabe : "sub0_1"
MMenu[0].SubMenues[1]->SubLabel - Ausgabe : komische Zeichen...
MMenu[0].SubMenues[2]->SubLabel - Ausgabe : komische Zeichen...
Vielen Dank im Voraus
Heinz
Heinz schrieb:> typedef struct> {> const char MainLabel[16];> SubMenu *SubMenues[10];> int subLength;> } MainMenu;
Ein MainMenu ist also etwas, das einen Namen hat UND aus einem Array von
10 Pointern besteht.
> MainMenu MMenu[] => {> {"Main_eins",subMenu1,2},> {"Main_zwei",subMenu2,2},> };> [/c]
Das passt nicht. Eine Zeile in dieser Initialisierung ist 1 MainMenu.
Und an der Stelle, an der eigentlich das Pointer Array initialisiert
werden sollte, hast du nur subMenu1 stehen. Das ist aber keine
Initialisierung eines Arrays, denn sie steht immer innerhalb von { }.
Daher die Meldungen.
Was du (wahrscheinlich) wolltest ist
MainMenu MMenu[] =
{
{ "Main_eins", { subMenu1, subMenu2 }, 2 },
};
Also 1 Hauptmenü, welches den Namen "Main_eins" trägt und welches 2
Submenüs (nämlich subMenu1 und subMenu2) besitzt.
Zumindest verwendest du das hier
> MMenu[0].SubMenues[0]->SubLabel - Ausgabe : "sub0_1"> MMenu[0].SubMenues[1]->SubLabel - Ausgabe : komische Zeichen...> MMenu[0].SubMenues[2]->SubLabel - Ausgabe : komische Zeichen...
in dieser Form.
.... MMenu[0].SubMenues[2] ....
Ähm. Das gibt es nicht. In deinem MMenu gibt es nur 2 Submenüs. Ein
3-tes existiert nicht.
Wednn du mit den Verpointerungen durcheinander kommst, dann mal dir die
Dinge auf Papier auf!
Du hast gebaut
1
SubMenusubMenu1[]=
2
{
3
{"sub0_1",dummy_menu_func,0},
4
{"sub0_2",dummy_menu_func,0},
5
{"sub0_3",dummy_menu_func,0}
6
};
7
8
SubMenusubMenu2[]=
9
{
10
{"sub1_1",dummy_menu_func,0},
11
{"sub1_2",dummy_menu_func,0}
12
};
13
14
MainMenuMMenu[]=
15
{
16
{"Main_eins",{subMenu1,subMenu2},2},
17
};
und jetzt malen wir mal ein bischen. Wie sieht das ganze graphisch aus
1
MMenu
2
+-------------+
3
| "Main_eins" | subMenu1
4
| +----------+| +----------------+
5
| | o--------------------------->| "sub0_1" |
6
| +----------+| | o-------------> dummy_func
7
| | o---------------+ | 0 | ^^
8
| +----------+| | +----------------+ ||
9
| | || | | "sub0_2" | ||
10
| +----------+| | | o--------------+|
11
| 2 | | | 0 | |
12
+-------------+ | +----------------+ |
13
| | "sub0_3" | |
14
| | o---------------+
15
| | 0 |
16
| +----------------+
17
v subMenu2
18
+--------------+
19
| "sub1_1" | |
20
| o--------------------------------+
21
| 0 |
22
+--------------+
23
| "sub1_2" | |
24
| o--------------------------------+
25
| 0 |
26
+--------------+
wie kommst du, ausgehend von MMenu zb auf den Menüpunkt ganz unten?
Lies es einfach von der Grafik ab.
Ausgangspunkt ist MMenu.
MMenu
Das ist ein riesen Kasten. Wo findet sich dort der Pfeil, der zum Kasten
mit dem Menüpunkt führt? Er ist im Array und dort ist es der Eintrag mit
dem Index 1. Also
MMenu.SubMenues[1]
An dieser Stelle dort beginnt ein Pfeil. Um also vom MMenu Kasten zum
Kasten mitte/unten zu kommen, brauchen wir
MMenu.SubMenues[1]->
Jetzt sind wir beim Kasten mitte/unten angelangt. Wie gehts weiter? Der
Kasten ist selber wieder ein Array. Ein Array von SubMenu Einträgen.
Davon würden wir den Eintrag mit dem Index 1 brauchen.
MMenu.SubMenues[1]->[1]
Nur: Diese Syntax gibt es nicht.
Jetzt muss man sich an die Pointer/Array-Indizierungs-Dualität erinnern.
Dann weiß man, dass man diese Operation so
(MMenu.SubMenues[1])[1]
schreiben kann.
(Allerdings: lieber eine Hilfsvariable benutzen. Das ist
durchschaubarer!)
Damit sind wir beim kleinen Kasten innerhalb des grossen Kastens, der
einen Eintrag beschreibt. Und von diesem Eintrag möchten wir den Namen.
((MMenu.SubMenues[1])[1]).SubLabel
So. Jetzt geb ich unumwunden zu, dass diese Syntax grauenhaft ist.
Daher: Eine Zwischenvariable einführen! Ein Pointer auf das Array von
SubMenus bietet sich an:
SubMenu* completeSubMenu = MMenu.SubMenues[1];
lcd_string( completeSubMenu[1].SubLabel );
und bringt wieder Klarheit in den ganzen Ausdruck.
Entschuldigung für den letzten Beitrag, ich bin aus versehen auf
Absenden gekommen.
Oh Backe...
Meine Bezeichnungen sind ein wenig Irreführend.
MMain SubMenu
Main_eins Sub_eins
LCD - Helligkeit - dummy_func
- EcoMode - dummy_func
Main_zwei Sub_zwei
Messung - Intervall - dummy_func
- Logging - dummy_func
... ... ...
Das würde mir bereits genügen.
Deshalb dachte ich das man mit: MMenu[x].SubMenues[x]->SubLabel
auf das Array der struct SubMenu einfach zugreifen kann (was mit dem
ersten Eintrag aus dem SubMenu Array auch funktioniert)
Ich werde mir deine Erklärung später nochmal gründlich durchlesen und
versuchen die Syntax zu verstehen.
Das mit dem Aufmalen war ein guter Tipp, das vereinfacht es schonmal
enorm.
SChönen Dank.
Heinz schrieb:> Entschuldigung für den letzten Beitrag, ich bin aus versehen auf> Absenden gekommen.>> Oh Backe...>> Meine Bezeichnungen sind ein wenig Irreführend.>>> MMain SubMenu>> Main_eins Sub_eins> LCD - Helligkeit - dummy_func> - EcoMode - dummy_func>> Main_zwei Sub_zwei> Messung - Intervall - dummy_func> - Logging - dummy_func>> ... ... ...>> Das würde mir bereits genügen.
OK.
Das ist dann allerdings eine andere Struktur. Wie man ja auch deiner
jetzt konzeptionell sauberen 'Skizze' entnehmen kann, muss die so
aussehen
1
MainMenuMMenu[]=
2
{
3
{"LCD",{Sub_eins},1},
4
{"Messung",{Sub_zwei},1}
5
};
Kannst ja mal vergleichen, ob du auf dieselbe Schlussfolgerung gekommen
bist.
(Allerdings: Wenn das der Standardfall ist, frage ich mich, wozu du as
10-er Array von Pointern zu den Submenüs überhaupt brauchst :-)
IMHO braucht das eigentlich keiner.
Eine MMenu 'Zeile' besteht aus einem Text, der angezeigt wird. Und wenn
dieser Menüpunkt angewählt wird, dann wird das angegebene Sub-Menü
angewählt. Das kann aber sowieso nur eines sein! Bei Anwahl des
Menüpunktes "LCD" geht es ja immer weiter ins Sub Menü Sub_eins, welches
die LCD-Menüpunkte beinhaltet. (d.h. das Array braucht keiner und die
dort gespeicherte Anzahl ist in Wirklichkeit die Anzahl der Menüpunkte
im SubMenü!
1
typedefstruct
2
{
3
constcharMainLabel[16];
4
SubMenu*SubMenue;
5
intsubLength;
6
}MainMenu;
7
8
typedefstruct{
9
constcharSubLabel[16];
10
MenuFnctFunction;
11
intArgumentToFunction;
12
}SubMenu;
13
14
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
15
16
SubMenuSub_LCD[]=
17
{
18
{"Helligkeit",dummy_menu_func,0},
19
{"EcoMode",dummy_menu_func,1},
20
};
21
22
SubMenuSub_Measure[]=
23
{
24
{"Intervall",dummy_menu_func,2},
25
{"Logging",dummy_menu_func,3},
26
};
27
28
MainMenuMMenu[]=
29
{
30
{"LCD",Sub_LCD,ARRAY_SIZE(Sub_LCD)},
31
{"Messung",Sub_Measure,ARRAY_SIZE(Sub_Measure)},
32
};
Jetzt wird schön langsam ein Schuh draus.
> Ich werde mir deine Erklärung später nochmal gründlich durchlesen> und versuchen die Syntax zu verstehen.
Wenn du dir eine vernünftige Funktionsaufteilung machst, brauchst du die
Komplettsyntax nirgends. Teile deine Funtionen auf in Funktionen die mit
einem MainMenu arbeiten und Funktionen die mit einem SubMenu arbeiten.
Hallo.
Karl Heinz Buchegger schrieb:> Kannst ja mal vergleichen, ob du auf dieselbe Schlussfolgerung gekommen> bist.
Ja das bin ich. MenuFnct ist kein Array mehr was sich glücklicherweise
auch im Speicherverbrauch bemerkbar macht.
Program Memory Usage : 1908 bytes 23,3 % Full
Data Memory Usage : 438 bytes 42,8 % Full
Allerdings wird es langsam eng auf dem ATMega8, zumal das nur der
Optische Teil ist.
Karl Heinz Buchegger schrieb:> Wenn du dir eine vernünftige Funktionsaufteilung machst, brauchst du die> Komplettsyntax nirgends. Teile deine Funtionen auf in Funktionen die mit> einem MainMenu arbeiten und Funktionen die mit einem SubMenu arbeiten.
Gut, den Tipp werde ich wohl auch beherzigen, zur Zeit ist alles in
einer Funktion, was ein wenig Chaotisch aussieht.
Heinz schrieb:> Program Memory Usage : 1908 bytes 23,3 % Full> Data Memory Usage : 438 bytes 42,8 % Full>> Allerdings wird es langsam eng auf dem ATMega8, zumal das nur der> Optische Teil ist.
Auch dagegen lässt sich was tun.
Die Texte können ins Flash (ins Program Memory) ausgelagert werden und
anstatt fixen 16 Zeichen kann man dann auch nur den Platz in Anspruch
nehmen, den die Texte auch wirklich brauchen.
Aber alles zu seiner Zeit. Noch hast du genügend Platz.
Moin,
ersteinmal herzlichen Dank an "kbuchegg" für die tolle und (für mich)
sehr verständliche Erklärung! Daraus entstand ein wunderbar
funktionierendes LCD-Menü.
Gibt es Verbesserungsvorschläge zu meiner Verfahrensweise der Nutzung?
Was ich mir vorstellen könnte wäre eine Funktion die meine defines
ersetzt, habe aber noch keine Idee wie ich das derart einfach anstellen
könnte, daß das Kosten/Nutzen-Verhältnis noch passt.
Vielen Dank!
Ich würde die Funktionalität aufteilen:
Eine Funktion, die das Hauptmenü behandelt
und eine Funktion die das jeweilige Submenü behandelt.
Deine Tasten rgt/lft sind dann ganz einfach
rgt: vom Hauptmenü ins aktuelle ausgewählte Submenü wechseln
(Funktionsaufruf der Funktion, die das Submenü behandelt)
lft: aus der Submenüfunktion wieder aussteigen (return)
Die Variable menueebene brauchst du dann nicht mehr und die
durchgeknallte Syntax beim eigentlichen Funktionsaufruf vereinfacht sich
ebenfalls.
Ausserdem eröffnet sich dann auch die Möglichkeit, dass ein Submenü
wieder neue Submenüs haben könnte (mit entsprechender Erweiterung der
Datenstruktur)