Forum: Mikrocontroller und Digitale Elektronik String in global char Array schreiben!?


von Mr Bean (Gast)


Lesenswert?

Guten Morgen,

ich habe hier ein Problem und ich komme einfach nicht auf die Lösung. 
Wahrscheinlich ist es etwas ganz einfaches, aber ich sehe es einfach 
nicht. Ich möchte einen String, den ich aus einem EEPROM hole, in ein 
globale char Array schreiben. Ich versuche das auf folgende Weise:
1
extern char devName[16];
2
3
void setName(void)
4
{
5
  char name[16];
6
  
7
  getDeviceName(name);    //Name aus EEPROM holen
8
  dbg_printf("%s\r", name);
9
  //memcpy(devName, name, 16);
10
11
  //sprintf(devName, "%s", (const char*)name);
12
  //strncpy(devName, name,3);
13
  //strcpy((char *)devName, (const char *)name);
14
  dbg_printf("%s\r", devName);
15
}

Das Problem ist jetzt, dass sich der Controller immer wenn ich versuche 
auf das globale Array zu schreiben, aufhängt. Er verweigert komplett 
seinen Dienst, nur ein Reset hilft dass noch. Architektur ist ein ARM 
Cortex M0.
Ich habe wie ihr seht schon auf mehrere Arten versucht, den String in 
"devName" zu bekommen. Bei allen Varianten das gleiche Verhalten. In 
"name" steht der richtige String und wird auch richtig ausgegeben 
(dbg_printf(...) ).
Habt ihr eine Idee, was das Problem sein könnte?

Gruß,
Bean

von Daniel V. (danvet)


Lesenswert?

Ist es sicher, dass der String NULL-terminiert ist? Sonst schreibst du 
dir sonstwas kaputt.
Warum kopierst du nicht einfach die 16Byte vom einen ins andere oder 
liest dein EEPROM-String direkt in die globale Variable?

Edit:
und das "extern"... die Variable gibts aber irgendwo?

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:

> extern char devName[16];

mittels 'extern' deklarierst du nur.
Du sagst also im Klartext: Irgendwo existeriert ein entsprechendes Array 
mit diesem Namen.
Aber du definierst es so nicht.

Definition: dadurch wird auch tatsächlich entsprechender Speicher 
angelegt
Deklaration: es wird mitgeteilt wie etwas aussieht. Aber dieses etwas 
muss an anderer Stelle definiert sein.


Hast du eine entsprechende Definition an anderer Stelle im Programm?

von Rolf M. (rmagnus)


Lesenswert?

Für mich klingt das nach kaputtem Startup-Code oder einem fehlerhaften 
Linker-Skript. Funktionieren denn globale Variablen normalerweise auf 
dem µC?

von Mr Bean (Gast)


Lesenswert?

Hallo,

vielen Dank für eure Antworten. Also die externe Variable ist 
deklariert. An einer anderen Stelle (bewusst so gemacht).
Den Gedanken mit der Nullterminierung hatte ich auch schon. Darum habe 
ich es auch schon mit strncpy versucht. Hier wird die Länge ja 
vorgegeben.
Hat trotzdem nicht funktioniert.
Außerdem wird der korrekte String mit printf ja auch ausgegeben. Wenn er 
keine Terminierung hätte, würde das dort ja schon auffallen oder?

Gruß,
Bean

von Mr Bean (Gast)


Lesenswert?

Nachtrag: Ja, globale Variablen funktionieren generell in meiner 
Anwendung.

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:

> Außerdem wird der korrekte String mit printf ja auch ausgegeben. Wenn er
> keine Terminierung hätte, würde das dort ja schon auffallen oder?

normalerweise ja. Das fällt da meistens schon auf. Was wird denn bei der 
ersten Ausgabe angezeigt?

Du kannst ja mal probieren, ganz einfach
a) dir die Länge des Strings ausgeben lassen. Alles kleiner als 16 ist 
ok.
b) einen mit Sicherheit "sauberen" String zuzuweisen
1
   ...
2
   strcpy( devName, "juhu" );

von Daniel V. (danvet)


Lesenswert?

welche Adresse wird im Debugger für devName angezeigt?

von Mr Bean (Gast)


Lesenswert?

