Moin zusammen, ich hänge seit einiger Zeit mit folgendem Problem an meiner Programmierung eines ATMEGA8 mit AVR-Studio 5 fest und komme einfach nicht weiter. Bevor entsprechende Kommentare aufkommen: Ja, ich habe das Forum vorher durchsucht und ja, ich habe auch ein C-Buch gelesen. Manchmal sitzt man aber einfach stundenlang vor einem Problem und findet den entscheidenden Bug nicht. Vielleicht ist es hier auch so: Mein Programm soll ein GSM-Modul über den UART initialisieren und - wenn die Befehle einwandfrei ausgeführt wurden - ein OK zurückerhalten. Die folgende Routine läuft mit Codeblocks aus dem PC einwandfrei, auf dem AVR funktioniert dagegen der Teil mit der Füllung des Array mit 0x41 (nur zum testen, später laufen hier die empfangenen Bytes vom UART rein) nicht. Für die Ausgabe auf dem AVR nutze ich natürlich nicht printf, sondern eine Ausgaberoutine für ein LCD, die jedoch schon funktioniert (lcd_out(char *s)). Ich bekomme derzeit auf dem LCD den ursprünglichen Text "Hallo Welt" ausgegeben, nicht aber die A's (0x41), die die Schleife ins Array schreibt, d. h. das Array wird in der Funktion nicht geändert. Hat jemand eine Idee, woran's liegen könnte? Danke Euch schon vorab! #include <stdio.h> #include <stdlib.h> #include <string.h> void read_uart(char *str) { unsigned int i=0; unsigned int c=0x41; for (i=0;i<15; i++) //Hier steht später eine Abfrage á la while(solange empfang mache weiter) { str[i] = (unsigned char)c; //Hier füllt später die uart_getc von Peter Fleury das Array } } void gsm_init(char *abuffer) { //Hier laufen einige Initialisierungsbefehle für das GSM-Modul ab, die Bestätigung kommt vom Modul mit "OK". read_uart(abuffer); //Frage die UART-Routine ab, ob OK vom Modul eingetroffen printf("%s\n",abuffer); } int main(void) { char buffer[15]; char *pbuffer; memset (buffer, 0, 15); pbuffer = &buffer[0]; *pbuffer = "Hallo Welt"; //Schreibt etwas in Array, um zu sehen, ob die Pointer einwandfrei arbeiten gsm_init(pbuffer); //Ruft die Initialisierung auf return EXIT_SUCCESS; }
JoBo70 schrieb: > d. h. das Array wird in der Funktion nicht geändert. Bist du da sicher? > ja, ich habe auch ein C-Buch gelesen Hast du auch den Abschnitt über Strings gelesen, wo der Abschluß durch ein 0x00-Byte beschrieben ist. Am Ende deiner "a"-Füllroutine muß das noch passieren.
Eigentlich nicht, die Funktion soll ja bewusst auf das Array als Adresse zurückgreifen (Pointer) und den Inhalt über die Adresse ändern. Meines Wissens nach sollte man doch nur so wenig globale Variablen definieren wie möglich, oder?
Jesse schrieb: > Müsste str[] nicht global sein, damit die Funktion es ändern kann? Wozu gibt es Parameterübergabe "by Reference"? Nichts anderes ist der Pointer *Str. Steht auch im C-Buch.
Hallo Michael, danke für den Hinweis. Du hast recht, der Abschluss fehlt. Habe ich gerade mal mit str[i+1] = '\0'; am Ende eingefügt, aber bringt leider keine Änderung ..
JoBo70 schrieb: > am Ende eingefügt, aber bringt leider keine Änderung .. Hast du in deinem Puffer auch genügend Platz für 15 Zeichen + '\0'?
Hallo, JoBo70 schrieb: > *pbuffer = "Hallo Welt"; also, das tut schon mal nicht das, was Du denkst. String Literal in Zuweisung bedeutet Adresse des String-Literals, Typ in diesem Fall ein char[11] Pointer *pbuffer = "Hallo Welt" bedeutet also schonmal *pbuffer = Adresse der Stelle wo das H von Hallo Welt steht Links wird pbuffer vom Typ char* dereferenziert. pbuffer enthält zu diesem Zeitpunkt die Adresse der Speicherzelle buffer[0]. Dereferenziert ergibt das ein char. Diesem char weist Du einen char[11] Pointer zu, das ergibt nie und nimmer das Ergebnis, das Du erwartet hast! Der Compiler hätte auch warnen müssen. Das am Ende dennoch Hallo Welt ausgegeben wird, ist ein Zeichen dafür, dass in Deiner LCD Ausgabe irgendwo was nicht stimmt. Es kommt schon AAAAAAAAA dabei raus, wenn alles richtig läuft, weil die Hallo Welt Zeile komplett wirkungslos ist. Also: Der Fehler muss in der Ausgabe liegen! Vlg Timm
JoBo70 schrieb: > *pbuffer = "Hallo Welt"; Mööööp! pbuffer ist ein Zeiger auf char und wird mit pbuffer = &buffer[0]; initialisiert. *pbuffer bedeutet also das erste Element des Arrays. Diesem ersten Element weist Du nun die Adresse eines Strings ("Hallo Welt") zu. Das macht nichts kaputt oder so, aber führt bestimmt nicht dazu, dass das Array mit der Bytefolge "Hallo Welt" gefüllt wird. Schau mal nach strcpy oder memcpy.
Hallo T.Reinisch, danke für die ausführliche Erklärung. Meine LCD-Ausgabe sieht wie folgt aus: void lcd_out(char *s) { while (*s) //so lange Zeichen ausgeben wie *s != '\0', also ungleich dem "String-Endezeichen" { lcd_write(*s, 1); //Zeichen ausgeben s++; } } WEnn ich die Routine per lcd_out("Hallo Welt") direkt anspreche, funktioniert sie einwandfrei. Wo kann in der kleinen Routine der Fehler denn stecken?
Hallo, ich habs nur mal zusammengefasst und in main ein wenig aufgeräumt, das ist also jetzt der Stand: was liefert das nun bei dir? vlg Timm #include <stdio.h> #include <stdlib.h> #include <string.h> void lcd_out(char *s) { while (*s) { // lcd_write(*s, 1); printf("%c",*s); // bzw eben lcd_write s++; } } void read_uart(char *str) { unsigned int i=0; unsigned int c=0x41; for (i=0;i<14; i++) { str[i] = (unsigned char)c; } str[14] = '\0'; } void gsm_init(char *abuffer) { read_uart(abuffer); lcd_out(abuffer); } int main(void) { char buffer[15]; memset (buffer, 0, 15); strcpy(buffer,"Hallo Welt!\0"); gsm_init(buffer); return EXIT_SUCCESS; }
Hallo T.Reinisch, danke für den Vorschlag. Auf dem PC läuft's einwandfrei - er gibt 14 A's aus. Auf dem ATMEGA läuft's jetzt auch: Ich hatte zuvor auf dem ATMEGA in der Routine gsm_init den Aufruf lcd_out(*abuffer) verwendet, könnte das der entscheidende Fehler gewesen sein? Mit lcd_out(abuffer) läuft's jetzt. Ich habe bei der Gelegenheit noch ein wenig "rumgespielt" und wenn ich statt strcpy (buffer, "Hallo Welt!\0"); das hier einsetze buffer[0] = "Hallo Welt\n"; funktioniert's auch. Ist beides eventuell gleichwertig?
Hallo, prima, dass es jetzt funktioniert. Ja das könnte der entscheidende Fehler sein. Das Problem mit den Pointern ist einfach, dass nicht garantiert ist, dass das Programm nicht funktioniert, wenn man etwas falsch macht. Es funktioniert dann halt nur manchmal oder tut sehr seltsame Dinge. Gefühlt glaube ich, dass je kleiner der Adressraum ist, die Wahrscheinlichkeit um so größer ist, dass bei Pointerfehlern noch irgendetwas halbwegs sinnvolles passiert. Aber was ist das für ein Kompilier, dass der diesen Aufruf ohne Warnung schluckt? Ich kenne WinAVR nicht, aber irgendwo muss man ihm sagen können "-Wall" das ist wichtig. Oder gibt der Warnungen aus und du ignorierst sie nur? Das solltest Du nicht tun! Wenn Du gecheckt hast, wo Du -Wall eintragen musst, kannst Du gleich noch -Werror setzen. Für den Anfang sicherlich eine prima Sache! JoBo70 schrieb: > Ich habe bei der Gelegenheit noch ein wenig "rumgespielt" und wenn ich > statt > > strcpy (buffer, "Hallo Welt!\0"); > > das hier einsetze > buffer[0] = "Hallo Welt\n"; > > funktioniert's auch. Ist beides eventuell gleichwertig? auch das sollte der Compiler Dir nicht durchgehen lassen. links steht ein char und rechts ein char[11]. Das ist absolut nicht gleichwertig. In C gibt es keinen Datentyp "Zeichenkette". Das das funktioniert ist kein Beleg dafür, dass es immer funktioniert, sondern dafür, dass verdeckte und seltsame Effekte bei kleinen Adressräumen alles andere als selten sind. Verwende einfach den Standard-Konformen Weg über das explizite Kopieren mit strcpy oder memcpy und Du kannst sicher sein, dass Dein Programm sich so vorhersagbar wie möglich verhält. Durch solche Geheimoperationen mit ungewissem Ausgang kannst Du ganz tolle Fehler produzieren. Plötzlich funktioniert die Ausgabe doch nicht mehr, ob wohl du nichts geändert hast, oder nur einen Programmteil, der nichts damit zu tun hat. Viele Grüße Timm
Hallo Timm & und auch alle anderen, lieben Dank für die schnelle Hilfe und die hilfreichen Erklärungen, die mir sehr geholfen haben! Beste Grüße! PS: Ich nutze AVR Studio 5.
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.