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 ..
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.