Also habe versucht einen sauberen String zuzuordnen. Funktioniert leider 
auch nicht.

Adresse der Variable devName laut Debugger: 0x20002F90

Gruß,
Bean

von Daniel V. (danvet)


Lesenswert?

Mr Bean schrieb:
> Also habe versucht einen sauberen String zuzuordnen. Funktioniert leider
> auch nicht.
>
> Adresse der Variable devName laut Debugger: 0x20002F90
>
> Gruß,
> Bean

Und ist das eine gültige Adresse für Variablen (laut Datenblatt) ?

von Mr Bean (Gast)


Lesenswert?

Der Adressbereich für meine Variablen geht von 0x20002800 bis 0x20004100 
sollte also passen.

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:
> Also habe versucht einen sauberen String zuzuordnen.

darf man fragen welchen?
Nicht das wir aneinander vorbeireden.
Nur um das klarzustellen: in einem Array der Länge 16, kannst du einen 
String mit 15 darstellbaren Zeichen gerade noch speichern. 16 
darstellbare Zeichen wären zu viel.
1
  strcpy( devName, "123456789012345" );
wäre also noch in Ordnung
1
  strcpy( devName, "1234567890123456" );
hingegen ist nicht mehr ok.

von Daniel V. (danvet)


Lesenswert?

Ich fürchte du solltest mal den kompletten Code zeigen.
Compiliert alles ohne Warnungen?
Ist die Variable devName[] vielleicht viel kleiner als angenommen?

von Mr Bean (Gast)


Lesenswert?

Also es compiliert ohne Fehler und ohne Warnungen.
Ist ein sehr großes Projekt. Wie gesagt, funktioniert der Code aber. Nur 
das Hinzufügen von der Stringzuweisung bringt die Anwendung zum Absturz. 
Sobald ich diese Operationen wieder entferne, habe ich keine Probleme 
mehr.
Den String habe ich folgendermaßen zugeordnet:
1
strcpy(devName, "Hallo");
Der passt also in das Array rein.

Gruß,
Bean

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:
> Also es compiliert ohne Fehler und ohne Warnungen.

Das heisst nichts.

"Das Flugzeug frühstückt im Tannenbaum." ist auch ein deutscher Satz, 
gegen den kein Duden etwas einzuwenden hätte. Compiler überprüfen nur, 
ob du dich an die Sprachregeln hältst. Ob du logische Fehler hast bzw. 
ob du Speicher überrennst, ist damit noch lange nicht geprüft.

von Daniel V. (danvet)


Lesenswert?

Mr Bean schrieb:
> Also es compiliert ohne Fehler und ohne Warnungen.
> Ist ein sehr großes Projekt. Wie gesagt, funktioniert der Code aber. Nur
> das Hinzufügen von der Stringzuweisung bringt die Anwendung zum Absturz.
> Sobald ich diese Operationen wieder entferne, habe ich keine Probleme
> mehr.
> Den String habe ich folgendermaßen zugeordnet:
>
1
strcpy(devName, "Hallo");
> Der passt also in das Array rein.
>
> Gruß,
> Bean

Ich habe die Variablendefinition von devName[] noch nicht gesehen. 
Sondern nur die Deklaration. Ist es sicher, dass devName[] 16 Elemente 
hat?

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:

> Ist ein sehr großes Projekt.

Es ist auch nicht gesagt, dass das Problem nicht ganz woanders sitzt und 
du hier nur die Auswirkungen siehst.

Symptom ist nicht dasselbe wie Ursache.

von Mr Bean (Gast)


Lesenswert?

Hallo, ich habe einfach die Frage beantwortet, ob das Projekt ohne 
Warnungen und Fehler compiliert wird. ;-) Dass das nicht bedeutet, dass 
keine Fehler vorhanden sind, die das Programm zum absturz bringen 
können, ist mir klar.

Die Variabe devName wird in main.c folgendermaßen global angelegt:
1
char devName[0x10];

Gruß,
Bean

von Mr Bean (Gast)


Lesenswert?

Ja Heinz, das glaube ich mittlerweile auch. Es ist auch nicht das erste 
Mal, dass ich solche stringoperationen mache. Bisher immer ohne 
Probleme. Aber wie finde ich die Ursache dann?

