Forum: Mikrocontroller und Digitale Elektronik sprintf auf MSP430 geht nicht mehr.


von Mark M. (mom-jovi)


Lesenswert?

Mein CCE ärger mich gewaltig.
Immermal wieder gehen bestimmte Funktionen nicht mehr.
Jetz macht sprintf nicht mehr das, was es soll. Es hat bis vor kurzem 
funktioniert.
Ich möchte mehrere uint16-Werte in einen String speichern, aber dann 
steht im String nur wirres Zeug.
1
sprintf(buf,"\r\n%02u:%02u:%02u %u %u %u %u", std, min, sek, Data[0],Data[1],Data[2],Data[3]);

in buf, welcher ein
1
char buf[100];
ist, stehen vor allem '\0', '\191' und ab und an mal ein "echter" 
Buchstabe...

von Seltsam (Gast)


Lesenswert?

Mark, sei nicht so garstig mit dem armen CCE! Ich behaupte, man kann mit 
jedem Compiler ein Programm um deine Zeile produzieren, das die 
beschriebenen Fehler erzeugt. Beste Voraussetzungen dafür sind wenig 
freier RAM, d.h. zu Ende gehender Stack und falsch oder am falschen Ort 
definierte Variablen.

von markus (Gast)


Lesenswert?

Hi,

auf einem Controller mit begrenztem Speicher wie beim MSP430 sollte man 
solch vergleichsweise großen Speicherbereiche wie bei deinem Fall auf 
jeden Fall mit malloc reservieren!

Über den Rückgabe-Wert sieht man dann auch gleich, ob der Speicher 
überhaupt zur Verfügung steht!

Ansonsten schließe ich mich meinem Vorredner an: Das sieht einfach 
danach aus, dass du dein RAM nicht richtig nutzt und deshalb an 
irgendwelchen wirren Orten schreibst und ließt, an denen du eigentlich 
nicht sein solltest!

Das Problem hatte ich auch mal, seitdem speichere ich solche 
Datenstrings im Flash.

Gruß,

Markus

von Karl H. (kbuchegg)


Lesenswert?

markus schrieb:
> Hi,
>
> auf einem Controller mit begrenztem Speicher wie beim MSP430 sollte man
> solch vergleichsweise großen Speicherbereiche wie bei deinem Fall auf
> jeden Fall mit malloc reservieren!

Und was bringt das?
Wenn der Speicher zu Ende ist, dann ist er zu Ende. Egal ob globale 
Variable oder dynamisch allokiert.

> Über den Rückgabe-Wert sieht man dann auch gleich, ob der Speicher
> überhaupt zur Verfügung steht!

Das du dich da mal nicht täuscht.
Typisch liefert malloc noch lange gültige Pointer, während der Heap 
schon langst in den Stack hineingewachsen ist.

von Gerhard (Gast)


Lesenswert?

Bei IAR kann ich die Stackgröße angeben und die liegt default bei 80 
Byte. Du könntest versuchen deine Variable buf als static außerhalb der 
Funktion zu deklarieren, das wäre erst einmal das einfachste.


---

von Mark M. (mom-jovi)


Lesenswert?

Es lag nicht am Speicher, Problem ist gelöst: stdio war nicht 
inkludiert. Ich dachte, es reicht ein include in der main.c.
Aber warum kam denn keine Warnung vom Compiler?

von Mark M. (mom-jovi)


Lesenswert?

Ok, anderes Problem:
1
typedef unsigned char uint8_t;
2
typedef unsigned short int uint16_t;
3
4
char buf[60];
5
uint8_t sek;  //==2     |
6
uint8_t min;  //==55    |
7
uint16_t std; //==15     \  aus dem laufenden
8
uint8_t day;  //==10     /  Programm heraus
9
uint8_t mon;  //==2     |
10
uint16_t year;//==2011  |
11
12
sprintf(buf,"\r\n%02u %02u %02u %02u:%02u:%02u %u %u %u %u", day, mon, year, std, min, sek, Data[0],Data[1],Data[2],Data[3]);
13
14
//jetzt steht in buf: \r\n02 522 2011 15:55:02 1024 1024 0 128
Warum wird der Monat nicht richtig formatiert?

