Wenn ich eine Funktion über einen Pointer aufrufe.
zb. über eine Menüstruktur.
Wird dann diese Funktion nur 1 mal ausgeführt oder läuft die sollange
von vorne los wie ich mich in diesem Menü befinde?
tastenzuordnung(1) <- geht so nicht
An diese Stelle in der Struktur darf nur der Funktionspointer, also nur
die Adresse der Funktion gespeichert werden. Bei dem Aufruf des Fkt-Ptrs
kannst du dann ein Argument angeben.
Tipp 2
======
Statt
1
voidtastenzuordnung(unsignedcharwert);
kannst du doch direkt den Pointer auf den aktuellen Menueintrag
übergeben. Somit wirst du auch gleich die globale Variable menu_index
los.
Da du sowieso nur 5 Funktionalitäten hast, die eine überschaubare Menge
darstellen, lass Funktionspointer sein und mach es konventionell mit
Funktions Codes, die in der Menüstruktur enthalten sind.
1
#define NO_ACTION 0
2
#define EXIT_ACTION 1
3
#define DEF_KEY_ACTION 2
4
#define DEF_REPEAT_ACTION 3
5
#define LCD_ACTION 4
6
#define LED_ACTION 5
7
#define SAVE_ACTION 6
8
9
typedefstructdef_menustruktur
10
{
11
constchar*text;
12
13
unsignedcharnext;
14
unsignedcharprevious;
15
unsignedcharsub;
16
unsignedcharup;
17
18
unsignedcharActionCode;
19
unsignedcharActionArgument;
20
}menustruktur;
Braucht weniger Speicher und ist auch einfacher zu handhaben
Heiko schrieb:
> tastenzuordnung(1) <- geht so nicht> An diese Stelle in der Struktur darf nur der Funktionspointer, also nur> die Adresse der Funktion gespeichert werden. Bei dem Aufruf des Fkt-Ptrs> kannst du dann ein Argument angeben.>
Ich weiß nicht wie ich dann jedem Menüpunkt eine Variable zuweisen soll.
> Statt>
1
voidtastenzuordnung(unsignedcharwert);
> kannst du doch direkt den Pointer auf den aktuellen Menueintrag> übergeben. Somit wirst du auch gleich die globale Variable menu_index> los.
Kannst du mir genauer erklären wie du das meinst.
> Braucht weniger Speicher und ist auch einfacher zu handhabenmenustruktur> menu[] PROGMEM => {> {menu_002, 0, 0, 0, 0, NO_ACTION, 0 },> {menu_100, 11, 1, 2, 1, NO_ACTION, 0 },> {menu_101, 3, 2, 1, 1, DEF_KEY_ACTION, 1 },> {menu_102, 4, 2, 1, 1, DEF_KEY_ACTION, 2 },> ...
Wie sieht denn dann die dazugehörige Funktion aus die ich für jeden
menüpuinkt aufrufen möchte?
Wenn ich richtig verstanden habe, was du vorhast, dann folgendes:
1
menustrukturmenu[]PROGMEM=
2
{
3
{menu_002,0,0,0,0,NULL},
4
{menu_100,11,1,2,1,NULL},
5
{menu_101,3,2,1,1,tastenzuordnung(1)},
6
{menu_102,4,2,1,1,tastenzuordnung(2)},
7
...
Ich vermute, du willst hier hinterlegen, daß später mal
tastenzuordnung(1) etc. aufgerufen wird.
Geht nicht wie Heiko scho sagte, weil so wie es hier steht
beim Initialisieren bereits die Funktion aufgerufen wird,
und nicht später beim Zugriff auf das Feld.
Besser:
In der struct noch ein Element vorsehen für das Argument.
Erst beim Aufruf dann Funktionszeiger und dieses Argument
zusammenbringen:
f_pointer zeigt auf tastenzuordnung -> Rekursion wenn ich mich nicht
irre.
Manfred:
Das Argument wert ist der Index des Menueintrages oder?
Wenn nein -> muss ich wohl nochmal überlegen...
Wenn ja:
Wer ruft den tastenzuordnung auf? in dieser Fkt ist der Index bekannt,
also kannst du direkt einen Ptr auf den Menueintrag dem f_pointer
übergeben und in diesem dann das von Klaus vorgeschlagene Feld argument
auswerten.
Manfred W. schrieb:
>> Braucht weniger Speicher und ist auch einfacher zu handhabenmenustruktur>> menu[] PROGMEM =>> {>> {menu_002, 0, 0, 0, 0, NO_ACTION, 0 },>> {menu_100, 11, 1, 2, 1, NO_ACTION, 0 },>> {menu_101, 3, 2, 1, 1, DEF_KEY_ACTION, 1 },>> {menu_102, 4, 2, 1, 1, DEF_KEY_ACTION, 2 },>> ...>> Wie sieht denn dann die dazugehörige Funktion aus die ich für jeden> menüpuinkt aufrufen möchte?
Der springende Punkt ist, dass das Menü dann gar nicht mehr automatisch
irgendeine Funktion aufruft. In der Funktion, die das Menü abarbeiten,
steht dann
1
....
2
3
if(menu[menu_index].ActionCode==DEF_KEY_ACTION)
4
nKeys=menu[menu_index].ActionArgument;
5
6
elseif(menu[menu_index].ActionCode==....)
Natürlich nicht so, sondern noch unter Berücksichtigung, dass das Menü
im Flash liegt.
Du machst schon wieder einen Kardinalfehler nach dem anderen.
Programmiere erst mal ein konventionelles Menü und achte darauf, dass du
die Flashzugriffe richtig machst, ehe du dich an Funktionspointern
versuchst.
Karl heinz Buchegger schrieb:
> Du machst schon wieder einen Kardinalfehler nach dem anderen.> Programmiere erst mal ein konventionelles Menü und achte darauf, dass du> die Flashzugriffe richtig machst, ehe du dich an Funktionspointern> versuchst.
Und zusätzlich:
Mit Techniken wie Funktionszeigern wird man auf einem PC
wesentlich einfacher warm.
Wenn man dann weiß, was man anrichtet, macht es erst auf
einem MC Sinn.
> Du machst schon wieder einen Kardinalfehler nach dem anderen.> Programmiere erst mal ein konventionelles Menü und achte darauf, dass du> die Flashzugriffe richtig machst, ehe du dich an Funktionspointern> versuchst.
Habs jetzt verstanden wie es abläuft.
Das menü ist ja schon komplett aufgebaut.
Mußte es jetzt nur anhand der Funktionstabelle anpassen.
Dabei hab ich ejtzt das problem das mein Untermenü bei Tastendruck nicht
mehr weitergesprungen wird:
Weil du dich wieder mal mit viel zu vielen Variablen selbst ausgetrickst
hast.
Wo wird menu_index verändert.
Was passier bei einem kurzen Druck auf KEY_0?
Was bedeutet das für menu_index?
Was heisst das dann daher folgerichtig für das nächste angezeigte Menü?
Wie spielt das hier:
> {menu_002, 0, 0, 0, 0, NO_ACTION, 0 },
dann mit hinein?
Wie stellst du dir vor, dass da jemals irgendein anderer Menüpunkt
'aktiviert' werden soll, wenn alle weiterführenden Indexeinträge aus
diesem Menüpunkt heraus wieder beim Indexeintrag 0 landen?
Auch:
Das hinschreiben des Menütextes bzw. Ausführen der Aktion ist ja wohl
nur dann notwendig, wenn eine Taste gedrückt wurde. Es macht keinen
Sinn, das jedesmal, bei jedem Durchlauf durch die Schleife,
durchzuführen.
> Warum?
Weil du dich noch immer mit Komplexität übernimmst, die du nicht
beherrscht.
Noch was:
Bau das alles zunächst ohne Flash auf. Also: komplettes Menü im
Speicher. Dann hast du eine Chance, dass dir der Compiler den einen oder
anderen Fehler findet. Und dann passiert dir sowas
menu_index = pgm_read_word(&menu[menu_index].text);
nicht. Hier, mit dem Umweg über das Flash kann sich der Compiler nicht
'wehren'. Er muss das so akzeptieren.
Aber so ...
menu_index = menu[menu_index].text;
... hätte er dich längst angepflaumt, dass da etwas nicht stimmt.
Und wie immer: vorher ein Konzept zurechtlegen.
Wie soll die Menüführung prinzipiell funktionieren? Was bedeutet das für
die Variablen? Was ist daher der Inhalt jeder Variablen? Und ruhig auch
einmal auf dem Papier ein einfaches Menü skizzieren, inklusive
Variablen, und durchspielen was bei einem Tastendruck zu geschehen hat.
Welche Variable bekommt welchen Wert? Warum bekommt sie ihn? etc.
Karl heinz Buchegger schrieb:
> Das hinschreiben des Menütextes bzw. Ausführen der Aktion ist ja wohl>> nur dann notwendig, wenn eine Taste gedrückt wurde. Es macht keinen>> Sinn, das jedesmal, bei jedem Durchlauf durch die Schleife,>> durchzuführen.
da geb ich dir recht.
Jedoch weiß ich nicht wie ich sonst Zentral die Anzeige aktuallisieren
soll.
Bei jedem Tastendruck das Display neu schreiben?
Mal abgesehen von den Fehlern die ich dadurch erhalte:
../main.c:306: warning: passing argument 1 of 'lcd_puts_p' makes pointer
from integer without a cast
Manfred W. schrieb:
> da geb ich dir recht.> Jedoch weiß ich nicht wie ich sonst Zentral die Anzeige aktuallisieren> soll.> Bei jedem Tastendruck das Display neu schreiben?
zb indem dar eigentliche LCD-Update in eine Funktion ausgelagert wird,
die dann, wenn ein Neubeschreiben notwendig ist, ganz einfach aufgerufen
wird.
So hat man die Logik des Update an nur einer Stelle gesammelt und kann
sie trotzdem überall einfach benutzen.
> lcd_puts_p(pgm_read_word(&menu[sub_menu_index].text));>> ../main.c:306: warning: passing argument 1 of 'lcd_puts_p' makes pointer> from integer without a cast
Was will lcd_puts_p haben?
Was liefert pgm_read_word?
> Mal abgesehen von den Fehlern die ich dadurch erhalte:
Und nein. Den Fehler hast du nicht durch die Umstellerei erhalten. Der
war vorher auch schon da.
Nochmal: Realisiere das erst mal alles, ohne dass du Dinge ins Flash
verlagerst. Erst dann, wenn alles funktioniert, fängst du an, Teile ins
Flash auszulagern.
Du führst einen 2-Fronten-Krieg und es mangelt an Erfahrung, wie man so
etwas meistern kann.
Daher: immer schön eins nach dem anderen. Mach dir nicht selbst das
Leben unnötig schwer. Zuerst soll das Menüsystem laufen und dann
kümmerst du dich um die Verschiebung der Daten ins Flash und die dazu
notwendigen Anpassarbeiten im Code.
Du hast einen Mega8 und genug SRAM, dass die paar Texte und die
Menüstruktur da reinpassen werden. Und wenn nicht: Dann speck während
der Entwicklung das Menü ab. Hauptsache du hast erst mal alles im SRAM
und kannst dich auf die Programmierung der Menü-Auswertung konzentrieren
und musst nicht zusätzlich auch noch Flashzugriffe gleichzeitig richtig
stellen.
OK, ich habe die Flashroutine nun komplett entfernt.
Beim compilieren wird auch keinen Fehler mehr angezeigt.
Einen Teil der Menüanzeige habe ich in einer Funktion ausgelagert. (Ob
es so Sinnvoll ist weiß ich jetzt noch nicht)
Was mir jetzt noch Sorgen macht sind 2 Sachen:
1.) Ich möchte gerne den eingestellten Wert (zb. der Tastenzuordnung)
beim verlassen des Menüs erhalten haben.
Darumd achte ich mir schreibe ich diesen in die Variable nKonfig.
Nur leider tut es das nicht. Ich erhalte immer 1.
Ich komm nicht dahinter.
Ein Denkanstoss wäre toll.
2.) Ich habe das Menü jetzt wieder so umstrukturiert das
1
constcharmenu_002[]="** HAUPTMENUE **";//
nun kein Teil der Menüstruktur mehr ist:
1
menustrukturmenu[]=
2
{
3
{menu_100,10,0,1,0,NO_ACTION,0},
4
{menu_101,2,1,0,0,DEF_KEY_ACTION,1},
5
{menu_102,3,1,0,0,DEF_KEY_ACTION,2},
6
{menu_103,4,2,0,0,DEF_KEY_ACTION,3},
7
{menu_104,5,3,0,0,DEF_KEY_ACTION,4},
8
{menu_105,6,4,0,0,DEF_KEY_ACTION,5},
9
{menu_106,7,5,0,0,DEF_KEY_ACTION,6},
10
{menu_107,8,6,0,0,DEF_KEY_ACTION,7},
11
{menu_108,9,7,0,0,DEF_KEY_ACTION,8},
12
{menu_109,9,8,0,0,DEF_KEY_ACTION,9},
13
{menu_200,21,0,11,10,NO_ACTION,0},
14
{menu_201,12,11,10,10,DEF_REPEAT_ACTION,0},
15
{menu_202,13,11,10,10,DEF_REPEAT_ACTION,1},
16
{menu_203,14,12,10,10,DEF_REPEAT_ACTION,2},
17
{menu_204,15,13,10,10,DEF_REPEAT_ACTION,3},
18
{menu_205,16,14,10,10,DEF_REPEAT_ACTION,4},
19
{menu_206,17,15,10,10,DEF_REPEAT_ACTION,5},
20
{menu_207,18,16,10,10,DEF_REPEAT_ACTION,6},
21
{menu_208,19,17,10,10,DEF_REPEAT_ACTION,7},
22
{menu_209,20,18,10,10,DEF_REPEAT_ACTION,8},
23
{menu_210,21,19,10,10,DEF_REPEAT_ACTION,9},
24
{menu_300,24,10,22,21,NO_ACTION,0},
25
{menu_301,23,22,21,21,LCD_ACTION,1},
26
{menu_302,23,22,21,21,LED_ACTION,1},
27
{menu_400,25,21,24,24,SAVE_ACTION,1},
28
{menu_500,25,24,25,25,EXIT_ACTION,1}
29
};
Da dies ja nur angezeigt werden soll, wenn ich im Hauptmenü bin.
Da ist jedoch leider jetzt das Problem.
Wie bekomme ich beim Rücksprung ins Hauptmenü diesen Text wieder in die
obere Spalte?
Ist diese vielleicht doch besser in der Struktur aufgehoben um darauf
zuzugreifen?
eine andere Frage:
Beim bedienen der Taster passiert es das das Display dünkler wird.
Jeh mehr Taster ich bediene umso dünkler wird es.
Ich habe das ganze jetzt mal mit einem gelöschten AVR probiert. Da tritt
dieses Verhalten nicht auf.
Am AVR hängt auch sonst nichts außer dem Display einem Taster und 2
taster zur Menünavigation drann.
Das Verhalten tritt nur beim Drücken des einzelnen Tasters auf.
Das hier irgendwas zuviel Strom zieht kann ich mir also nicht
vorstellen.
Das Display ist mit 5mA angegeben.
Die Versorgung erfolgt Wahlweise über den USB-Port oder mittels 3 AA
Batterien.
Also nehme ich fast an das die Software schuld sein müßte.
Kann es sein das der TimerInterrupt oder die Schleifen dieses Verhalten
hervorrufen?
Code im Anhang.
Ich sehe nirgends die Stelle an der nKonfig wieder aus dem EEPROM
ausgelesen wird und den Wert 1 von der Definition überschreibt.
Die "exotische" Schreibweise 00 z.B. eeprom_write_byte(00, nKonfig);
wird bei anderen Werten deinem Programm irgendwann das Genick brechen.
> Beim bedienen der Taster passiert es das das Display dünkler wird.> Jeh mehr Taster ich bediene umso dünkler wird es.
Was wird dunkler, die Zeichen auf dem Display (eher Softwareproblem)
oder die Hintergrundbeleuchtung (eher Hardwareproblem)? Wie sind die
Taster und das Display in Hardware verschaltet?
Stefan B. schrieb:
> Ich sehe nirgends die Stelle an der nKonfig wieder aus dem EEPROM> ausgelesen wird und den Wert 1 von der Definition überschreibt.>
Das ist richtig. Die Funktion wird momentan noch nicht genutzt. Mir ging
es vorerst darum die Speicherfunktion zu implementieren.
> Die "exotische" Schreibweise 00 z.B. eeprom_write_byte(00, nKonfig);> wird bei anderen Werten deinem Programm irgendwann das Genick brechen.>
Hm, was ist denn daran falsch? Der Wert der ins EEPROM gespeichert
werden soll liegt zwischen 1 und 9. Und der soll an die erste Stelle
gespeichert werden.
>> Beim bedienen der Taster passiert es das das Display dünkler wird.>> Jeh mehr Taster ich bediene umso dünkler wird es.>> Was wird dunkler, die Zeichen auf dem Display (eher Softwareproblem)> oder die Hintergrundbeleuchtung (eher Hardwareproblem)? Wie sind die> Taster und das Display in Hardware verschaltet?
Die Zeichen auf dem Display. Hab ich schon fast vermutet. Ich tippe mal
auf den Timer. Aber wie find ich das Problem nur? Der AVR läuft mit
8MHz. Kann das eventuell auch eine Auswirkung haben?
Also ist dein Problem nicht das Schreiben ins EEPROM sondern die
Zuweisung an nKonfig im Programm z.B. hier?
nKonfig = menu[menu_index].ActionArgument;
Irgendwann landest du mit den führenden Nullen bei Oktalzahlen.
Die Zeichen, hmm,
das kann einem schlechter werdenden Verhältnis von Löschen/Schreiben
hängen. Das Programm hält sich quasi länger in Bereichen auf, wo das LCD
gelöscht ist als in Bereichen in denen Zeichen ausgegeben sind.
Versuchsweise LCD Löschen auskommentieren und die (ja, verstümmelte)
Ausgabe betrachten.
Oder deine Kontrastspannung am LCD ist weniger stabil als du denkst.
Nachmessen mit Multimeter
Stefan B. schrieb:
> Also ist dein Problem nicht das Schreiben ins EEPROM sondern die> Zuweisung an nKonfig im Programm z.B. hier?> nKonfig = menu[menu_index].ActionArgument;>
Ja
> Die Zeichen, hmm,>> das kann einem schlechter werdenden Verhältnis von Löschen/Schreiben> hängen. Das Programm hält sich quasi länger in Bereichen auf, wo das LCD> gelöscht ist als in Bereichen in denen Zeichen ausgegeben sind.> Versuchsweise LCD Löschen auskommentieren und die (ja, verstümmelte)> Ausgabe betrachten.>
Das Display wird eigentlich nur 1 mal gelöscht und das ist vor der
While-Schleife.
Danach wird das Display immer nur überschrieben.
Was ich noch beobachtet habe. Das dunkelwerden verhält sich
unterschiedlich. Je nachdem ob das Hauptmenü ausgewählt wurde und man
dort navigieren kann oder nur die Wilkommensschrift angezeigt wird.
Im Hauptmenü wird es fast komplett dunkel.
> Oder deine Kontrastspannung am LCD ist weniger stabil als du denkst.> Nachmessen mit Multimeter
Die Spannung bricht beim Drücken der Taste etwas zusammen. Je mehr
Taster gedrückt werden umso mehr.
Was ich noch vergessen hatte war, die LCD Ausgänge als Ausgang zu
definieren. Aber das hatte keine Auswirkung auf das Display.
Was nun?
Die Schaltng mal im Anhang.