Gruß,
Bean

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:
> Hallo, ich habe einfach die Frage beantwortet, ob das Projekt ohne
> Warnungen und Fehler compiliert wird. ;-) Dass das nicht bedeutet, dass
> keine Fehler vorhanden sind, die das Programm zum absturz bringen
> können, ist mir klar.
>
> Die Variabe devName wird in main.c folgendermaßen global angelegt:
>
1
char devName[0x10];

Was passiert, wenn du gleich in main als allererstes den strcpy machst?
Wenn das klappt (und davon ist auszugehen), dann schiebst du den in der 
Programmlogik immer weiter nach hinten, bis es das erste mal kracht.

von progger (Gast)


Lesenswert?

Mr Bean schrieb:
> char devName[0x10];

wer hat dir denn das beigebracht --> Zahlen in irgendwelchen "krusen" 
Zahlensystemen, bei der Deklaration von Variablen. Zum Glück hast du 
kein Feld mit 1000 Elementen vereinbart. Bei 0x03E8 müsste ich erst mal 
meinen Taschenrechner rauskramen....

von Daniel V. (danvet)


Lesenswert?

progger schrieb:
> Mr Bean schrieb:
>> char devName[0x10];
>
> wer hat dir denn das beigebracht --> Zahlen in irgendwelchen "krusen"
> Zahlensystemen, bei der Deklaration von Variablen. Zum Glück hast du
> kein Feld mit 1000 Elementen vereinbart. Bei 0x03E8 müsste ich erst mal
> meinen Taschenrechner rauskramen....

Das ist jetzt zwar OffTopic, aber:
Das Zahlensystem an sich ist doch wurscht. Für mich fällt das unter die 
Kategory "Magic Numbers".
Woher soll den der Schreiber von Modul_3.c wissen, welche Größe die 
Variable von main.c hat? Oder ob der Schreiber von main.c die Größe 
geändert hat.
Das kann man nur über ein #define (o.ä.) lösen
1
#define devName_Length 0x10
2
3
char devName[devName_Length];

von Mr Bean (Gast)


Lesenswert?

Also, auch wenn ich die Variable devName in main.v verwende, schmiert 
das Programm ab. Ich habe die Variable nun mal initialisiert mit 
"={"HALLO"}".
Wenn ich versuche, die Variable in main.c (am Anfang) auf dem Terminal 
auszugeben, schmiert das Programm schon ab??

von Mr Bean (Gast)


Lesenswert?

Hallo, also die Größe ist über ein #define definiert. ;-)
Wollte euch nur nicht mit solchen Kleinigkeiten "nerven" ;-)
1
#define ARRAY_SIZE 0x10

Gruß,
Bean

von Daniel V. (danvet)


Lesenswert?

Mr Bean schrieb:
> Hallo, also die Größe ist über ein #define definiert. ;-)
> Wollte euch nur nicht mit solchen Kleinigkeiten "nerven" ;-)
>
1
#define ARRAY_SIZE 0x10
>
> Gruß,
> Bean

Um Offtopic zu bleiben: hübscher Name (ARRAY_SIZE). Es weiß dann jeder 
was gemeint ist und wo es zu verwenden ist. ;-)

von Daniel V. (danvet)


Lesenswert?

Mr Bean schrieb:
> Also, auch wenn ich die Variable devName in main.v verwende, schmiert
> das Programm ab. Ich habe die Variable nun mal initialisiert mit
> "={"HALLO"}".
> Wenn ich versuche, die Variable in main.c (am Anfang) auf dem Terminal
> auszugeben, schmiert das Programm schon ab??

Was genau funktioniert jetzt nicht?
Die Initialisierung mit einem String, oder das Ausgeben des Strings?

von Mark B. (markbrandis)


Lesenswert?

Karl H. schrieb:
> Hast du eine entsprechende Definition an anderer Stelle im Programm?

Wenn es die nicht gibt, würde doch der Linker meckern.

von Mr Bean (Gast)


Lesenswert?

Das Ausgeben des Strings funktioniert nicht.
Sobald ich versuche, den String auszugeben, sieht es so aus, als ob der 
Controller nicht einmal los läuft.
Habe die Zeile
1
dbg_printf("%s\r", devName);
direkt am Anfang von main.c eingebaut. --> Controller läuft nicht los.
Zeile wieder entfernt --> Programm läuft.

