Hallo zusammen,
Ich habe mir für einen ATmega64 eine Menüstruktur gebastelt.
Das Menü ist sehr umangreich. Insgesamt 61 Menüs mit Untermenüs.
Das struct sieht so aus:
1
structMenu{
2
char*Name;
3
// Untermenues
4
structMenu*Menus[12];
5
structMenu*ParentMenu;
6
// Anzahl von Untermenues
7
uint8_tMenuCount;
8
// Index des Cursors in den Untermenues
9
uint8_tCursorIndex;
10
Functionfunction;
11
uint16_tdata;
12
}Menu;
Initialisieren tue ich es so (auszugsweise):
1
structMenuMainMenu;
2
MainMenu.Name="MainMenu";
3
MainMenu.data=0x0000;
4
MainMenu.MenuCount=3;
5
MainMenu.function=MAIN;
6
7
structMenuMAIN_;
8
MAIN_.Name="MAIN:";
9
MAIN_.data=0x0000;
10
MAIN_.MenuCount=0;
11
MAIN_.function=Text_Display;
12
13
structMenuControls;
14
Controls.Name="Controls";
15
Controls.data=0x0000;
16
Controls.MenuCount=7;
17
Controls.function=Normal;
18
19
structMenuSetup;
20
Setup.Name="Setup";
21
Setup.data=0x0000;
22
Setup.MenuCount=4;
23
Setup.function=Normal;
24
25
26
MainMenu.Menus[0]=&MAIN_;
27
MainMenu.Menus[1]=&Controls;
28
MainMenu.Menus[2]=&Setup;
Irgendwie scheint er aber mit seinem Speicher nicht klar zu kommen.
Will ich mir z.B. den Name von Setup ausgeben lassen, kommt manchmal
"Setup", manchmal "Setup/&%§$(%" und manchmal nur Müll.
Sollte ich die structs vielleicht static deklarieren?
Ich hatte auch schon probiert, ein \0 am Ende des Strings einzufügen
(was er ja eigentlich selber macht) aber das hat auch nur kurz
funktioniert.
Am Anfang lief auch alles reibungslos. Nur als das Menü immer größer
wurde, fingen die Probleme an. Deshalb denke ich an ein Speicherproblem.
Mit static, const und volatile habe ich schon rumprobiert und auch schon
alles Mögliche gelesen.
Aber ich komme einfach nicht weiter.
Hilfe ! :)
Kann es vielleicht sein, dass der Speicher wirklich voll ist? Dann nach
ordentlich was auf dem Stack und man trifft sich in der Mitte. Würde auf
die Problembeschreibung zutreffen. Schau doch mal nach der
Speicherbelegung und rechne mal nach, wieviel Platz dann noch für den
Stack bleibt. Als Abhilfe könntest du versuche, die ganzen Strings in
den Flash zu packen.
Ja, das würde auf jeden Fall zutreffen.
Wenn ich nämlich noch eine Zeile Code einfüge, egal was sie macht, dann
tritt ein anderer Fehler auf.
Also kommen sich da irgendwie die Speicherbereiche in die Quere.
Wie kann ich berechnen, wie viel Platz der Stack braucht?
Wie packe ich die Strings am Besten in den Flash? Habe im Tutorial etwas
gelesen, das erscheint mir aber recht umständlich.
Soll ich vielleicht gleich alle Menüs im Flash speichern?
Wie mache ich das und wie greife ich später drauf zu?
Ich hatte noch einen sehr merkwürdigen Fehler.
Ich habe vor main eine Variable deklariert.
static volatile uint8_t test = 0;
In main habe ich mir die Variable dann ausgeben lassen und sie hatte auf
einmal 136 gespeichert. Es wird von nirgendwo anders auf die Variable
zugegriffen.
Könnte also auch von dem Speicherproblem kommen (nein, muss
eigentlich...).
Warum warnt avr-gcc eigentlich nicht, wenn es ein Speicherproblem geben
könnte? Er müsste das doch berechnen können?
Hier mal die Speicherbelegung, die avr-gcc meldet:
Naja der Speicher ist ja in zwei große Teile geteilt: am Anfang befinden
sich die statischen Daten (und der Heap, wenn du einen hast, was ich
aber jetzt mal nicht vermute) und vom Ende beginnend wächst der Stack
zum Anfang des RAMs. Die statischen Daten lassen sich berechnen - klar,
die stehen ja zum Compilierzeitpunkt fest. Der Stack ist ja aber
abhängig von der Programmausführung, wenn du also viele Funktionen
womöglich noch rekursiv aufrufst, wird der Stack schnell in den
Datenbereich wachsen, wodurch es dann zu genau diesen Fehlern kommen
kann. Wenn du aber nur z.B. eine Main-Funktion mit z.B. nur wenigen
lokalen Variablen hast, wird der Stack nie wachsen. Deshalb kann man die
Stackgröße nicht (wirklich) berechnen.
Ok, wie du dein Problem lösen kannst...naja, also die Möglichkeit, die
Menüs und alle Strings komplett in den Flash auszulagern würde ich auf
jeden Fall nutzen, da der Rest Speicherverschwendung ist (es sei denn,
du änderst an den Menüs zur Laufzeit was). Um das auszulagern muss man
die Strukturen nur mit einem Attribut versehen und man muss sie im
Programm über andere Befehle ansprechen (siehe AVR-GCC-Tutorial). Und
dann kannst du halt mal sehen, ob du viele Funktionen rekursiv aufrufst,
oder oft große Parameter übergibst. Die Menu-Struktur solltest du
beispielsweise nie komplett einer anderen Funktion als Argument
übergeben, sondern immer (wenn möglich) einen Zeiger darauf, da die
Menu-Struktur schon recht groß ist und diese immer, wenn du sie als
Argument an eine neue Funktion übergibst, neu im Stack kopiert wird. Die
Alternative zu Zeigern wäre hier, diese Argumente als "const" zu
übergeben, aber dazu siehe C-Tutorials im Netz.
Grüße
Randy
Ok,
Dann werde ich als erstes mal das Menü in den Flash verbannen.
Allerdings habe ich noch ein Verständnisproblem.
Also das Programm vom Atmel ist im Flash. Damit die Variablen und das
Menü doch auch? Wo kommt das Menü denn dann hin, wenn ich es für den
Flash markiere?
Was passiert dann, wenn ich einen Menüeintrag aus dem Programm aufrufe.
Dann wird er doch auch wieder auf den Stack oder in den RAM geladen?
Wann wird er dort wieder entladen?
Im Moment habe ich so viele Fragen, dass ich garnicht weiss, wo
anzufangen ;)
Tutorials habe ich schon ein paar gelesen. Die werde ich mit meinem
neuen Wissen jetzt nochmal querlesen.
Danke für Eure Hilfe bisher!
> Also das Programm vom Atmel ist im Flash.
Ja...
> Damit die Variablen und das> Menü doch auch?
Nööö...
AVRs haben Harvard-Architektur, da liegen Programm und Daten in
verschiedenen Speichern mit verschiedenen Adressräumen.
Programm liegt im Flash (ROM) und kann nur vom Programmer (oder
Bootloader) verändert werden.
Variablen (auch Arrays) liegen im SRAM (oder notfalls in Registern) und
können zur Laufzeit verändert werden.
Konstanten sind meist Bestandteil des Programmcodes und liegen daher
erstmal im Flash. Meist werden sie aber Variablen zugewiesen, damit
liegt auch eine Kopie davon im SRAM.
Konstanten-Arrays lassen sich auch (als reine Datenbereiche) im Flash
ablegen, sie lassen sich aber zur Laufzeit nicht mehr verändern, sind
halt konstant.
In ASM könnte ich Dir auch erklären, wie man das macht (.db und LPM),
von C habe ich allerdings keine Ahnung (ist mir zu kryptisch), da muss
es irgendwie "um die Ecke" gemacht werden (Stichwort "Progmem"), denn
normales ANSI-C sieht das erstmal nicht vor, das ist für
v.Neumann-Architektur entworfen worden.
...
> Also das Programm vom Atmel ist im Flash. Damit die Variablen und das> Menü doch auch? Wo kommt das Menü denn dann hin, wenn ich es für den> Flash markiere?
Genau, alles liegt auch jetzt im Flash. Wie Hannes Lux schon sagte haben
die AVRs aber Havard-Architektur, d.h. es gibt alle Adressen mehrmals:
Einmal beginnt der RAM bei Adresse 0, der Flash beginnt bei Adresse 0
und der EEPROM beginnt bei Adresse 0. Damit du jetzt dein Menü im Code
wie jede andere normale Variable (die ja auch im RAM liegen) nutzen
kannst, muss das komplette Menü bei jedem Einschalten des
Mikrocontrollers komplett in den RAM geladen werden (das macht der
C-Compiler vor der main() automatisch für dich). Wenn du jetzt das Menü
für den Flash markierst, belässt der Compiler das dort, es wird also
nicht beim Einschalten zusätzlich in den RAM geladen. Da es aber wie
schon gesagt die Adressen dann mehrmals gibt kannst du die als im-Flash
markierte Variable nicht wie eine normale Variable in C verwenden. Du
musst jedesmal spezielle Funktionen (definiert in pgmspace.h) verwenden,
um darauf zugreifen zu können.
> Was passiert dann, wenn ich einen Menüeintrag aus dem Programm aufrufe.> Dann wird er doch auch wieder auf den Stack oder in den RAM geladen?> Wann wird er dort wieder entladen?
Da du spezielle Befehle verwenden musst, arbeitest du direkt mit dem
Flash, das Menü wird also nie in den RAM geladen.
Ok ein Beispiel wie man das in C anstellt: Also erstmal die pgmspace.h
includen und dann die Variablen, die im Flash bleiben sollen
folgendermaßen definieren:
1
staticuint8_tMeinArray[]PROGMEM={1,2,3,4,5};
Jetzt hast du also eine neue Variable MeinArray, die sich aber auf den
Flash bezieht. So kann man sie nun lesen:
1
pgm_read_byte(MeinArray+1);// Zweites Element
MeinArray ist ein Zeiger wie jeder andere in den RAM auch, nur dass er
eben in den Flash zeigt. Deshalb kann man zu MeinArray auch einfach 1
addieren und erhält somit das zweite Element. Würdest du MeinArray ohne
pgm_read_byte() verwenden, würdest du irgendeinen Wert aus dem RAM
bekommen, der zufälligerweise an dieser Adresse steht. Eine
Fehlermeldung bekommst du da nicht - der AVR selbst weiß auch nicht,
dass MeinArray im Flash liegt.
> Wie kann ich diese Strings in den Flash bringen?
Für Strings gibt es ein Makro:
1
usb_puts_P(PSTR("Menu active")));
Das PSTR sorgt automatisch dafür, dass der String dahinter im Flash
abgelegt wird, ABER ACHTUNG: die Funktion usb_puts kannst du dann nicht
mehr wie sie jetzt ist verwenden, denn sie muss ja selbst auch die
entsprechenden Befehle verwenden, um aus dem Flash zu lesen. Deshalb
habe ich die Methode in dem Beispiel gleich in "usb_puts_P" umbenannt,
was sich glaub ich so als Standard eingebürgert hat. Also bei
Methodenname + _P beziehen sich die Zeiger auf den Flash. So könnte die
Methode aussehen:
1
voidusb_puts_P(PGM_Pstr)
2
{
3
charchr=pgm_read_byte(str);
4
5
while(chr!='\0')
6
{
7
usb_putc(chr);
8
9
chr=pgm_read_byte(++str);
10
}
11
}
Ich hoffe jetzt sind alle Klarheiten beseitigt :-)
Grüße
Randy
Ok, super, jetzt geht es richtig vorwärts bei mir :D
Ich habe meine Menu structs jetzt alle mit "static" deklariert.
Vorher sah es so aus:
1
1>AVRMemoryUsage
2
1>----------------
3
1>Device:atmega64
4
1>Program:20152bytes(30.7%Full)
5
1>(.text+.data+.bootloader)
6
1>Data:1476bytes(36.0%Full)
7
1>(.data+.bss+.noinit)
8
1>EEPROM:3bytes(0.1%Full)
9
1>(.eeprom)
Mit static dann so:
1
1>AVRMemoryUsage
2
1>----------------
3
1>Device:atmega64
4
1>Program:18600bytes(28.4%Full)
5
1>(.text+.data+.bootloader)
6
1>Data:3489bytes(85.2%Full)
7
1>(.data+.bss+.noinit)
8
1>EEPROM:3bytes(0.1%Full)
9
1>(.eeprom)
Wo sind die structs jetzt? Zugreifen darauf kann ich immer noch ganz
normal.
Wie bringe ich die structs in den Flash und wie rufe ich sie daraus
wieder auf? Wären dann die Zeiger auf die Untermenüs noch korrekt? Also
trägt der Kompiler dann dort die Flash-Adressen der Untermenüs ein?
Wenn ich sie "const" deklariere, wären sie dann im Flash? Aber dann
funktioniert meine Initialisierung nicht mehr.
Ich versuche gerade, die variablen Teile (ParentMenu und CursorIndex)
wegzuoptimieren. Dann wären die Menüs tatsächlich komplett statisch und
würden während der Laufzeit nie verändert werden.
Ich habe mal mit dem PSTR experimentiert. Wenn ich das vor eine Variable
schreibe, dann verringert sich der "Data" Bereich bei Memory Usage.
Also Data bezeichnet den RAM, richtig?
D.h. dass die Variable nun nur noch im Flash bleibt und nicht mehr in
den RAM geladen wird.
Zugreifen darauf dann so, wie Du beschrieben hast mit "pgm_read_byte"
bzw. entsprechenden Funktionen.
Es macht immer mehr "Klick" ;)
> Also Data bezeichnet den RAM, richtig?
Genau :-)
"Program" ist der Flash, der kann ruhig voll werden
"Data" sind die statischen Variablen im RAM. Alles was also nicht von
Data belegt wird hast du im RAM für die dynamischen Daten (Stack...)
noch frei
"EEPROM" bezeichnet, wer hätte das gedacht, den EEPROM
> Es macht immer mehr "Klick" ;)
:-)
Ok, dann war meine static Sache oben kontraproduktiv, weil er nun alles
ins RAM gelegt hat.
Mit PROGMEM ändert sich garnichts. Das AVR-GCC Tutorial hört leider
genau an der Stelle auf..
Kannst Du mir die Fragen von oben noch beantworten?
---
Wie bringe ich die structs in den Flash und wie rufe ich sie daraus
wieder auf? Wären dann die Zeiger auf die Untermenüs noch korrekt? Also
trägt der Kompiler dann dort die Flash-Adressen der Untermenüs ein?
Funktionieren die Zuweisungen überhaupt oder muss ich die Menus mit
einer Mega-Codezeile erstellen?
Wenn ich sie "const" deklariere, wären sie dann im Flash? Aber dann
funktioniert meine Initialisierung nicht mehr.
Ich versuche gerade, die variablen Teile (ParentMenu und CursorIndex)
wegzuoptimieren. Dann wären die Menüs tatsächlich komplett statisch und
würden während der Laufzeit nie verändert werden.
---
Soweit schon mal vielen Dank :)
Wenn ich es richtig verstanden habe, ist ein Struct doch eine
benutzerdefinierte Variable, also eine Zusammenfassung mehrerer
Variablen.
Ein Menü besteht nun aber aus einem Array von fixen Menütexten
(Konstanten, gehören ins Flash), einem Array mit den Adressen der
Routinen für den indirekten Sprung (IJMP) über Z-Pointer (Konstanten,
gehören ins Flash) und einigen Variablen wie z.B. aktueller Menüpunkt,
Parameterlisten zu jedem Menüpunkt (Variablen (Veränderliche!) gehören
nunmal ins RAM).
Du musst nun darauf achten, dass Du Konstanten und Variablen sauber
trennst, damit Du die Konstanten im Flash lassen kannst, die Variablen
aber ins RAM kommen. Überprüfe also, ob Dein Struct da nicht Konstanten
und Variablen zusammenfasst, denn dann wird es mit der Trennung Flash /
RAM wohl nicht so einfach (wenn überhaupt möglich).
Sorry, ich sehe das aus ASM-Sicht, der AVR aber auch, er kann kein C, er
kann nur Maschinencode, eine andere Schreibweise von ASM.
C wurde für ursprünglich 16-bittige Computer nach v.Neumann-Architektur
entwickelt, um damit die Eigenheiten der 8-Bitter und der
Harvard-Architektur zu berücksichtigen, muss man neben dem eigentlichen
C auch noch die ganzen Tricks beherrschen, mit denen man die Grenzen des
ANSI-C aushebelt um den AVR effizient zu programmieren bzw. dessen
(relativ knappen) Ressourcen nicht unnötig zu verschwenden.
Für alle, die mir jetzt widersprechen möchten, nein, ich verteufele C
nicht, aber meine AVR-Projekte sind so klein, dass ich auch mit ASM
zurecht komme, da muss ich nicht auch noch C mit all seinen Tücken
lernen.
...
Flo wrote:
> Ok, dann war meine static Sache oben kontraproduktiv, weil er nun alles> ins RAM gelegt hat.
Nein nein, das siehst du falsch :-) Die Daten liegen nach wie vor im
RAM. ALLERDINGS listet dieses kleine Tool, dass die AVR Device Memory
usage anzeigt, nur die Daten auf, die entweder global oder statisch
sind. Sprich: Der Speicher wurde auch vorher belegt, nur nicht in der
Statistik angezeigt. Die Daten wurden alle auf dem Stack erzeugt.
Und nein, dieses kleine Tool kann leider nicht die Stackbelegung zur
Compile-Zeit berechnen. Das geht nicht, da man ja beispielsweise auch
rekursive Funktionen schreiben kann (dessen Stack-Usage man nicht vorher
voraussagen kann).
Das ist der ganze Budenzauber ;)
Hannes Lux wrote:
> Du musst nun darauf achten, dass Du Konstanten und Variablen sauber> trennst, damit Du die Konstanten im Flash lassen kannst, die Variablen> aber ins RAM kommen. Überprüfe also, ob Dein Struct da nicht Konstanten> und Variablen zusammenfasst, denn dann wird es mit der Trennung Flash /> RAM wohl nicht so einfach (wenn überhaupt möglich).
Hannes hat das Problem schon geblickt :-) Ich hab mir da letztens mal
Gedanken drum gemacht: Vom Prinzip her muss man es so realisieren, dass
die Konstanten Daten des Menüs in einen Struct-Datentyp kommen, und die
veränderbaren Daten (aktuelle Menüposition etc...) in einen anderen
Datentyp kommen.
Zu jedem Menüpunkt legt man jetzt jeweils eines der beiden Structs an.
Das Struct mit den konstanten Daten landet im Flash, das andere im RAM.
Anschließend fügt man noch einen Verweis vom konstanten Struct auf das
Struct, was im RAM liegt hinzu (per Pointer zB) und fertig isset.
Ok, das ist einleuchtend.
Aber wie deklariere ich jetzt ein struct, dass in den Flash soll??
Ich habe schon viel gesucht und einiges mit Progmem und const probiert,
aber ohne Erfolg.
Vielen Dank an euch für die ausführlichen Erklärungen!
Ich hatte bisher auch eher kleine Programme. Zumindest keine, die soviel
RAM verwenden und daher keine Probleme. Sparsam mit Ressourcen gehe ich
schon um.
Allerdings wusste ich hier nicht weiter ;)
Mit euren Erklärungen habe ich es schon geschafft, die RAM Belegung um
die Hälfte zu reduzieren, ohne das Menü anzufassen. Das Programm scheint
jetzt auch stabil zu laufen.
Wenn ich noch das Menü in den Flash kriege, bin ich bei ca. 8% RAM
Nutzung.
>Zu jedem Menüpunkt legt man jetzt jeweils eines der beiden Structs an.>Das Struct mit den konstanten Daten landet im Flash, das andere im RAM.
Das kann man sich sparen wenn man das Konzept des Menusystemes
entsprechend anpasst.
Bei meinem System gibt es im Grunde nur die Strukturen der Menusysteme
die alle im FLASH liegen.
Nun gibt es einen globalen Menuhandler, das ist eine Funktion wie
nachfolgende
1
// main processing function of menu system
2
externuint8_tmenuProcess(constmenuDef_t*menu);
der man zb. das Hauptmenu oben, mmMain, als Parameter übergibt. Diese
Funktion arbeitet eine Schleife ab solange bis das Menu mit dem Kommando
MM_EXIT verlassen wird.
Dabei ruft menuProcess() periodisch die externe Funktion menuGetEvent()
auf, die natürlich im Hauptsource vom Programmierer zu implementieren
ist. Innerhalb dieser "innersten" Funktion kann man auch dann denjenigen
Code unterbringen der normalerweise in deiner main()-Schleife enthalten
ist.
In menuProcess() werden also alle Zustandsvariablen für das aktuelle
Menu in lokalen Variablen gehalten, also zb. der Index auf das aktuell
selektierte MenuItem dieses Menus.
Wird nun ein Submenu in menuProcess() ausgewählt so wird menuProcess()
rekursiv mit diesem ausgewählten Menu aufgerufen. So entsteht im Stack
eine rekursive "Datenstruktur" die die Reihenfolge der Menuebenen die
man immer tiefer werdend aufgerufen hat.
Irgendwelche globalem SRAM Variablen sind also garnicht nötig und der
SRAM Verbrauch ist dynamisch und richtet sich nach der Aufruftiefe des
aktuell ausgewählten Menus.
Gruß Hagen
Hier mal die Supportfunktionen die der Programmierer in seinem
Mainsource implementieren muß.
1
// Menu Event Handling
2
uint8_tmenuGetEvent(void){
3
4
while(1){
5
wdt_reset();
6
if(timer_event>=5){//50ms
7
timer_event-=5;
8
returnMM_TIMER;
9
}
10
if(rotary_switch&0x02){
11
rotary_switch=0;
12
returnMM_SELECTLONG;
13
}
14
if(rotary_switch){
15
rotary_switch=0;
16
returnMM_SELECT;
17
}
18
if(rotary_delta){
19
returnMM_STEP;
20
}
21
sleep_mode();
22
}
23
}
24
25
int8_tmenuGetStep(void){
26
27
returnrotary_get();
28
}
29
30
voidmenuEventFlush(void){
31
32
rotary_get();
33
rotary_switch=0;
34
}
Man sieht das menuGetEvent() als innerste Funktion die durch
menuProcess() aufgerufen wird quasi Timerintervalbasiert zurückkehrt,
oder bei einem Event wie dem Rotary Encoder, Tastatur etc.pp. sofort
nach menuProcess() zurückkehrt. Sollte aber genügend Rechenzeit
vorhanden sein so könnte man statt des Sleep() Aufrufes auch noch andere
Arbeiten erledigen lassen. Also alles was man sonst in Main() gemacht
hat.
Die Main() sieht dann so aus
Sie ist zuständig dafür das das aktuelle Menu gezeichnet wird, es wertet
die Events von menuGetEvent() aus, also zb. Rotaryencoder, Tastatur,
Timer, verwaltet das selektierte Menuitem, zeichnet dieses entsprechend
selktiv neu, führt die Aktionen zum MenuItem aus, zb. rekursiver Aufruf
eines Submenus oder Anwendungsspezifisch Menu Callback usw.
Der rekursive Stackverbrauch beläuft sich auf 1 Byte "selected" und 2
Bytes Returnaddresse beim rekursiven Aufrauf eines Untermenus.
Wenn man zb. 3 Menuebenen tief ist so hat man 7 Bytes SRAM dafür
verbraucht.
Gruß Hagen
Mal ein Bild wie das dann aussieht. Das ist das "Einstellungsmenu".
Dessen Menuitems können mehr als 5 sein, sollte dies der Fall sein so
kann man das Menu automatisch scrollen lassen. Wie man sieht gibt es
grundsätzlich drei Arten von Menuitems
1.) Items die eine Standardaktion auslösen wenn man sie selektiert, wie
zb. "<< Exit". Dieses Menuitem beendet quasi die menuProcess() Schlewife
und kehrt zum Aufrufer zurück. Das ist in diesem Fall selber
menuProcess() das das Hauptmenu verwaltet.
2.) Items die Untermenus aufrufen. Wählt man diese aus so wird rekursiv
menuProcess() mit dem Menu das diesem Item zugeordnet ist aufgerufen.
3.) Items die verschiednene Parameter darstellen und editieren können.
Im Displymodus werden diese Paramater nur dargestellt, zb. "Minuten bis
Standby" zeigt rechts eine 5 an. Oder man ist im Editmodus, natürlich
nur das selektierte Menuitem, hier "MIDI Port". Den Editor erkennt man
an der roten Umrandung. In diesem Editmodus wählt man per Rotaryencoder
aus einer Liste von Strings den Wert der Schnittstelle aus, hier
"RS232", "MIDI", "BEIDE".
Somit kann ein Menu und dessen Menuitems nicht nur das Menu anzeigen
sondern zeigt auch noch die eingestellten Parameter an und kann diese im
Menu selber auch noch editieren. Diese Anzeige/Editierung der
individuellen Parameter wird per Menu/Menuitem-Callback Funktionen
ermöglicht. Oben der Aufruf in menuProcess()
Ich habe mir mal die besten Ideen abgeguckt und mein Menü optimiert.
"Name" und "Data" lade ich komplett aus dem Flash, der Rest bleibt noch
im RAM.
Bei gleichem Funktionsumfang komme ich jetzt auf folgende
Speicherbelegung:
1
1>AVRMemoryUsage
2
1>----------------
3
1>Device:atmega64
4
1>Program:19336bytes(29.5%Full)
5
1>(.text+.data+.bootloader)
6
1>Data:499bytes(12.2%Full)
7
1>(.data+.bss+.noinit)
8
1>EEPROM:3bytes(0.1%Full)
9
1>(.eeprom)
Das Programm läuft bis jetzt fehlerfrei. Es sollte nun auch genug
Speicher haben.
Also nochmal vielen Dank an alle, die mir hier so tatkräftig, schnell
und umfangreich geholfen haben!!
Verstehe ich das richtig, du willst mit verschachtelten Strukturen (die
sogar Arrays variabler Länge enthalten) rumhantieren, aber die
unterschiedlichen Variablen-Klassen sind dir nicht so recht klar?
Was ist nur aus der guten alten Vorgehensweise geworden, sich erstmal
mit einfachen Beispielen die Grundlagen anzueignen?
Joup, verstehst du ganz richtig...
Die Klassen sind mir schon klar, nur welche der vielen soll ich denn als
Static anlegen?
Bei dem Kollegen, muss der Code ja wohl funktioniert haben...