ich würde gerne ein LCD Menü realisieren, weiß aber nichtgenau wie. Mit
strukturen müsste eseigentlich einfach zu machen sein´. hat jemand von
euch eventuell ein programm mit einer menüstruktur?
danke für eure hilfe!!
ich habe WinAVR und einen ATmega8535
gruß,
Joe
du brauchst ein paar funktionen...
du springst von deiner "main-loop" wo du normal immer endlos
dahinschleifst oder wie auch immer in eine "menü-loop"...
endlosschleife die du in einem bestimmten fall verlassen tust..also
einfach ein break wenn irgendwas passiert...
void menu() {
menü anzeigen
while (1) {
if (bExit)
break;
Taste oder was auch immer holen
menü updaten
}
}
also was anzeigen tut is klar glaub ich..einfach das lcd "füllen" ;)
mit "Taste oder was auch immer holen" tust du nur schaun ob eine
taste gedrückt oder wie bei mir beim inkrementalgeber was gemacht
wurde
und das menü (ich tu einen pfeil dort hin wo ich grad bin) wird eben
dementsprechend neu gezeichnet
wenn du jetzt ein pointer-array im speicher hast das auf deine strings
zeigt... und du einen pointer auf die funktion reingibst auf die
funktion die schaut was welcher eintrag tun soll (switch-case) dann
hast du einmal den code und kannst damit auch verschachtelte menüs
machen...wenn dir der stack nicht ausgeht g
Hi
Ich bin auch dabei so ein lcd menü zu programmieren, doch irgendwie
bekomm ich in mein programm keine vernümpftige struktur rein, das wird
langsam ein durcheinander! Bis jet habe ich ges geschafft das man durch
ein hauptmenü durchblättern kann (hoch runter) mit switch case. Doch
irgendwie komme ich jet nicht weiter.
Kann jemand vielleicht ein ausschnitt aus seinem prog posten, damit ich
mal sehe wie das am besten geht?
Vielen dank schonmal im vorraus
MFG Jörn
PS: Mein prog befindet sich im anhang!
Aus dem Stegreif würde ich es (universell) so machen:
typedef struct MENU {
const unsigned char *text;
int8_t previous;
int8_t next;
int8_t up;
int8_t down;
void ( *fp )( void );
} MENU_ENTRY;
Das Menü ist dann ein Array von MENU_ENTRYs:
const MENU_ENTRY menue[] PROGMEM= {
{ menu_string0, 1, 2, 3, 4, menu_function },
Die Strings sehen dann so aus:
static const char menu_string0[] PROGMEM = "Hallihallo";
Die Funktion dann so:
void menu_function01( void );
Im Programm wird die gedrückte Taste per Timer-IRQ ermittelt, siehe
auch Peter Danneggers Code-Beispiel.
In der Hauptschleife musst Du dann je nach Taste die Variable für den
aktuellen Menüstand aktualisieren und gegebenfalls die zugehörige
Funktion aufrufen, falls es zum Menüpunkt eine gibt.
Anschliessend machst Du in der Hauptschleife noch einen Display-Refresh
(mit dem Eintrag text).
Hi,
ich bin jetzt schon ca 1 Woche dabei. Leider kriege ich aber nicht
wirkliches gebacken.
Ich habe es so gemacht wie Dieter vorgeschlagen hat.
Sprich eine Structur erstellt, danach ein Array dieser Struktur.
Jetzt fangen schon meine Probleme an. Ich habe ein Anfangspointer und
ein Endpointer erstellt.
struct menu *anfang=NULL
struct menu *ende=NULL
Nun wollte ich noch einen Pointer auf die einzelnen Array eintraege
machen.
Ich meinte eigentlich das es so funktioniert:
unsigned char *ptr;
ptr = menu;
Leider funktioniert das so nicht. Hmmm kann mir da jemand so ein
bischen unter die Arme greifen?
mfg
Dirk
Allerdings sollte man sowas wohl nur angehen, nachdem man das Kapitel
`Pointers & Arrays' aus dem K&R nicht nur gelesen, sondern auch
verstanden hat. ;-)
@Dirk:
Lass den Pointerkram weg. Deshalb hab ich es ja so wie oben gemacht.
Das brauchst Du dafür gar nicht. Nur in der Pflege bzw. Erweiterung der
Menüs ist das so etwas aufwendiger.
Du nimmst einfach eine uint-Variable, die der Index auf den aktuellen
Menüeintrag ist.
Die Einträge previous, next, up, down sind dann ebenfalls nur die
Indizes auf den jeweiligen Arrayeintrag.
Also Zugriff ganz simpel mit menue[x] :)
Sollte also Einsteiger-sicher sein...
Hi,
es nervt mich langsam tierisch an und irgendwann reisst auch mein
Geduldsfaden.
@Joerg Wunsch: Gut das du alles weisst und sofort verstehst. Du
solltest dich aber nicht sooft ueber andere Leute lustig machen die es
nicht so leicht haben wie du.
Mfg
Dirk
Ich mache mich nicht drüber lustig. Allerdings sollte man sein
Handwerkszeug halt verstehen, bevor man es benutzt.
Es kann eigentlich nicht oft genug geschrieben werden: Microcontroller
sind mit Abstand die miserabelste Plattform, auf der man die Sprache C
lernen kann. Das liegt vor allem daran, daß es sich dort deutlich
besch...er debuggen läßt als auf einem Universalprozessor unter einem
Betriebssytem.
Lerne C also besser erstmal auf dem Betriebssystem Deiner Wahl,
zusammen mit einem ordentlichen Debugger. Beim Übergang auf die
eingeschränkte Umgebung der Controller gibt's dann immer noch
genügend
Stolperfallen (gerade bei der Harvard-Architektur des AVR, besonders
in Kombination mit dem GCC, der mit Harvard praktisch nicht umgehen
kann). Gerade die Geschichte mit Zeigern und Feldern ist in C der
Teil, der auf den ersten Blick am kompliziertesten aussieht und daher
gern von vielen Leuten erstmal ignoriert wird... Andererseits ist er
(gerade für die Programmierung von Hardware, also Betriebssystemen
oder eben Controllern) unwahrscheinlich mächtig, so man ihn erstmal
verstanden hat. Aber mit trial&error kommt man selbst im gelobten
Zeitalter der mit kurzen Entwicklungszyklen erfreuenden Flash-ROMs auf
die Dauer in Teufels Küche (oder produziert bestenfalls Ergebnisse,
die rein zufällig funktionieren, ohne daß man weiß, warum eigentlich
;-).
OK, Du hast natürlich Recht, aber ich meinte doch das Wandern durch den
Menübaum ;) Der Aufruf der Funktion ist ja immer gleich.
@Dirk: In meiner Lösung darfst Du natürlich nicht vergessen, den
Funktionszeiger vor Verwendung aus dem Flash-ROM zu holen. Das liegt in
der Harvard-Architektur der AVRs begründet.
Wenn Du sonst noch Fragen hast, einfach posten.
Hi,
ich bin gerade dabei diese Sachen am PC zutesten. Ich bin auch schon um
einiges weiter.
Ich denke mal da werden aber noch ein paar Fragen auftauchen.
Mfg
Dirk
Hallo!
Habe mich auch an den Ansatz vom Dieter gehalten:
1
staticconstcharmenu_string0[]PROGMEM="Highpass";
2
staticconstcharmenu_string1[]PROGMEM="Bandpass";
3
staticconstcharmenu_string2[]PROGMEM="Lowpass";
4
5
typedefstructMENU{
6
constunsignedchar*text;
7
int8_tprevious;
8
int8_tnext;
9
void(*fp)(void);
10
}MENU_ENTRY;
11
12
constMENU_ENTRYmenue[]PROGMEM={
13
{menu_string0,2,1,highpass},
14
{menu_string1,0,2,bandpass},
15
{menu_string2,1,0,lowpass}
16
};
Jetzt versuche ich, den jeweiligen String auf dem LCD auszugeben:
1
strcpy_P(lcd_value,(char*)
2
pgm_read_word(menue[actual_menu_entry].text));
3
lcd_puts(lcd_value);
actual_menu_entry steht auf einem Wert zwischen 0 und 2.
(lcd.c von Peter Fleury)
Es passiert aber nicht wirklich was auf dem LCD.
Wie wann wo muß ich pgm_read_word einsetzen? Oder was mache ich
falsch?
Gruß
Markus
Hallo,
Dieter hat in seinem Posting vom 21.04.2004 davon gesprochen, dass der
Funktionszeiger bevor er benutzt werden kann aus dem Flash ausgelesen
werden muss.
Ich hab jetzt schon mehrere Varianten versucht, aber ich bekomme das
ganze net so hin.
Im Moment arbeite ich mit:
typedef void (*fptr) void
fptr function;
function = (int16_t*)(pgm_read_word(menu[x].fp));
function();
Leider habe ich mit dieser Methode keine Erfolg, da ich immer das
Warning: assigment from incompatible pointer type
Kann mir vielleicht jemand helfen?
Danke Volker
ich klink mich mal hier ein.
Ich habe nach etwas durcharbeiten das ganze jetzt gerafft (also die
Version mit dem Struct). Gefällt mir so eigentlich sehr gut (Besser als
State Machine) und nicht unbedingt schwerer.
Allerdings habe ich eins noch nicht so richtig verstanden beim Struct:
void ( *fp )( void );
Was bewirkt dies? Ich schätze es ist eine Funktion in einem Struct
(statt einer Variable)
Wie führe ich die funktion aus? Wie deklariere ich den Funktionsinhalt?
was sind die klammern? Und woher kommt der *fp Pointer? und warum steht
void in den klammern ?
Hallo Karl Heinz,
weißt du villeicht welchen Datentyp Funktionspointer im Flash haben,
daran scheint sich mein Win-AVR ja zu stören? soweit ich weiß sind das
immer 16Bit daher hab ich sowohl uin16_t und int16_t versucht aber
nichts von beidem funzt.
Gruß Volker
@Volker
Wozu musst Du das wissen?
Ein Funktionspointer ist ein Funktionspointer. Wozu
brauchst Du da uint16_t oder int16_t ?
Mir ist auch nicht klar, was Du mit
> typedef void (*fptr) void>> fptr function;> function = (int16_t*)(pgm_read_word(menu[x].fp));> function();
eigentlich bezwecken willst.
menu[x].fp ist bereits der Funktionspointer.
Um die Funktion die dahinter steckt aufzurufen, schreibst
Du ganz einfach:
(*menu[x].fp)();
hast Du vorher dem Menueeintrag x ueber
menu[x].fp = pgm_read_word;
den Funktionspointer zur Funktion pgm_read_word zugewiesen,
dann wird auch genau diese Funktion pgm_read_word aufgerufen.
> Mir ist auch nicht klar, was Du mit> > typedef void (*fptr) void> >> > fptr function;> > function = (int16_t*)(pgm_read_word(menu[x].fp));> > function();> eigentlich bezwecken willst.
Dann solltest du allerdings vielleicht auch nicht hier antworten...
AVR's Harvard-Architektur lässt grüssen. Syntaktisch ist das Ding im
Flash ein Funktionszeiger, aber man muss ihn erst in den RAM kopieren,
damit er auch wirklich benutzbar wird.
Liegt vielleicht eher daran, dass ich bei der
Funktion pgm_read_word() nicht geschaltet habe.
Ich dachte, das waere die Funktion die er indirekt
aufgerufen haben moechte.
Sorry.
bin eigentlich voll der noob und kenn mich mit bildschirmen nicht ganz
so doll aus, möchte aber wissen, ob es möglich ist, dass ein
lcd-bildschirm schaden nimmt, wenn er, nachdem der pc runtergefahren
ist, einfach von stromnetzt abgeschaltet wird, nichts standby oder
ausschalten, einfach strom weg, während er noch läuft...
ich befürchte dass die lc´s eben in ihrer struktur oder position oder
sonst was verändert werden, und das, wenn vielleicht nicht gleich ganz
zum knock out, aber doch zu einigen bildstörungen führen könnte, also,
wäre super wenn mir irgendwer irdendwie weiterhelfen könnte...
danke im voraus
<< Allerdings sollte man sowas wohl nur angehen, nachdem man das
Kapitel
`Pointers & Arrays' aus dem K&R nicht nur gelesen, sondern auch
verstanden hat. ;-)
>>
und für alle die sich damit schwer tun...
definiere eine
integer Menue = 1;
if (?Taste rechts gedrückt? ) Menue = Menue + 10;
if (?Taste links gedrückt? && Menue > 10) Menue = Menue - 10;
if (?Taste hoch gedrückt? ) Menue = Menue ++;
if (?Taste runter gedrückt? && Menue > 1) Menue = Menue --;
(Das kann man noch verfeinern und besser eingrenzen)
if (?Enter Taste gedrückt?)
switch (Menue)
{
case 1:if( stell
Mach_was_bei_1_zu_tun_ist;
break;
case 2:
Mach_was_bei_2_zu_tun_ist;
break;
Das kann man beliebig erweitern oder vertiefen.
Diese Version hat nur 2 Ebenen. Will man mehr, multipliziert man
einfach, statt zu addieren, also 1, 10, 100, ...
Hallo,
wie meine Vorgänger bin ich dabei ein Menü zu realisieren.
Die Variante von Dieter kommt mir da am geeignetsten vor, aber ich
krieg die Strings nicht mehr aus dem Flash - Ich glaub ich seh wieder
mal den Wald vor lauter Bäumen nicht.
// Definition of Menu entrys
static const char menu_str0[] PROGMEM = "Eintrag1";
static const char menu_str1[] PROGMEM = "Eintrag2";
static const char menu_str2[] PROGMEM = "Eintrag3";
static const char menu_str3[] PROGMEM = "Eintrag4";
typedef struct MENU {
const unsigned char *text;
INT next;
//void ( *fp )(void);
} MENU_ENTRY;
const MENU_ENTRY menue[] PROGMEM= {
{ menu_str0, 0/*, Function*/ },
{ menu_str1, 0/*, Function*/ },
{ menu_str2, 0/*, Function*/ },
{ menu_str3, 0/*, Function*/ }
};
.
.
.
strcpy_P(HelpStr, (char*) pgm_read_word
(menue[MENU_COUNT].text));
lcd_puts(HelpStr);
Die Funktionen hab ich erstmal ausgeblendet.
Kann mir jmd. Durchblick verschaffen?
Interessanter Ansatz!
Bin zwar noch blutiger Anfänger aber will ja lernen und werde es morgen
mal ausprobieren.
Hat evtl. noch jemand einen kompletten funktionstüchtigen Code da!?
(Ist für mich immer sehr hilfreich wenn ich nicht weiterkomme einen
lauffähigen Code zu sehen)
Gute N8 erstmal.
Gruß, Florian
Mir geht es ebenso wie Florian. Schein ein eleganter Ansatz zu sein,
doch steig ich noch nicht ganz durch.
Das ganze sollte auch (für den Anfang) ohne PROGMEM funktionieren oder?
Ist der Verbrauch von zusätzlichem RAM der einzige Nachteil dabei?
(Dafür schein mir der Aufruf einfacher zu sein.)
Hat jemand einen funktionsfähigen Code mit diesem Ansatz mit einem Menü
mit mehreren Ebenen um die Funktionsweise besser zu verstehen?
Gruss
Markus
Hallo Ihr Lieben,
nachdem in nun eine ganze Zeit mit diesem Menü verbracht habe, möchte
ich als Dank für die vielen Anstöße meinen funktionsfähigen Code hier
posten.
Die Zeiger rauben einem wirklich den letzten Nerv...
Hier die Bruckstücke, damit man das Ding zum Laufen bekommt:
1
// Damit aus dem Flash gelesen werden kann
2
#include<avr/pgmspace.h>
3
4
//Typ Funktionszeiger definieren
5
typedefvoid(*VoidFnct)(void);
6
7
8
// Funktionen für die einzelnen Menüeinträge:
9
10
voidmenu_function0(void){
11
//irgendwas machen bei 0...
12
}
13
14
voidmenu_function1(void){
15
//irgendwas machen bei 1...
16
}
17
18
voidmenu_function2(void){
19
//irgendwas machen bei 2...
20
}
21
22
23
typedefstructMENU{// Daten-Struktur für Menüeintrag
24
constunsignedchar*text;// Zeiger auf den anzuzeigenden String
25
// int8_t previous; // Zahl für vorherigen Menüeintrag, benötigt für mehrzeilige Displays
26
// int8_t next; // Zahl für nachfolgenden Menüeintrag, benötigt für mehrzeilige Displays
Darf ich darauf hinweisen, dass du auf einen zwei Jahre alten Post in
einem elf Jahre altem Thread antwortest? Bei sowas ist immer fraglich,
ob die früheren Teilnehmer noch mitlesen.
Dieter schrieb:> typedef struct MENU {> const unsigned char *text;> int8_t previous;> int8_t next;> int8_t up;> int8_t down;> void ( *fp )( void );> } MENU_ENTRY;
Das Thema ist zwar schon uralt.. Eventuel kann mir ja doch noch jemand
was dazu erklären...
Was genau sollen die Variablen "previous, next, up, down" bewirken?
Hat das etwas mit der Menüsteuerung zu tun? Oder waren das jetzt
speziell auf ein Projekt bezogene Variablen?
Würde mich auf eine Antwort freuen.
Das ganze basiert auf den AVR Butterfly, vielleicht findet man irgendwo
noch den Code dazu (seitdem Microchip umstellt nicht mehr ganz so
einfach).
Soweit ich mich erinnere sind das vier Tasten am Display die für die
Variablen stehen. Wird eine Taste gedrückt springt das Menü an der
Stelle, die in der Variable steht. Somit musste in jeden Menü-Eintrag
einmal definiert werden, was die Tasten an dieser Stelle machen.
p41145 schrieb:> Das ganze basiert auf den AVR Butterfly, vielleicht findet man irgendwo> noch den Code dazu (seitdem Microchip umstellt nicht mehr ganz so> einfach).>> Soweit ich mich erinnere sind das vier Tasten am Display die für die> Variablen stehen. Wird eine Taste gedrückt springt das Menü an der> Stelle, die in der Variable steht. Somit musste in jeden Menü-Eintrag> einmal definiert werden, was die Tasten an dieser Stelle machen.
Wie sollte denn die Abfrage funktionieren?
Ich hätte das "Array" jetzt anderst aufgerufen.
Jan H. schrieb:> Ich hätte das "Array" jetzt anderst aufgerufen.
Ein Array kann man gar nicht aufrufen.
"previous", "next", "up" und "down" sind übrigens auch keine
Variablen, sondern Elemente einer Struktur.
Für Grundlagenfragen bezüglich C ist dieser Uralt-Thread jedoch
denkbar ungeeignet. Bitte lass ihn in der Kiste liegen und starte
einen eigenen.
Bei dem Menü geht es ja auch nicht nur um Texte, die man darstellt,
sondern auch um Aktionen, die man auslöst.
Jörg W. schrieb:> "previous", "next", "up" und "down" sind übrigens auch keine> Variablen, sondern Elemente einer Struktur.
Klugsch***..
Was machen diese Elemente? Speichern sicherlicher irgendwas?
Jörg W. schrieb:> Bei dem Menü geht es ja auch nicht nur um Texte, die man darstellt,> sondern auch um Aktionen, die man auslöst.
Genau das wollte ich zu DIESEM Post wissen.
Was der Entwickler sich darunter vorgestellt hat.
Jan H. schrieb:> Im großen und ganzen sind das VARIABLEN.
Wenn du dir deine eigenen Definitionen von irgendwelchen Dingen
erfinden willst, ist das natürlich deine Sache. Erwarte aber nicht,
dass andere dich dann verstehen werden, wenn du sie um Hilfe fragst.