Datum:
Hallo, ich habe einen mega8 und mein Programm ist leider fast 8kb groß. Nun versuche ich das ganze etwas kleiner zu machen. Dazu eine Verständnisfrage. Was verbraucht weniger Speicher A
MAIN: ... PORTC |= (1 << PC5); ... PORTC |= (1 << PC5); ... PORTC |= (1 << PC5); ... PORTC |= (1 << PC5); |
B
void schaltePortC(void) { PORTC |= (1 << PC5); } ... MAIN: ... schaltePortC(); ... schaltePortC(); ... schaltePortC(); ... schaltePortC(); |
A oder B? Danke, cmf
Datum:
was hindert dich daran, andere Teile deines Programmes temporär rauszuwerfen, dann beide oben genannten Varianten einzubinden, und zu sehen was größer wird?
Datum:
Hast du die Optimierung eingeschaltet? (-os) Die kürzeste Version müsste A) sein, weil der Compiler daraus ein sbi = 1 Word machen sollte. Kürzer geht nicht.
Datum:
Christian F. schrieb: > Nun > versuche ich das ganze etwas kleiner zu machen. Dann suche erstmal die Routinen, die viel Flash belegen. Ein simples SBI kanns ja auf keinen Fall sein. Ich hoffe mal nicht, daß Du Spaghettikode schreibst mit 1000-mal SBI:
PORTC |= (1 << PC5);
|
Dann wäre nämlich Dein Programmkonzept Dein größter Feind. Peter
Datum:
In Mapfile reinsehen und die Klöpse suchen. Dort optimieren. Wenns zu aufwendig wird: Pinout/Gehäuse vom Mega8 ist bis 32KB Flash ausbaufähig.
Datum:
Christian F. schrieb: > A oder B? Ein halbwegs gut optimierender Compiler wird für beide Varianten den selben Code erzeugen. Schau dir besser mal das Listing an und versuche abzuschätzen, wo du die grössten Speicherfresser hast. Verwendest du printf? Arbeitest du mit Fliesskomma-Zahlen?
Datum:
Im Mapfile finden sich vielleicht auch ein paar Funktionen, die man eigentlich überhaupt nicht haben wollte, die aber aus einem dummen Zufall heraus doch am Hals hat (32/64bit Rechnung, Fliesskomma, ...).
Datum:
Christian F. schrieb: > Nun versuche ich das ganze etwas kleiner zu machen. Zeig doch mal deinen Code...
Datum:
Angehängte Dateien:Vielen Dank für die Antworten! Ich kann meinen Code gerne mal zeigen :) Zur Erklärung: Es handelt sich um einen Schattenbahnhofsteuerung für die Modellbahn, die aber BEI WEITEM noch nicht fertig + optimiert ist. Außerdem ist sie sehr sparsam kommentiert, USART fehlt noch und vor allem ist sie erstmal unverständlich. Trotzdem kann ich den Code gerne mal posten. In den nächsten Tagen, wenn ich den MSA hinter mir habe, werde ich mich mal dransetzen und alles kommentieren. Man beachte, dass ich da (natürlich mit Pausen) seit 1 Jahr dran sitze und die Syntax deshalb noch nicht wirklich toll ist. Edit: Ja die Variablennamen sind nicht die besten...
Beitrag #2600593 wurde vom Autor gelöscht.
Datum:
void Schattenbahnhofsteuerung(void) { int dreigleiseinfahrt = 0, einfahrtsgleis = 0, gleiswendelausfahrt = 0; int ees = 0, ehs = 0, egg = 0, egl = 0, egr = 0, egm = 0, egw = 0; int dreigleisausfahrt = 0, dreigleisausfahrt2 = 0; int *pointeraufdreigleisausfahrtsgleis = NULL; int eesold = 1, ehsold = 1, eggold = 1, eglold = 1, egrold = 1, egmold = 1, egwold = 1; int eescounter = 0, ehscounter = 0, eggcounter = 0, eglcounter = 0, egrcounter = 0, egmcounter = 0, egwcounter = 0; int signalcounter = 0; |
Wenn du mit 7 oder 8 bit auskommst nimm int8_t oder uint8_t anstatt int, das spart ca 50% flash und ram.
Datum:
Ja danke, war immer zu faul darauf zu achten. Ich probiere es gleich mal aus.
Datum:
Aus dem Bauch heraus können das aber keine 8KB sein. Bist du sicher, dass du die Optimierung eingeschaltet hast? Was mir aufgefallen ist: Du hast einige Variablen, in einer Funktion sogar haufenweise davon, die du alle als 'int' definiert hast. int hat auf deinem µC 16 Bit, d.h. du wingst deinem µC 16-Bit Aithmtik auf, die du gar nicht brauchst! Auch das ist a) Code und b) Laufzeit die du unnötig verschenkst. Als Faustregel. Verwende auf einem AVR nicht einfach nur int. Wenn du * einen kleinen Ganzzahltyp brauchst, ohne Vorzeichen, so dass du mit dem Wertebereich 0 bis 255 locker über die Runden kommst, dann nimm uint8_t als Datentyp * dasselbe, nur diesmal mit Vorzeichen, dann ist int8_t der Datentyp deiner Wahl * Wenn deine Zahlen dann doch mal größer werden, dann nimmst du int16_t (mit Vorzeichen, also signed) bzw. uint16_t (ohne Vorzeichen, also unsigned). * und wenns noch größer wird, dann eben int32_t bzw. uint32_t Alleine dadurch, dass du die 16-Bit Arithmetik erst mal auf 8 Bit zurückstutzt, und unsigned benutzt wo du nur kannst (also einen uint8_t benutzt), wird schon einiges an Code wegfallen. Edith: zu langsam
Datum:
Ja genial! Von 6,351 auf 4,698. Ich hatte das einfach unterschätzt. Jetzt passt ja die Kommunikation mit dem Computer noch locker rauf! Danke!
Datum:
Karl Heinz Buchegger schrieb: > Aus dem Bauch heraus können das aber keine 8KB sein. Bist du sicher, > dass du die Optimierung eingeschaltet hast? Optimierung ist eingeschaltet (-Os). Ok, es waren nicht ganz 8kB.
Datum:
Christian F. schrieb: > In den nächsten Tagen, wenn ich den MSA hinter mir habe, werde ich mich > mal dransetzen und alles kommentieren. Ganz ehrlich? So wie der Code aussieht: Setz dich hin, nimm alles zusammen, was du in diesem Jahr gelernt hast (auch über das Problem gelernt) und mach dir ein neues Konzept auf dem Papier. Dann schreib ein neues Programm. Wirst sehen, das dauert auch nicht viel länger als wenn du das Vorhandene umarbeitest und dafür hast du dann etwas tragfähiges für die nächste Zeit. Das dein erstes Programm nicht wirklich das Nonplusultra ist, ist schon klar. Das wäre ein Wunder, wenn es so wäre. Es braucht viel Übung, bis man auf Anhieb ein gutes Programmkonzept findet, welches auch Bestand hat. Von daher ist es nicht so schlimm, wenn man die Erstversion verwirft und mit dem Gelernten an eine neue Version geht, auch wenn es auf den ersten Blick schmerzt.
Datum:
Christian F. schrieb: > Optimierung ist eingeschaltet (-Os). Ok, es waren nicht ganz 8kB. Also bei mir sind das ohne Optimierung: Program: 6786 bytes (82.8% Full) (.text + .data + .bootloader) Data: 18 bytes (1.8% Full) (.data + .bss + .noinit) und mit -0s: Program: 2246 bytes (27.4% Full) (.text + .data + .bootloader) Data: 10 bytes (1.0% Full) (.data + .bss + .noinit) mfg.
Datum:
@ Christian F. (cmf) >ich habe einen mega8 und mein Programm ist leider fast 8kb groß. > * main.c (12,5 KB, 6 Downloads) | Codeansicht Wo sollen DAS 8kB werden? Niemals. Oder ist dein .hex File fast 8kB groß? Das wäre real eher 3kB, denn .hex ist Intel-HEX, da wird alles per ASCII +bissel Adressierung dargestellt, und ist ~2,5mal so groß wie die echten, binären Daten. >Nun versuche ich das ganze etwas kleiner zu machen. Dazu sollte man andere Konzepte nutzen, und zwar allgemein als auch bezüglich C. Siehe statemachine. Damit schrumpft der Speicherverbrauch ganz ordentlich, ausserdem muss man nicht soviel tippen. MFG Falk
Datum:
Falk Brunner schrieb: > @ Christian F. (cmf) > >>ich habe einen mega8 und mein Programm ist leider fast 8kb groß. > >> * main.c (12,5 KB, 6 Downloads) | Codeansicht > > Wo sollen DAS 8kB werden? Niemals. Oder ist dein .hex File fast 8kB > groß? Das wäre real eher 3kB, denn .hex ist Intel-HEX, da wird alles per > ASCII +bissel Adressierung dargestellt, und ist ~2,5mal so groß wie die > echten, binären Daten. Ups. Ich habe natürlich immer das HEX File angesehen. Danke! (Woher sollte man das wissen?) >>Nun versuche ich das ganze etwas kleiner zu machen. > > Dazu sollte man andere Konzepte nutzen, und zwar allgemein als auch > bezüglich C. Siehe statemachine. Damit schrumpft der > Speicherverbrauch ganz ordentlich, ausserdem muss man nicht soviel > tippen. > > MFG > Falk Habe ich mal kruz überflogen, mache ich das nicht in etwa so? Ich habe eine while Schleife, darin 3 große Programmteile (1ANFANG, 1ENDE, ...) Die haben jeweils 3 bis 4 Zustände, also wie bei der Ampel rot, gelb, grün, rot, gelb ... Den aktuellen Zustand speichere ich in einer Variable, damit er in der While Schleife nicht "verloren geht". So ist das doch auch bei der Statemachine, oder? > > P S Aha, Problem gefunden. > >
> sleep(schaltzeitWeiche); > |
> > Macht man so nicht. Siehe > > http://www.mikrocontroller.net/articles/AVR-GCC-Tu... > > Ändere es ab und staune. Ja, den Teil habe ich schon gelesen und das gehört natürlich nicht in eine Statemachine, da das ganze so nicht mehr paralel läuft. Aber ich hatte eben noch keine Lust, mich deshalb mit Interrupts (oder?) rumzuschlagen. Aber ich sehe schon, dass sollte man mal machen.
Datum:
@ Christian F. (cmf) >Ups. Ich habe natürlich immer das HEX File angesehen. Danke! (Woher >sollte man das wissen?) Grundlagen. Ausserdem zeigt dir AVR-Studio nach dem Compilieren den Speicherbedarf direkt an. >Habe ich mal kruz überflogen, mache ich das nicht in etwa so? Nur in etwa ;-) >> P S Aha, Problem gefunden. >> sleep(schaltzeitWeiche); >> Macht man so nicht. Siehe >> http://www.mikrocontroller.net/articles/AVR-GCC-Tu... Falsche Fährte. schaltzeitWeiche ist ein #define Konstante und damit unkritisch. ich dachte erst, es wäre eine echte Variable. Dennoch sind dein Dutzenden Sleeps nicht so doll. MFG Falk
Datum:
Dutzende?? Ich habe 3 Stück im richtigen Programm + 3 Stück in Debug Funktionen. AVR-Studio und Linux vertragen sich nicht so...
Datum:
Nun mal eine genauere Erkärung, wieso der Code so lang ist. Ich habe im
Hauptteil 3 Abschnitte, die praktisch alle fast das selbe tun, nämlich
Züge von Abschnitt A nach B bringen. Wieso sind sie dann so
unterschiedlich lang? Das liegt daran, weil mein Gleisplan in etwa so
aussieht:
-->--ehs------->----->--egl---\
\->--egm------->---egg--->--ees------>----
/------>--egr---/
/
Beispielhaft mal der Code von egg nach ees.
//1ANFANG /* Dieser Programmteil sorgt dafür, dass Züge vom Abschnitt egg zum Abschnitt ees fahren In egg steht 0, wenn der Abschnitt frei ist, genauso in ees, wenn ees frei ist ---->--egg---->---->-----ees----->-----> Mittels GG schalte ich den Abschnitt egg ein, mittels GGOFF aus. */ if(ees == 0) // 1: Zielabschnitt besetzt { dummy = zufall(3); //Dient dazu, den Zufall, der weiter unten benutzt wird, etwas "zufälliger" zu machen GGOFF; gleiswendelausfahrt = 0; //Nächster Schritt } if((((ees != 0) && (gleiswendelausfahrt == 0)) && (egg == 0))) // 2: Zielabschnitt freigeworden + Zug in Abschnitt egg { GG; //Lasse Zug aus egg ausfahren gleiswendelausfahrt = 1; //Nächster Schritt dummy = zufall(3); } if((egg!=0)&&(gleiswendelausfahrt==1)) GGOFF;// 3 Zug aus Abschnitt ausgefahren, deshalb Abschnitt abschalten //1ENDE |
Das ist ja gar nicht so lang. Aber es wird eben bedeutend länger, wenn die Züge von egl/egm/egr nach egg müssen. Dann muss geprüft werde, wo ein Zug steht und zufällig einer ausgewählt werden der dann losgeschickt wird. Danke nochmals!
Datum:
Christian F. schrieb: > Das ist ja gar nicht so lang. Aber es wird eben bedeutend länger, wenn > die Züge von egl/egm/egr nach egg müssen. Denk mal darüber nach, ob man das alles nicht auch durch Daten (zb in einem oder mehreren Arrays) beschreiben kann. Naiv wie ich bin, besteht doch eine Fahrstrasse immer aus diesen Komponenten: einem Anfangsgleis, einem Endgleis und Zwischenstücken. Eine Fahrstrasse kann nur dann befahren werden, wenn das Endgleis samt allen Zwischenstücken frei ist. Oder so ähnlich. Diese allgemeinen Gedanken würd ich mir erst mal machen und versuchen die in ein allgemeines Schema zu pressen, welches rein nur durch Daten beschrieben werden kann, die variabel sind und auf deine spezielle Situation im Schattenbahnhof zurechtgeschnitten sind.
Datum:
Karl Heinz Buchegger schrieb: > Christian F. schrieb: > >> Das ist ja gar nicht so lang. Aber es wird eben bedeutend länger, wenn >> die Züge von egl/egm/egr nach egg müssen. > > Denk mal darüber nach, ob man das alles nicht auch durch Daten (zb in > einem oder mehreren Arrays) beschreiben kann. > > Naiv wie ich bin, besteht doch eine Fahrstrasse immer aus diesen > Komponenten: > > einem Anfangsgleis, einem Endgleis und Zwischenstücken. > Eine Fahrstrasse kann nur dann befahren werden, wenn das Endgleis samt > allen Zwischenstücken frei ist. Oder so ähnlich. Ja, fast richtig. Nur bei mir gibt es keine Zwischenstücke, das wäre zu aufwendig. Deshalb muss ich mir in einer Variablen (im Beispiel "gleiswendelausfahrt") merken, dass sich ein Zug zwischen den beiden Abschnitten befindet. > Diese allgemeinen Gedanken würd ich mir erst mal machen und versuchen > die in ein allgemeines Schema zu pressen, welches rein nur durch Daten > beschrieben werden kann, die variabel sind und auf deine spezielle > Situation im Schattenbahnhof zurechtgeschnitten sind. Eigentlich lautet mein Schema, dass ich mir dazu überlegt habe so: // 1: Warte bis Zielabschnitt besetzt (also Zug nicht auf freier Strecke liegengeblieben ist) //Nächster Schritt // 2: Warte bis Zielabschnitt freigeworden + Zug in Startabschnitt steht //Lasse Zug aus Startabschnitt ausfahren //Nächster Schritt // 3 Wenn Zug aus Startabschnitt ausgefahren ist //Startabschnitt abschalten //Wieder von vorne Ich denke, ich werde mal versuchen, dafür eine allgemeine Funktion zu schreiben. Mein Problem dabei war, dass ich als Startgleis in einem Fall nur 1 Variable übergeben müsste (von egg -> ees) und im anderen Fall 3 Variablen (von egl/egr/egm -> egg). Mir kam nicht der Gedanke, Arrays zu verwenden. Leider kenne ich mich mit den Dingern nicht so gut aus, habe dafür aber schon so einige Erfahrung unter PHP mit Arrays. Also gut, ich werde es in den nächsten Tagen mal umbauen.
Datum:
Angehängte Dateien:Hallo, ich bin gerade dabei, das Programm zu überarbeiten. Dabei stoße ich auf folgendes Problem: Wenn ich das Folgende einkommentiere, stürzt das Programm beim Aufruf ab.
//DIESE FUNKTION BRINGT DEN µC zum ABSTURZ void uartSendStep(const int teil, const int step) { uart_puts("\n======Teil "); uart_puti(teil); uart_puts("======\n"); if (teil == 2 || teil == 3) { switch (step) { case 1: uart_puts("Zielabschnitt besetzt\n"); uart_puts(" Startabschnitt aus\n"); break; case 2: uart_puts("Zielabschnitt freigeworden und Zug in Startabschnitt\n"); uart_puts(" Startabschnitt an\n"); break; case 3: uart_puts("Startabschnitt freigeworden\n"); uart_puts(" Startabschnitt aus\n"); break; default: break; } } uart_puts("====================\n"); } |
Daten: mega8 kein externer Quarz Baud Rate: 4800 UART Bibliothek von Peter Fleury Der UART funktioniert sonst wunderbar (siehe z.B. uartSendInit())
Datum:
Nimm mal uart_puts_P() statt uart_puts().
Datum:
Danke erstmal für die Antwort. Nach einem Austausch sämtlicher uart_puts durch uart_puts_p stürzt das Programm immer noch ab, außerdem erhalte ich nur noch kryptische Zeichen.
Beitrag #2609187 wurde vom Autor gelöscht.
Datum:
Angehängte Dateien:Hä? Verstehe ich gerade nicht. Im Anhang mal der Code mit uart_puts_p. (Rekursion heißt ja, eine Funktion ruft sich immer wieder selbst auf. Wo tue ich das denn?) Edit: Jetzt ist der Beitrag weg? Wars also doch Quatsch?
Datum:
Sorry, war ein Schnellschuss, basierend auf dem Namen.
Aber was uart_puts_p angeht: Die Strings müssen zum Parameter passend in
ROM gelegt werden. PSTR("xxx") statt "xxx" könnte notwendig sein.
Manchmal gibt es Versionen _p ohne und _P mit automatischem PSTR. Doku
lesen.
Datum:
Ich probiers mal aus.
Datum:
uart_puts_p in uart_puti ist natürlich Käse, denn da gehts ja nicht um einen String im ROM, sondern um Daten im RAM.
Datum:
A. K. schrieb: > uart_puts_p in uart_puti ist natürlich Käse, denn da gehts ja nicht um > einen String im ROM, sondern um Daten im RAM. Ja ist es. Danke. So funktioniert es jetzt:
uart_puts_p(PSTR("bla"));
|
uart_puts_P gibt es nicht (Also mit automatischem PSTR). Das wollte ich mir jetzt selber schreiben. Aber wie geht das? So sieht uart_puts_p aus
void uart_puts_p(const char *progmem_s ) { register char c; while ( (c = pgm_read_byte(progmem_s++)) ) uart_putc(c); }/* uart_puts_p */ |
Beitrag #2609221 wurde vom Autor gelöscht.
Datum:
Oh. Hätte ich selber drauf kommen können... Nochmal Danke.
Datum:
Probiers mal so: #define uart_puts_P(s) uart_puts_p(PSTR(s)) (diesmal wars daneben geklickt...)
Datum:
Nochmal ne Frage: Ich habe ja eine Endlosschleife und am Ende ein _delay_ms(), siehe Statemachine.
MAIN: for(;;) { (PROGRAMM) _delay_ms(500); } |
Ist es nun schöner, besser, ordentlicher das so zu machen:
volatile uint8_t durchlauf = 0; ISR(TIMEROVERFLOW) //Alle 500ms { durchlauf = 1; } MAIN: for(;;) { if(durchlauf == 1) { durchlauf = 0; (PROGRAMM) } } |
cmf
Datum:
@Christian F. (cmf)
>Ist es nun schöner, besser, ordentlicher das so zu machen:
Ja.