von Helmut L. (helmi1)


Lesenswert?

Mark M. schrieb:
> Warum wird der Monat nicht richtig formatiert?

Weil sprintf davon ausgeht das es eine 16Bit Variable uebergeben 
bekommt.

Caste mal (uint16_t)mon  in deinem Aufruf.

von Mark M. (mom-jovi)


Lesenswert?

Helmut Lenzen schrieb:
> Weil sprintf davon ausgeht das es eine 16Bit Variable uebergeben
> bekommt.

??? Aber bei sek, min und day geht es doch auch?

von Mark M. (mom-jovi)


Lesenswert?

Mark M. schrieb:
> Helmut Lenzen schrieb:
>> Weil sprintf davon ausgeht das es eine 16Bit Variable uebergeben
>> bekommt.
>
> ??? Aber bei sek, min und day geht es doch auch?

Außerdem funktionierts auch mit dem Casten nicht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Helmut Lenzen schrieb:
> Weil sprintf davon ausgeht das es eine 16Bit Variable uebergeben
> bekommt.

Das bekommt es auch, bei Funktionen mit variabler Argumentenliste wird 
automatisch erweitert:

> Since the prototype doesn't specify types for optional arguments,
> in a call to a variadic function the /default argument promotions/
> are performed on the optional argument values.
> This means the objects of type char or short int (whether signed
> or not) are promoted to either int or unsigned int, as appropriate;
> and that objects of type float are promoted to type double.
(Quelle: 
http://www.gnu.org/s/libc/manual/html_node/Calling-Variadics.html#Calling-Variadics)

Im Beispiel aber wird nicht nur für den Monat, sondern auch für den Tag 
was falsches ausgegeben, da geht also irgendwas anderes schief.

Sind die im Beispiel angegebenen Werte mit einem Debugger ermittelt 
worden oder wo kommen die her?

von Mark M. (mom-jovi)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Im Beispiel aber wird nicht nur für den Monat, sondern auch für den Tag
> was falsches ausgegeben, da geht also irgendwas anderes schief.

Ups, sorry, hatte mich mal wieder vertippt! In buf steht natürlilch: 
\r\n10 522 2011 15:55:02 1024 1024 0 128

> Sind die im Beispiel angegebenen Werte mit einem Debugger ermittelt
> worden oder wo kommen die her?

Ja, die Werte hab ich aus dem Debugger, nachdem sie von der microSD 
gelesen worden. Anschließend schreibe ich den Timestamp zusammen mit dem 
Messdaten wieder auf die Karte und dann steht dort auch: 10 522 2011 
15:55:02 1024 1024 0 128

von Mathias A. (mrdelphi)


Lesenswert?

Bin mir gerade nicht sicher, aber werden bei sprintf die Argumente nicht 
als Pointer übergeben? d.h. bei %u liest er 16 bit ab der angegebenen 
Adresse. Die 522 sind ja 512+10, also lo-byte=10 und hi-byte=2, sieht 
also so aus als ob hier das mon- und das day-byte ausgelesen werden.

Dass es bei min und sek funktioniert könnte daran liegen dass der 
Compiler die Variablen umsortiert und dort "zufällig" 0-Bytes dazwischen 
liegen...

Wenn Dein sprintf sowas hat nimm statt %u ein Format welches nur 1 Byte 
liest; oder sonst müssen alle Variablen als uint16 deklariert sein.

von Mark M. (mom-jovi)


Lesenswert?

Ok, ich hab jetzt alle Variablen, die nicht 16bit sind, nach uint16_t 
gecastet und jetzt läuft es.
Danke, ich wusste nicht, dass sprintf 16bit erwartet. Ich hatte mir aber 
eigentlich gedacht, dass es trotzdem funktionieren müsste, wie rufus 
schrieb.

von Helmut L. (helmi1)


Lesenswert?

Mark M. schrieb:
> Ich hatte mir aber
> eigentlich gedacht, dass es trotzdem funktionieren müsste, wie rufus
> schrieb.

Haengt wohl von der Compiler Version ab. Bin da auch schon mal drauf 
reingefallen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Mathias A. schrieb:
> Bin mir gerade nicht sicher, aber werden bei sprintf die Argumente nicht
> als Pointer übergeben?

O nein. Das werden sie nur bei den /scanf/-Varianten.

Mark M. schrieb:
> Danke, ich wusste nicht, dass sprintf 16bit erwartet.

Dann solltest Du mal die Dokumentation Deines Compilers zum Thema 
"default argument promotion" befragen.

von Mathias A. (mrdelphi)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Mathias A. schrieb:
>> Bin mir gerade nicht sicher, aber werden bei sprintf die Argumente nicht
>> als Pointer übergeben?
>
> O nein. Das werden sie nur bei den /scanf/-Varianten.

stimmt, da hast Du recht...sorry, weiß auch nicht mehr wie ich darauf 
kam, zumal wenn es pointer wären ja eher das im Speicher hinter dem 
mon-Feld liegende year statt dem day genommen worden wäre...bei Übergabe 
übern Stack passt es ja dann wieder zu meiner Theorie, da dann day ja 
hinter mon liegt. :)
Bei Pointern hätte auch der Typecast nichts genützt...

