Hallo Leute. Ich habe gestern in meinem inzwischen nicht mehr ganz so kleines Programm (für einen 90CAN128) eine existierende case - Schleife um 4 Anweisungen ergänzt. Die Anweisungen in der Schleife sehen etwa alle gleich aus. case 23: strcpy((char*)&bufferstring[0],(char*)&serialstring[4]); var23 = atoi(bufferstring); write_var23(); send_string_uart0("OK\n\r"); break; Alle Variablen in dieser Funktion kommen aus dem main.c und sind dort global definiert. Am Anfang dieser Funktion befindet sich entsprechend noch die Deklaration dieser Variablen extern int var23; Danach ging in dem Programm nix mehr. Das Display flackert nur noch wild, gelegentlich gibt es einen Reset. Die Case-Anweisung wird zu diesem Zeitpunkt nicht durchlaufen. Ich tippe mal auf Stack-Überlauf, denn wenn ich die Zeilen wieder entferne geht alles wie gewohnt. Das führt uns zu folgenden Fragen: Extern deklarierte Variable verbrauchen Programmspeicher? Permanent? Wie sieht es dann mit lokalen Variablen aus? Wenn externe Variable sich am Programmspeicher bedienen, gibt es dann auch einen Weg, dies zu verhindern?
>Extern deklarierte Variable verbrauchen Programmspeicher? Ja >Permanent? Ja >Wie sieht es dann mit lokalen Variablen aus? Radio Eriwan. Die benötigen entweder Programmspeicher, solange sie existieren, oder sie werden in einem Prozessorregister gehalten (wenn sie klein genug sind, und ausreichen Register im Prozessor frei sind). >Wenn externe Variable sich am Programmspeicher bedienen, gibt es dann >auch einen Weg, dies zu verhindern? Nicht wirklich. Das Wesen einer Variablen ist nunmal, einen Speicherbereich darzustellen. Oliver
<<Nicht wirklich.>> Und wenn ich alles ins Main.c stopfe mit dem Pferdefuß einen unübersichtlichen Programmcode zu erzeugen aber dafür den Speicher zu sparen?
ich tippe auf
>strcpy((char*)&bufferstring[0],(char*)&serialstring[4]);
Überprüfe die Länge und die 0 Terminierung.
@ Wolfram Der Programmteil wird nicht ausgeführt. Es kommt schon vorher zum Fehler, ohne das strcpy((char*)&bufferstring[0],(char*)&serialstring[4]); überhaupt zur Ausführung kommt.
>Und wenn ich alles ins Main.c stopfe mit dem Pferdefuß einen >unübersichtlichen Programmcode zu erzeugen aber dafür den Speicher zu >sparen? Es gibt nur ein Programm, und nur ein Ram. Da ist alles drin. Es ist völlig egal, ob du deinen Surce-Code in eine oder in 100 Dateien schreibst, und es ist auch völlig egal, wie oft du darin eine Variable als extern derklarierst. int var23; benötigt exakt 2 byte Ram. extern int var23; benötigt gar nichts, das gibt dem Compiler nur die Möglichkeit, diese Source-Datei zu Kompilieren, mit dem Hinweis, das var23 irgendwo anders deklaiert wird. Der Linker macht dann den Rest. Wenn du allerdings gar keine Variablen hinzugefügt hast (var23 gabs schon vorher), dann darf eigentlich nichts passieren. Daher ist die von Wolfram geäusserte Vermutung, daß da igend was anderes queschiesst, gar nicht so abwegig. Jetzt ist Hardcore-Debugging angesagt. Oliver
<<int var23; benötigt exakt 2 byte Ram. extern int var23; benötigt gar nichts, >> Ich merke, ich habe mich bei der Fragestellung missverständlich ausgedrückt, entsprechnd Deine erste Antwort missverstanden. Das die Case Schleife schuld ist, kann ich mir nicht vorstellen. Immerhin stehen schon 22 identische Anweisungen davor, nur eben für var01 - var22.
Ok, da hatte ich die Frage anders verstanden. Aber trotzdem: Ein xx128 hat 4kB SRAM. Das bekommst du mit Integer-Variablen so schnell nicht voll, und auch Funktionsverschachtelung führt da so schnell nicht zu Problemen. Entweder hast du da riesige Arrays, sowas wie
1 | int LCD_BUFFER[240][128]; // :-)) |
oder Stringkonstanten im Ram, anstatt im Flash, oder so etwas. Und die Vermutung mit amoklaufenden Stringfunktionen ist auch noch nicht vom Tisch. Oliver
Nun, es ist einiges von diesem Zeug darin, send_string_uart0("OK\n\r"); aber das sollte doch im Flash stehen, oder? Und es gibt noch ein großen String für die variablen Ausgaben. char sendstring[40]; Das ist aber schon die größte und die wird ja auch nicht beeinflusstr von dem Code in der Case-Schleife Ein paar von den varXX sind floats, aber das kann es ja auch nicht sein. ...
flyingwolf wrote: > Nun, es ist einiges von diesem Zeug darin, > > send_string_uart0("OK\n\r"); > aber das sollte doch im Flash stehen, oder? Nein. Warum sollte es? Die send_string_uart0 muss ganz anders aussehen, wenn der String im Flash liegt. http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Vereinfachung_f.C3.BCr_Zeichenketten_.28Strings.29_im_Flash > > Und es gibt noch ein großen String für die variablen Ausgaben. > char sendstring[40]; > Das ist aber schon die größte und die wird ja auch nicht beeinflusstr > von dem Code in der Case-Schleife > > Ein paar von den varXX sind floats, aber das kann es ja auch nicht sein. > ... Dann könnten es auch noch sonstige Fehler im Programm sein, die sich jetzt bemerkbar machen.
> send_string_uart0("OK\n\r"); > aber das sollte doch im Flash stehen, oder? Nein. Die Strings werden im RAM gespeichert. Das geht nicht anders, weil der Prozessor auf Assembler-Ebene unterschiedliche Instruktionen für den Zugriff auf RAM und Flash braucht. Du kannst sie mit PROGMEM als globale Variablen definieren und eine zweite Sendefunktion schreiben, um das zu umgehen. Was sagt denn avr-size, wieviel RAM statisch belegt ist?
Hallo flyingwolf, schau dir doch mal diesen thread an. (und besonders die Lösung am Ende) Beitrag "Re: Speicherproblem" Gruß
Verstehe ich das richtig? bei z.B. if (irgendwas == 1) send_string_uart0("Press any key to continue"); landet der ganze Text automatisch im SRAM, auch wenn die If-Anweisung gar nicht ausgeführt wird?
Einzige Ausnahme: es ist schon zur Compilezeit bekannt, dass die Anweisung nie ausgeführt werden kann.
Umpf! Nun, dann weiss ich zumindest wo mein Speicher hin ist. Wenn ich das Tutorial jetzt richtig deute sollte ich gar nicht ganz unbedarft send_string_uart0("Press any key to continue"); schreiben, sondern die Texte in hunderten von Variablen a la char StringImFlash1[] PROGMEM = "Press any key to continue"; deklarieren und deren Ausgabe dann durch send_string_uart0(StringImFlash1); erzeugen? Gibt es noch eine bestimmte Regel an die ich mich dabei halten muss, oder genügt es in der entsprechenden Funktion die Texte als Lokale Variable zu definieren und dann in der oben angezeigten Weise auszugeben?
Mit bisschen Geschick kannst du das einfacher schreiben als:
1 | send_string_uart0_P(PSTR("Press any key to continue")); |
Der _P-Suffix ist dabei die übliche Kennzeichnung dafür, dass die Funktion einen progmem-String bekommt. Die Funktion ist dabei selbst dafür verantwortlich, die Daten aus dem Progmem zu ziehen (letztlich mittels LPM-Anweisungen). Der PSTR-Makro ist ein wenig Magie, die den String in den Progmem legt und dessen Adresse gleich zurückgibt. Der String selbst bildet dabei sowas wie eine anonyme Array-Variable.
Aber bevor wir dich noch mehr verwirren arbeite zuerst mal das Oben von Karl heinz Buchegger angeführte Tutorial durch. Dann wird dir hoffentlich vieles klarer.
Erst einaml vielen Dank. Da habe ich doch wieder viel dazugelernt. Das werden wir jetzt mal vertiefen. Zuerst in der einfachen Methode zu Fuss und dann schauen wir mal ob wir das mit der Magie hinbekommen, aber das wird wohl ein paar Tage brauchen
flyingwolf wrote: > Erst einaml vielen Dank. Da habe ich doch wieder viel dazugelernt. Das > werden wir jetzt mal vertiefen. Zuerst in der einfachen Methode zu Fuss > und dann schauen wir mal ob wir das mit der Magie hinbekommen, aber das > wird wohl ein paar Tage brauchen Das schöne ist, dass du die Magie nicht erfinden musst. Du musst nur eine klitzekleine Änderung in deiner send..... Funktion machen, vor den String ein PSTR und schon bist du fertig. Noch ein Hinweis: Lass um Gottes Willen deine jetzige send.... Funktion in Ruhe und mache eine zweite Funktion, die du laut üblicher Konvention send_string_uart0_p nennst.
<< Du musst nur eine klitzekleine Änderung in deiner send..... Funktion machen, vor den String ein PSTR und schon bist du fertig.>> Ja schon, aber woher hätte ich vorhin ahnen können, dass es so einfach ist ;-) Ich habe mich ja auch gleich noch an meiner LCD-Routine vergangen um selbigem Problem gleich mit auf den Leib zu rücken. Dabei habe ich mich dieser wunderbaren Vorlage aus dem Tutorial bedient, auch wenn es einen Moment gedauert hat, bis der Groschen fiel. Nun die Frage Natürlich hat der Compiler (und nicht ganz zu unrecht) was zu meckern an der Zeile while (charcounter = pgm_read_byte(data)) und bemerkt in seiner nüchternen Art uart.c:87: warning: suggest parentheses around assignment used as truth value Kann ich dem Compiler irgendwie sagen, das er an dieser Stelle mal ausnahmsweise nicht meckern soll?
> while (charcounter = pgm_read_byte(data)) > suggest parentheses around assignment used as truth value erfüll doch dem Compiler seinen Wunsch :-) Worum gehts denn da. Ein, besonders bei Einstegern, beliebter Fehler ist es, wenn man für einen Vergleich anstelle von == ein einfaches = schreibt. Da wird dann ein simples sscanf( "%d", &Count ); if( Count = 1 ) printf( "Sie haben 1 eingegeben" ); schnell zum Drama. Daher warnen manche Compiler vor solchen Konstrukten. Wohlwissend, dass es in C durchaus Konstruktionen gibt, bei denen man tatsächliche eine Zuweisung haben möchte. Man kann natürlich auch die Langform schreiben: while( ( charcounter = pgm_read_byte(data) ) != 0 ) { ... } und hat damit auch für den neuesten Einsteiger klar gemacht was Sache ist (oder auch nicht). Aber gcc gibt sich schon zufrieden wenn du einfach nur die Klammern machst, der explizite Vergleich muss nicht sein: while( ( charcounter = pgm_read_byte(data) ) ) { dann glaubt dir der gcc, dass du wirklich einen Zuweisung meinst.
Super. Und damit ein erneutes, ganz herzliches Danke (an alle) und eine gute Nacht. ;-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.