Hallo! Ich möchte mit meinem Atmel 4433er ein Menü am LCD erzeugen. Das funktioniert auch alles einwandfrei. Mein Problem ist, dass mein RAM durch die Menütexte voll ist. In Eurem C-Tutorial hab ich gelesen, dass man diese Texte im Flash ablegen kann. Gesagt getan mit solchen Zeilen: const char Optionen[] PROGMEM = " Optionen"; So, das funktioniert alles einwandfrei laut Compiler. Wenn ich die Texte jetzt aber mit LCD_Out (Optionen); ausgeben will, bekomme ich folgende Warnung: main.c:444: warning: passing arg 1 of `LCD_Out' discards qualifiers from pointer target type Funktioniert die direkte Ausgabe eines Strings vom Flash ans LCD anders als so? Vielen Dank jetzt schon mal Wolfgang
Wolfgang K. wrote: > const char Optionen[] PROGMEM = " Optionen"; > > So, das funktioniert alles einwandfrei laut Compiler. > > Wenn ich die Texte jetzt aber mit > > LCD_Out (Optionen); > > ausgeben will, bekomme ich folgende Warnung: > > main.c:444: warning: passing arg 1 of `LCD_Out' discards qualifiers from > pointer target type Der Compiler teilt dir erst mal mit, dass die Funktion LCD_Out einen char Pointer annimmt und keinen const char Pointer. Da davon ausgegangen werden kann, dass LCD_Out den übergebenen String nicht verändern wird, ist das kein Problem. Allerdings wäre es in den Fall dann besser, wenn LCD_Out das auch dokumentieren würde und so definiert würde void LCD_Out( const char* Text ) { ... } > > Funktioniert die direkte Ausgabe eines Strings vom Flash ans LCD anders > als so? Ja: Die Funktion kann nicht unterscheiden, ob der Pointer den sie bekommt ins SRAM oder ins Flash zeigt. Wenn der Pointer aber ins Flash zeigt, dann muessen die Character anders gelesen werden als wie wenn der Pointer ins SRAM zeigt. Ist aber im Tutorial beschrieben. Diese Thematik hat aber nichts mit der Warnung des Compilers zu tun. Dem Compiler geht es einzig und alleine um das 'const', welches beim Aufruf auf der Strecke bleiben würde.
Ändert sich durch das Hinzufügen des const bei LCD_Out(const ...) dann etwas an der Ausgabe von normalen Text wie z.b. LCD_Out ("Hallo"); oder funktioniert das trotzdem noch ganz normal wie vorher?
Und ist es egal ob ich const char oder static char schreibe? mfg Wolfgang
Wolfgang K. wrote: > Ändert sich durch das Hinzufügen des const bei LCD_Out(const ...) dann > etwas an der Ausgabe von normalen Text wie z.b. > > LCD_Out ("Hallo"); > Nein. Ein String Literal, wie "Hallo", ist sogar per Definition eine Konstante. > oder funktioniert das trotzdem noch ganz normal wie vorher? Funktioniert wie eh und je. Du brauchst dich hier nicht um den Aufrufer kümmern. Es geht nur darum, was die Funktion mit dem übergebenen Argument macht. Verändert sie es, dann kann das kein const char* Pointer sein. Verändert sie es nicht, dann sollte es ein const char* sein um auch nach aussen zu dokumentieren, dass die Funktion den übergebenen String nicht verändern wird. Wenn eine Funktion einen String nicht verändern wird, dann kann ich ja durchaus einen veränderbaren (also einen nicht konstanten) String übergeben. Da die Funktion noch nicht mal den Versuch unternimmt den String zu verändern, wird nichts abartiges passieren. Wenn auf der anderen Seite eine Funktion versucht einen String zu verändern (also einen nicht-const Pointer übernimmt) und ich übergebe dieser Funktion einen String der eigentlich nicht verändert werden darf, dann habe ich ein Problem. Deine Funktion void LCD_Out( char* Text ); dokumentiert mit seiner Schnittstelle, dass sie versuchen wird, den String zu verändern. Das sie das in Wirklichkeit nicht tun wird (weil das Ausgeben eines Textes auf einem LCD nun mal keine Veränderung des Strings bedingt) ist ja nur mit dieser Schnittstellenbeschreibung nicht sichtbar. Schreibst du die Funktion aber so: void LCD_Out( const char* Text ); so dokumentierst du auch auf der Schnittstelle: Lieber Aufrufer, du kannst nach Belieben jeden String da hineinstecken, die Funktion wird nicht versuchen ihn zu verändern.
So, hab das jetzt mal ausprobiert, aber das LCD zeigt den Text vom Flash nicht an, sondern nur ein paar komische Zeichen. Der Text vom RAM wird aber korrekt angezeigt. Hab ich noch was vergessen?
ich habe anscheinend das problem mit der adresse, wo sie hin zeigt (ram oder flash), wie du es gesagt hast. habe jetzt ein paar varianten durchprobiert, aber es klappt nicht. kannst du mir erklären was ich genau machen muss?
Wolfgang K. wrote: > ich habe anscheinend das problem mit der adresse, wo sie hin zeigt (ram > oder flash), wie du es gesagt hast. > > habe jetzt ein paar varianten durchprobiert, aber es klappt nicht. > kannst du mir erklären was ich genau machen muss? Schau ins GCC Tutorial http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29 http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Vereinfachung_f.C3.BCr_Zeichenketten_.28Strings.29_im_Flash
Hab die Sachen ausprobiert wie den String vorher mit strcpy in RAM kopieren und dann ausgeben, aber funktioniert nicht. Ich will nur ganz simpel einen Text im Flash speichern und den Text vom Flash wieder ausgeben, da ja der RAM zu klein wäre für diese Textmengen. Ich mach anscheinend irgendwo einen Fehler... const char Optionen[] PROGMEM = "TEXT IM FLASH"; LCD_Out (Optionen); oder const char Optionen[] PROGMEM = "TEXT IM FLASH"; char temp; strcpy (temp, Optionen); // diese funktion in allen varianten mit pgm_read_byte usw. probiert LCD_Out (temp); Kannst du mir die paar Zeilen die funktionieren für mein vorhaben bitte reinschreiben? mfg
Wolfgang K. wrote: > Hab die Sachen ausprobiert wie den String vorher mit strcpy in RAM > kopieren und dann ausgeben, aber funktioniert nicht. Dan zeig endlich mal etwas Programmcode. Im speziellen: Wie hast du denn das LCD_Out programmiert? > > Kannst du mir die paar Zeilen die funktionieren für mein vorhaben bitte > reinschreiben? Im Tutorial ist doch eine funktionierende Ausgabefunktion enthalten. Und falls das noch nicht klar geworden ist: Du brauchst 2 Funktionen! Eine für Strings im SRAM Eine für Strings im Flash
Wolfgang K. wrote: > > const char Optionen[] PROGMEM = "TEXT IM FLASH"; > char temp; > > strcpy (temp, Optionen); > // diese funktion in allen varianten mit pgm_read_byte usw. probiert Weil ichs gerade sehe. Du musst auch noch über Stringverarbeitung nachlesen. Ist zwar nur ein grober Überblick, aber vielleicht hilfts. http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F Das strcpy() an dieser Stelle nicht funktionieren kann, sollte doch nun wirklich klar sein. Interessant sind daher all die Varianten die du ausprobiert hast, und die nicht funktioniert haben.
Wolfgang K. wrote: > Hab die Sachen ausprobiert wie den String vorher mit strcpy in RAM > kopieren und dann ausgeben, aber funktioniert nicht. Das kann man so machen, ist aber eine schlechte Idee. (*) Besser ist es allemal eine eigene LCD_Out_p Funktion für die Ausgabe von Strings aus dem Flash zu schreiben. Alles was du dazu tun musst: Schau dir im Tutorial die Ausgabe Funktion für die Ausgabe auf den UART an. Die übernimmst du und anstelle das einzelne Zeichen auf den UART zu schicken, gibst du das einzelne Zeichen an das LCD aus. Du hast doch eine Einzelzeichen Ausgabe Funktion für das LCD? (*) Das Problem dabei ist, dass du nicht vorhersehen kannst wieviel Speicher du im RAM reservieren musst um den String vom Flash in den RAM umzukopieren. Die direkte Ausgabe vermeidet dieses Problem, indem es einfach nur Zeichen für Zeichen des Strings aus dem Flash holt und jedes Zeichen gleich an die LCD ausgibt. Dadurch muss der String nicht komplett im RAM zwischengespeichert werden.
Meine LCD_Out-Funktion sieht so aus, die hab ich von diesem Forum und funktioniert auch einwandfrei bei normaler Ausgabe: void LCD_Out (const char *s) { while (*s) { LCD_Data(*s); s++; } } Und die wäre die neue für Text aus Flash lt. der Ausgabe bei dem Beispiel: LCD_Out_p (const char *text) { char zeichen; while (zeichen = pgm_read_byte(text)) { LCD_Out(zeichen); text++; } } Würde dann LCD_Out_p(Optionen) funktionieren?
Wolfgang K. wrote: > Und die wäre die neue für Text aus Flash lt. der Ausgabe bei dem > Beispiel: > > LCD_Out_p (const char *text) > { > char zeichen; > > while (zeichen = pgm_read_byte(text)) > { > LCD_Out(zeichen); > text++; > } > } Sieht doch schon gut aus :-) Noch ein void vor die Funktionsdefinition void LCD_Out_p( const char *text) { ... und wenn du dann noch innerhalb der Funktion LCD_Data() mit dem Zeichen aufrufst und nicht LCD_Out(), dann bist du auch schon fertig. > > Würde dann LCD_Out_p(Optionen) funktionieren? Na, aber sicher doch!
Hab das void nicht mitmarkiert... ;-) Funktioniert!!!! Vielen Dank! Hab nur noch eine Frage: Beim Compilieren kommt jetzt diese Meldung: main.c:408: warning: suggest parentheses around assignment used as truth value und zeigt auf diese Zeile -> while (zeichen = pgm_read_byte(text)) { ... }
aja, und diese meldung kommt nur beim ersten mal compilieren von verändertem code, d.h. beim danach gleich nochmal compilieren ist sie weg.
Der Vergleichsoperator in C heißt "==" und nicht "=". "=" macht eine Zuweisung!
das stimmt, aber das soll es hier ja auch machen denke ich. dem char zeichen die zeichen von text zuweisen, ist dann ja wie while(zeichen) { ... } also so lange etwas is zeichen ist, so auf die art.
Wolfgang K. wrote: > main.c:408: warning: suggest parentheses around assignment used as truth > value > > und zeigt auf diese Zeile > > -> while (zeichen = pgm_read_byte(text)) > { > ... > } Weil die Zeile eigentlich so aussehen sollte: while( ( zeichen = pgm_read_byte(text) ) != '\0' ) Der Programmierer hat sich aber den Vergleich mit '\0' gespart, da der sowieso automatisch gemacht wird. Der 'Trick' besteht darin, dass hier gleichzeitig das Ergebnis von pgm_read_byte an zeichen zugewiesen wird und das so zugewiesene Zeichen mit '\0' verglichen wird. Den Vergleich muss man nicht explizit schreiben. Allerdings ist es eine beliebte Fehlerquelle bei einem anderen Vergleich, sagen wir mal while( i == 5 ) einen Tippfehler zu machen und stattdessen eine Zuweisung anstelle eines Vergleiches zu machen while( i = 5 ) Viele Compiler warnen an dieser Stelle mit der, oft nicht unbegründeten, Vermutung, dass es sich dabei um einen Tippfehler handelt. Allerdings kommt es manchmal vor, dass man tatsächlich Zuweisung meint und auch Zuweisung schreibt. Und um dem Compiler mitzuteilen, dass man die Zuweisung auch ernst meint, hat sich eingebürgert da noch mal ein ( ) - Paar rundherum zu setzen while( (i = 5) ) // das ist in dem Fall natuerlich eine // sinnlose Zuweisung. Es geht nur ums // Prinzip so wie man das auch machen muesste, wenn man dann noch einen Vergleich auf ungleich 0 anhaengen wuerde while( (i = 5) != 0 ) Ersetze i mit 'Zeichen' und die 5 mit dem Funktionsaufruf von pgm_readByte und du bist genau auf deiner Form.
Ahhh, hab das jetzt umgeschrieben, da mich die Warnung rein optisch gestört hat. Danke für deine ganze Hilfe nochmal! mfg PS: Weisst du rein zufällig, auf die schnelle, zu wieviel man den RAM und FLASH beim kompilieren anfüllen darf, um nicht in das Risiko des Überschreibens zu geraten? (z.b. 90%) Hatte das schon beim RAM wegen den Strings und dann spielt ja alles verrückt.
Wolfgang K. wrote: > PS: Weisst du rein zufällig, auf die schnelle, zu wieviel man den RAM > und FLASH beim kompilieren anfüllen darf, um nicht in das Risiko des > Überschreibens zu geraten? (z.b. 90%) > Hatte das schon beim RAM wegen den Strings und dann spielt ja alles > verrückt. Flash ist kein Thema. Das kannst du bis zum letzten Byte mit deinem Code füllen. Beim RAM kann man das nicht so pauschal sagen. Während der Laufzeit wird ja auch RAM verbraucht. Irgendwo muss ja der Prozessor die Rücksprungadressen bei einem Funktionsaufruf auch speichern. Und funktionslokale Variablen wollen auch erzeugt werden etc, etc. Kurz und gut: Wieviel Speicher dies alles verschlingt, hängt unter anderem auch vom exakten Programmablauf ab und vom Programm selber ab. Sorry. Ich kann dir da jetzt keine Zahl nennen. Es ist ein leichtes ein Programm zu schreiben, das selbst bei einer angezeigten Auslastung von 0% nicht mit dem SRAM auskommen wird und es ist auch nicht weiter schwer ein Programm zu schreiben, welches bei einer 98% Auslastung ohne Probleme klarkommt. Aber das sind konstruierte Beispiele und haben mit der Realität nicht viel zu tun. Irgendwo zwischen diesen beiden Zahlen wird sich bei deinem speziellen Programm die magische Grenze bewegen. Beim nächsten Programm wird es wieder so eine Grenze geben aber die liegt dann an einer ganz anderen %-Marke.
Upps, hatte nicht gesehen, dass die Zuweisung an der Stelle gewollt ist. Aber der gute Karl Heinz hat ja mal wieder Licht ins Dunkel gebracht...
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.