Wundert mich aber dann warum es bei min und sek trotzdem geklappt hatte, 
aber nun gut, wenn es jetzt funktioniert sollte man vielleicht nicht 
mehr zuviel Gedanken drüber verschwenden.


Mark M. schrieb:
> Danke, ich wusste nicht, dass sprintf 16bit erwartet.

das hängt von der Plattform ab: allgemein liest %u ein "unsigned int", 
was je nach Plattform eben 16, 32, 64 oder wieviel auch immer Bits sein 
können. Dazu gibts normalerweise Modifier, z.b. %hu für unsigned short, 
%lu für long, etc.   Ist schon lange her dass ich sowas auf einem 
16-Bit-System gemacht habe, aber wenn ich mich recht erinnere könnte %hu 
das passende für 8-Bit-Werte sein (müsstest mal in der Doku Deines 
Compilers/C-Lib nachschauen).

von Helmut L. (helmi1)


Lesenswert?

Mathias A. schrieb:
> Wundert mich aber dann warum es bei min und sek trotzdem geklappt hatte,

Weil das nächste Byte im Speicher das als Highbyte eingelesen wurde 
zufällig mit 0 besetzt war.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Helmut Lenzen schrieb:
> Weil das nächste Byte im Speicher das als Highbyte eingelesen wurde
> zufällig mit 0 besetzt war.

Das kommt mir spanisch vor. Angenommen, es sei so, wie Du annimmst, dann 
müssten die Argumente nacheinander auf den Stack gepackt werden, ohne 
die von mir angesprochene default argument promotion sollte das bei 
den ersten sechs Argumenten day, mon, year, std, min, sek in folgenden 
sieben Bytes resultieren:

  10,   2, --2011--,  15,  55,   2
0x0A 0x02 0x07 0xDB 0x0F 0x37 0x02

oder (falls der Kram andersherum auf den Stack gepackt wird)

0x02 0x37 0x0F 0xDB 0x07 0x02 0x0A

Das aber haut vorne und hinten nicht hin, denn da fehlen die von Dir 
angesprochenen zufälligen Nullen.
Für die ersten drei Formatspezifzierer müsste dann das hier 
herauskommen:

0x0A02   522(!)
0x07DB  2011
0x0F37  3895

... was es ja nicht tut (resp. tun soll), es sollen ja alle Werte bis 
auf den zweiten korrekt ausgegeben werden.

Auffällig ist hier allerdings der Wert 522, der kommt irgendwie 
bekannt vor.

von Helmut L. (helmi1)


Lesenswert?

Man müsste mal den erzeugten Assemblercode dazu sehen. Dann könnte man 
sehen was dort schief läuft.

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.