von Daniel V. (danvet)


Lesenswert?

Dann liegt das Problem doch an dbg_printf() und nicht an der Variablen.
Oder???

von Karl H. (kbuchegg)


Lesenswert?

Mr Bean schrieb:
> Das Ausgeben des Strings funktioniert nicht.
> Sobald ich versuche, den String auszugeben, sieht es so aus, als ob der
> Controller nicht einmal los läuft.
> Habe die Zeile
>
1
dbg_printf("%s\r", devName);
> direkt am Anfang von main.c eingebaut. --> Controller läuft nicht los.
> Zeile wieder entfernt --> Programm läuft.
1
int main()
2
{
3
  strcpy( devName, "Juhu" );
4
  dbg_printf( "%s\n", devName );
5
6
alles weitere wird auskommentiert
7
}

musst du irgend etwas initialisieren, damit die Debug Ausgabe zum 
Terminal funktioniert? Wenn ja, dann kommt dieser Teil noch davor.

von Mr Bean (Gast)


Lesenswert?

Ok, also wenn ich das mache, dann kommt "HALLO" auf dem Terminal raus.
Jetzt heißt es also, alles der Reihe nach wieder inzukommentieren oder 
wie?

Gruß,
Bean

von Mark B. (markbrandis)


Lesenswert?

Mr Bean schrieb:
> Ok, also wenn ich das mache, dann kommt "HALLO" auf dem Terminal raus.
> Jetzt heißt es also, alles der Reihe nach wieder inzukommentieren oder
> wie?

Kann man machen. Man kann aber auch systematischer vorgehen.

Eventuell wird zur Laufzeit ein Speicherbereich überschrieben. Sowas 
könnte man zum Beispiel mit statischer Codeanalyse herausfinden, wobei 
man dafür ein entsprechendes Tool braucht.

Was auch oft schon helfen kann: Einfach mal auf einer anderen Plattform 
mit besseren Debugging-Möglichkeiten übersetzen, z.B. auf dem PC mit 
z.B. gcc (MinGW oder Cygwin) oder Clang/LLVM. Bestimmte Funktionsaufrufe 
und Initialisierungen muss man dann natürlich in #ifdefs packen. Aber 
man erkennt, ob die eigentliche Programmlogik tut oder nicht. Auch hat 
man auf dem PC auf jeden Fall einen Debugger zur Verfügung (z.B. gdb). 
Auf der Zielhardware steht einem sowas nicht unbedingt zur Verfügung.

von Mr Bean (Gast)


Lesenswert?

Genau das ist eines meiner Probleme. Ich arbeite mit KEIL. Auf dem 
Controller läuft noch ein eigenständer BLE Stack. Dieser verhindert ein 
ordentliches Debuggen, da dieser eine Laufzeitkontrolle macht. Mann kann 
also nicht eben mal anhalten und wieder laufen lassen. Das einzigste was 
geht, ist anhalten und sich die Register/Speicher zu diesem Zeitpunkt 
anschauen. Weiterlaufen lassen ist leider nicht möglich.

Gruß,
Bean

von Daniel V. (danvet)


Lesenswert?

Das schränkt natürlich enorm ein. Gibt es keine "Debug-Version" des 
BLE-Stacks? Wie soll man denn da sinnvoll entwickeln können?
Wenn der Controller sich aufhängt: Kannst du den Debugger anhalten und 
schauen, wo das Programm steht? Lässt sich da was rauslesen?

Es sieht ganz nach einem Speicherkonflikt aus.
Was macht denn dbg_printf() genau (Sourcecode)?

von Mr Bean (Gast)


Lesenswert?

Ja, das stimmt, das schränkt wirklich ein. Aber gut, bisher sind wir 
klar gekommen. Habe den Übeltäter auch gefunden. Es war eine Funktion 
des BLE Stacks. Diese hat den String verwendet / falsch verwendet. Diese 
Funktion möchte den String als "const char" ansonsten schlägt ein 
exception handler zu... Fieses Ding. Hat mich ganz schön Nerven 
gekostet.
Vielen Dank an alle die geholfen haben!

Gruß,
Bean

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
Noch kein Account? Hier anmelden.