Hi,
ich bin mittlerweile am verzweifeln mit PROGMEM. Ich würde gerne eine
Menüstruktur auf einem LCD anzeigen. Ich hab schon einiges gesucht und
probiert, aber irgendwie will das alles nicht so wie ich.
Es geht mir hier nicht drum etwas fertiges zu nutzen von wem anders und
es nicht zu verstehen, sondern es selbst zu machen und zu verstehen wie
das funktioniert! Leider bisher ohne erfolg.
Ich habe folgende Struktur:
1
#define MenuPoint0 "Einstellungen"
2
#define MenuPoint0_1 "Uhrzeit"
3
#define MenuPoint0_2 "Dauer"
4
#define MenuPoint0_3 "Weckzeit"
5
#define MenuPoint0_3_1 "Uhrzeit"
6
#define MenuPoint0_3_2 "Fadingzeit"
7
#define MenuPoint0_4 "Testeintrag 0_4"
8
9
typedef struct def_MenuStruktur
10
{
11
const char *text;
12
uint8_t next;
13
uint8_t previous;
14
uint8_t sub;
15
uint8_t up;
16
void (*funktion)(void);
17
} MenuStruktur;
18
19
MenuStruktur PROGMEM Menu[] =
20
{
21
{MenuPoint0, 7, 10, 1, 255, }, //0
22
{MenuPoint0_1, 2, 6, 255, 0, }, //1
23
{MenuPoint0_2, 3, 1, 255, 0, }, //2
24
{MenuPoint0_3, 6, 2, 4, 0, }, //3
25
{MenuPoint0_3_1, 5, 5, 255, 3, }, //4
26
{MenuPoint0_3_2, 4, 4, 255, 3, }, //5
27
{MenuPoint0_4, 1, 3, 255, 0, }, //6
28
{MenuPoint1, 10, 0, 8, 255, }, //7
29
{MenuPoint1_1, 9, 9, 255, 7, }, //8
30
{MenuPoint1_2, 8, 8, 255, 7, }, //9
31
{MenuPoint2, 0, 7, 11, 255, }, //10
32
{MenuPoint2_1, 12, 12, 255, 10, }, //11
33
{MenuPoint2_2, 11, 11, 255, 10, }, //12
34
};
Diesen struct würde ich jetzt gerne in etwa so auslesen:
1
char Output[4][20];
2
uint8_t MenuItemCount = 0;
3
4
strcpy(Output[0], Menu[MenuItemCount].text);
Also den Wert (hier z.B. ".text") in ein Array kopieren. Das
funktioniert soweit OHNE PROGMEM. Kommt jetzt aber das PROGMEM dazu,
geht das nichtmehr, was ja verständlich ist.
Also hab ich das versucht:
Was aber auch nicht den erhofften erfolg brachte. Ich hab noch einiges
anderes probiert, wie statt (char*) mit (PGM_P) etc... aber alles ohne
Erfolg. Compiler-Error bekomm ich keine. Wie bekomm ich das also hin?
Danke schonmal im vorraus!
Der jeweilige Menüpunkt liegt zwar im Flash.
Aber der Menüpunkt enthält einen Zeiger auf den Text. Und dieser Text
liegt nicht im Flash. Daher ist strcpy_P hier die falsche Funktion.
Aber mein Guter!
Du kannst doch nicht einfach irgendeine Funktion darein klatschen nur
weil "pgm" im Namen vorkommt und dann annehmen, dass das dann genauso
wie im RAM funktionieren wird.
Lies Dir mal genau durch was pgm_read_word macht und falls dann
notwendig stelle die nächste Frage.
Karl Heinz Buchegger schrieb:> Und dieser Text> liegt nicht im Flash.
Verstehe ich nicht.
#define MenuPoint0 "Einstellungen"
ist doch keine Variable. Der String sollte doch dann im Flash liegen,
oder nicht?
Hans schrieb:> Karl Heinz Buchegger schrieb:>> Und dieser Text>> liegt nicht im Flash.>> Verstehe ich nicht.>> #define MenuPoint0 "Einstellungen">> ist doch keine Variable. Der String sollte doch dann im Flash liegen,> oder nicht?
Warum sollte der im Flash liegen?
Solange du nichts anderes anordnest, kommt der String ins SRAM
Und hier
1
typedefstructdef_MenuStruktur
2
{
3
constchar*text;
vereinbarst du nur, dass in einer Menüstruktur ein Pointer steht. Der
Pointer selber ist natürlich dann im Flash. Aber wo er hinzeigt nicht.
Du baust das hier
der linke Teil (das Array) liegt durch das PROGMEM im Flash. Soweit
richtig. Aber die Pointer führen ins SRAM. Du hast nicht dafür gesorgt,
dass auch die Texte im Flash liegen.
>Verstehe ich nicht.>#define MenuPoint0 "Einstellungen">ist doch keine Variable. Der String sollte doch dann im Flash liegen,>oder nicht?
Was hat das damit zu tun? Wie das Literal aussieht hat doch keine
Auswirkung darauf wohin es gespeichert wird.
Dafür ist die Deklaration und Definition zuständig.
In deinem Strukt steht,
...
const char *
...
Ergo liegt zwar der Zeiger im PGM-Speicher aber nicht das worauf der
Zeiger zeigt.
Karl Heinz Buchegger schrieb:> Warum sollte der im Flash liegen?> Solange du nichts anderes anordnest, kommt der String ins SRAM
#define MenuPoint0 "Einstellungen"
der Define ist doch nur ein Makro. Zur Compile-Zeit wird doch einfach
(in diesem Fall) "Einstellung" durch MenuPoint0 ersetzt.
Also hier: würde dann stehen
MenuStruktur PROGMEM Menu[] =
{
{"Einstellung", 7, 10, 1, 255, }, //0
....
jetzt bin ich aber wirklich verwirrt. Ich dachte immer die
Makro-Expansion ist ein Einsetzen für einen Alias.
Hans schrieb:> Karl Heinz Buchegger schrieb:>> Warum sollte der im Flash liegen?>> Solange du nichts anderes anordnest, kommt der String ins SRAM>> #define MenuPoint0 "Einstellungen">> der Define ist doch nur ein Makro.
Der #define ist völlig uninteressant.
Du hast ein STring-Literal. Und solange du nichts dagegen unternimmst,
landet das im SRAM.
Du hättest genauso schreiben können
> MenuStruktur PROGMEM Menu[] => {> {"Einstellung", 7, 10, 1, 255, }, //0
genau das.
Das #define ändert daran nichts. Das ist nur syntaktischer Zucker, so
dass du den eigentlichen Test schreibweisenmässig im Code an einer
anderen Stelle hast. Aber es ist und bleibt ein Stringliteral.
> Ich dachte immer die Makro-Expansion ist ein Einsetzen für einen Alias.
Oho.
C-Buch
ein Makro ist nichts anderes als eine Textersetzung. Nicht mehr und
nicht weniger.
Im Grunde macht ein Makro nichts anderes als es auch dein Editor macht,
wenn du dir mittels Suchen&Ersetzen einen Text durch einen anderen Text
ersetzen lässt.
Ok, die Details sind ein wenig komplexer (aber nicht viel), aber im
Grunde ist das genau das, was ein Makro macht: es ersetzt einen Text
durch einen anderen Text.
Und zwar bevor der eigentliche C-Compiler den Quellcode zu Gesicht
bekommt!
> Also hier: würde dann stehen>> MenuStruktur PROGMEM Menu[] => {> {"Einstellung", 7, 10, 1, 255, }, //0
Ja, und?
Deine Strukturdefinition sagt
1
typedefstructdef_MenuStruktur
2
{
3
constchar*text;
4
uint8_tnext;
5
...
text ist nur ein Pointer. Dort steht die Adresse drinnen, an der der
Text zu finden ist. Und der (der Pointer) steht im Flash, weil auch
die komplette Struktur im Flash steht.
Aber das sagt nichts darüber aus, dass auch der Text im Flash zu finden
sein wird.
Karl Heinz Buchegger schrieb:> Deine Strukturdefinition sagt> typedef struct def_MenuStruktur> {> const char *text;> uint8_t next;> ...>> text ist nur ein Pointer. Dort steht die Adresse drinnen, an der der> Text zu finden ist. Und der (der Pointer) steht im Flash, weil auch> die komplette Struktur im Flash steht.> Aber das sagt nichts darüber aus, dass auch der Text im Flash zu finden> sein wird.
Deshalb habe ich ja gerade geschrieben. Das ich blöd bin. Ich habe
darauf nicht geachtet. Ich will mich jetzt nicht mehr weiter aus dem
Fenster lehnen. Aber ich vermute, dass der TO den Struct in PROGMEN
packen muss. Egal. Ich halte mich hier jetzt zurück.
>Aber ich vermute, dass der TO den Struct in PROGMEN>packen muss. Egal.
Ja, Hans. Das muss der TO tun. Oder auch nicht. Jedenfalls hat er.
Ich reiche mal Karl-Heinz ein Taschentuch.
Funktioniert genauso wie ichs mir vorgestellt hab!
@Oliver: Mit "strcpy_P(Output[0], Menu[MenuItemCount].text);" geht es
nicht, muss also wohl doch pgm_read_xxx davor.
Aufjedenfall danke an alle!
Darki schrieb:> wie rufe ich die Funkion ("void (*funktion)(void);") auf?
So wie immer.
Du brauchst entweder den Namen der Funktion oder (was im Grunde
eigentlich gleichwertig ist) deren Startadresse und ein () verursacht
dann den Aufruf der Funktion.
(Mal sehen ob du 2 und 2 zusammenzählen kannst)
time();
| |||
| |++
| | |
+--+ |
| |
Dieser 'Ausdruck' ist der Name einer Funktion. Und wie bei Arrays
steht der Name einer Funktion für deren Startadresse.
|
|
Und dieses () besagt, dass die Funktion aufgerufen werden soll,
deren Startadresse mit dem vorhergehenden Ausdruck festgelegt
wurde.
:-) Der Schlüssel liegt darin, dass man () als eine 'Operation'
auffassen kann, die auf die Startadresse einer Funktion angewendet
werden kann und zum Aufruf der Funktion führt.
Ob du nun die Startadresse der Funktion durch Nennung des Namens
spezifizierst, oder ob diese Adresse aus einer Variablen kommt, .....
Nur muss im Falle, dass die Startadresse aus einer Variablen kommt,
diese Variable dann natürlich auch vom Typ her ein Funktionspointer
sein. Und an dieser Stelle kommt dann auch mein Rat für jeden ins Spiel,
der mit Funktionspointern hantiert: Du sparst dir eine Menge
Schreibaufwand, wenn du dir erst mal einen typedef für den Datentyp des
Funktionspointers machst, anstatt dauernd ständig immer wieder die
ausführliche Deklaration/Definition eines Funktionspointers zu
schreiben. Denn aus pgm_read_word kommt ja erst mal nicht dieser
Datentyp raus. Numerisch ist das zwar schon richtig, aber der Datentyp
ist noch falsch ....
Gleichwertig und lesbarer geht's auch mit einem Typedef und Cast auf den
entsprechenden Prototypen.
Oder du verwendest __flash mitd er aktuellen Compiler-Version:
Das wollte der Compiler aber nicht.
Also der Versuch war die Adresse von .funktion in meinen FuncPtr zu
übergeben. Ging aber schief... vllt liegt auch an der Uhrzeit ;)
@Johann:
Danke, das mit ((void(*)(void)) funktioniert.
Hab mal nach "__flash" gegoogelt, aber da kam nix bei rum. Hast du einen
Link?
> Das wollte der Compiler aber nicht.
Genauer.
WAS wollte der Compiler nicht?
Der wirft ja nicht einfach eine Fehlermeldung aus "Ich will nicht"
> Also der Versuch war die Adresse von .funktion in meinen FuncPtr zu> übergeben. Ging aber schief... vllt liegt auch an der Uhrzeit ;)
Du musst anfangen zu realisieren, dass bei einer Zuweisung nicht nur
Zahlenwerte im Spiel sind sondern auch Datentypen. Der Ausdruck rechts
vom = ergibt einen Datentyp. Die Zuweisung erfolgt an eine Variable, die
auch einen Datentyp hat.
FuncPtr = pgm_read_word( ...
Welcher Datentyp steht links vom = ?
Da steht ein Funktionspointer
Welchen Datentyp ergibt der Ausdruck rechts vom = ?
Da kommt ein word raus (also ein uint16_t)
Sind die beiden Datentypen zuweisungskompatibel?
Nein, sind sie nicht. Die Datentypen passen nicht zusammen. Ein
uint16_t ist erst mal kein Pointer. Selbst wenn der Zahlenwert stimmt.
Wenn wir wissen, dass der Zahlenwert korrekt ist, können wir den
Compiler darin überstimmen, dass die Datentypen nicht zusammenpassen?
Ja, natürlich. Man kann den Compiler immer überstimmen. Mit einem
Cast
> @Johann:> Danke, das mit ((void(*)(void)) funktioniert.
Genau das wollte ich eigentlich vermeiden, dass du einfach nur
abschreibst ohne zu wissen, was du da eigentlich warum tust.
Erstmal danke nochmal für die hilfe!
Mein Problem ist immer der Pointer kram. Ich versteh zwar im grunde was
da passiert, aber ich steh immer total auf Kriegsfuß damit. Die
Grundlagen sind ja schön und gut, aber die Umsetzung in einem Konkreten
fall ist schwierig.
Daher zauder ich auch noch mit einem C Buch. Ich bin kein blutiger
Anfänger, aber es fehlt hier und da noch an Grundlagen. Oder an
Übersicht was grade passiert.
Hab schon paarmal versucht ein C Buch anzufangen zu lesen, aber schnell
langweil ich mich weil der Anfang bekannt ist und in späteren Kapiteln
fehlt dann Wissen von davor.
Es fehlt mir hier wohl an Ausdauer...
Danke aufjedenfall nochmals!
PS: Und wenn du ein Tip für nen C-Buch hast, was nicht ewig in Schleifen
etc rumeiert und auf µC bezogen ist, immer her damit!