Hi zusammen,
ich scheitere gerade an einem scheinbar recht simplen Problem.
Für einen pic18F13K50 (ist aber auch unerheblich denke ich) schreibe ich
ein Program welches schlichtweg den Wert eines Timers per USART ausgeben
soll.
Dabei will ich den 16bit unsigned int wert des Timers1 also per
putsUSART() ausgeben (ich nutze die standard usart.h die beim Compiler
dabei ist: void putsUSART ( char *data); )
Damit das geht versuche ich also den Wert des int in ein char[]
umzuwandeln mittels der itoa function aus der stdlib.h: char *itoa (auto
int value, auto char *s);
Aktuell bin ich nu im Simulator von MPLAB X unterwegs und lese da auch
die Werte beim debuggen aus und lasse mit den UART Output anzeigen, wenn
ich nur einfach texte rüber schicke klappt das alles, man kann also
davon ausgehen das es nicht am USART und dessen konfoguration liegt.
Hier nun der relvante code:
1
unsignedintnumberToPrint=12345;
2
charstr[5];
3
itoa(numberToPrint,(char*)str);
4
putsUSART((char*)str);
Was jedoch ausgegeben wird ist in der Output console:
1
24880h
Ich habe beim debuggen gesehen das bereits der Wert von "str" auch eben
dieses "24880h" ist, somit ist recht eingegrenzt das in dem itoa aufruf
irgendwas schief läuft. Aber was. Ich habe nun stundenlang rumgegoogelt
und bisher nur verweise auf "sprintf" gefunden, damit klappt es
grundsätzlich auch....aber nur EINMAl. Die Zahl wird richtig ausgegeben
per UART, jedoch hängt sich dabei der Simulator scheinbar immer ziemlich
auf (er pausiert dann duaernd obwohl es keine breakpoints gibt und der
PC scheint immer nur im Kreis zu laufen jedoch kann ich an die
entsprechende Stelle im Code springen....kein plan) da ich aber eh
gelesen habe das sprintf sehr ressourcenfressend sein soll würde ich
gerne itoa nutzen das ja eigentlich genau da machen sollte was ich will.
Jemand eine Idee was ich falsch mache? Ich werd bekloppt.
Sofern es wichtig ist hier nur die includes:
> unsigned int numberToPrint = 12345;> char str[5];
passt ja auch nicht zusammen, ein string braucht am ende ein \0. Also
brauchst du für 12345 mindestens 6 zeichen.
Paul K. schrieb:> Hoppala, danke dir für die schnelle Antwort, das war aber nicht das> Problem, nur st der Wert der ausgebeben wird halt:>> 24880
Spätestens jetzt ist ein Blick ins Compiler-Handbuch angebracht bzw. in
sonstige Doku.
Denn auch wenn itoa keine C-Standardfunktion ist, so sind doch die
Paramter bei so gut wie allen Implementierungen gleich. Nämlich
1
char*itoa(intvalue,char*str,intbase);
die dritte Angabe, die Zahlenbasis fehlt bei deinem itoa. Damit ist
klar, dass das irgendeine compilerspezifische Spezialversion deines
Compilers ist. Und da hilft dann nur noch ein Blick in die Doku.
Paul K. schrieb:> unsigned int numberToPrint = 12345;> char str[5];
Das ist zu wenig.
Wie lang ist ein String, in den 5 Zeichen passen?
Richtig: 6 Zeichen. Nie die abschließende \0 vergessen.
Also muss es (mindestens) heißen:
> char str[6];
itoa erwartet einen int, kein unsigned int. Also wird, sofern der Wert
größer ist als 32767, der Wert als negativer Wert interpretiert und noch
ein Minuszeichen davor ausgegeben. Damit muss Dein Puffer noch Platz für
ein weiteres Zeichen bieten.
> char str[7];
Dieses Puffergrößenproblem wird die Ursache dafür sein, daß Dein
printf-Versuch nur einmal glückt -- danach ist irgendwelcher Speicher
überschrieben und es können merkwürdige Dinge geschehen.
Initialisiere Deinen Puffer, bevor Du itoa aufrufst, dann kannst Du
überprüfen, ob diese Funktion überhaupt irgendwas macht.
> itoa(numberToPrint, (char*) str);> putsUSART((char*) str);
Was soll hier der Typecast nach char*?
Im übrigen ist itoa sowieso die falsche Funktion. itoa will einen int -
also signed. Du hast keinen int. Du hast einen unsigned int. Die
korrekte Funktion dafür ist utoa und nicht itoa. Das erklärt allerdings
nicht die Diskrepanz bei diesem Zahlenwert.
Karl Heinz Buchegger schrieb:> Paul K. schrieb:>> Hoppala, danke dir für die schnelle Antwort, das war aber nicht das>> Problem, nur st der Wert der ausgebeben wird halt:>>>> 24880>> Spätestens jetzt ist ein Blick ins Compiler-Handbuch angebracht bzw. in> sonstige Doku.>> Denn auch wenn itoa keine C-Standardfunktion ist, so sind doch die> Paramter bei so gut wie allen Implementierungen gleich. Nämlich>
1
>char*itoa(intvalue,char*str,intbase);
2
>
> die dritte Angabe, die Zahlenbasis fehlt bei deinem itoa. Damit ist> klar, dass das irgendeine compilerspezifische Spezialversion deines> Compilers ist. Und da hilft dann nur noch ein Blick in die Doku.
Das das keine C-Standardfunktion ist war mir bekannt, daher hilft mir
der Galileo link nicht so recht weiter.
Bei dem C18 Compiler (v3.41) den ich verwende ist die Signatur jedoch
abweichend zu deinem Beispiel nur mit zwei Parametern (wie ich oben
bereits geschrieben habe, da war der Auszug aus der stdlib.h die zum
Lieferumfang des C18 gehört). Ausserdem ware die Signatur abweichend
würde das ganze ja nicht mal kompilieren, das tut es aber ohne murren.
Die Doku der Funktion selbst hilft mir nicht so recht weiter:
1
char*itoa(autointvalue,autochar*s);
2
/** @name ltoa
3
* The {\bf ltoa} function converts the {\bf long} value {\bf value} to
4
* a radix 10 string representation, storing the resultant string into
5
* the location pointed to by {\bf s}.
6
*
7
* The {\bf ltoa} function is an MPLAB-Cxx extension to the ANSI required
8
* libraries and may not be present in other implementations.
9
* @param value value to convert
10
* @param s pointer to destination string object
11
* @return The {\bf ltoa} function returns the value of {\bf s}.
12
*/
Leider auch im Handbuch keine weiteren Hinweise oder Beispiele.
Karl Heinz Buchegger schrieb:> Im übrigen ist itoa sowieso die falsche Funktion. itoa will einen int -> also signed. Du hast keinen int. Du hast einen unsigned int. Die> korrekte Funktion dafür ist utoa und nicht itoa. Das erklärt allerdings> nicht die Diskrepanz bei diesem Zahlenwert.
Danke für deine Antwort Karl Heinz, das mit dem "unsigned int" vs "int"
habe ich auch schon durch, leider absolut gleiches Ergebnis, es macht
keinen unterschied in dem Fall.
Wie oft hast du in deinem restlichen Programm diesen Array_zu_klein
Fehler noch gemacht?
Auf Deutsch: So ist erst mal kein Problem mehr ersichtlich. Das es
trotzdem nicht funktioniert kann natürlich auch daran liegen, dass im
restlichen Programm noch so einiges nicht stimmt und du das System
zerschossen hast.
----> minimales Beispielprogramm zusammenstellen und posten.
am besten ein Beispielprogramm, welches tatsächlich nur dieses utoa und
die UART Ausgabe enthält und sonst nichts anderes.
Dirk schrieb:> Versuch mal> str = itoa(numberToPrint, (char*) str);
das ist doch unsinn, wie soll man denn str ändern können, wenn es eine
array auf dem Stack ist.
Rufus Τ. Firefly schrieb:> Paul K. schrieb:> itoa erwartet einen int, kein unsigned int. Also wird, sofern der Wert> größer ist als 32767, der Wert als negativer Wert interpretiert und noch> ein Minuszeichen davor ausgegeben. Damit muss Dein Puffer noch Platz für> ein weiteres Zeichen bieten.>>> char str[7];>> Dieses Puffergrößenproblem wird die Ursache dafür sein, daß Dein> printf-Versuch nur einmal glückt -- danach ist irgendwelcher Speicher> überschrieben und es können merkwürdige Dinge geschehen.
Hallo Rufus, vielen Dank für deine Antwort. Ich habe auch mit einer
Array-Größe von 7 das gleiche Problem.
Bei dem printf nutze ich übrgens den char[] garnicht, da übergebe ich
schlicht die int variable und lasse printf die Formatierung machen (%i).
Somit ist die Lange da vermultich nicht das Problem gewesen
>>> Initialisiere Deinen Puffer, bevor Du itoa aufrufst, dann kannst Du> überprüfen, ob diese Funktion überhaupt irgendwas macht.>
hab ich gemacht, initialisiert mit "000000" (im debugger verifziert, war
"000000\u0x0") und dann nach dem itoa nochmal geprüft, steht dann auch
der neue "24880\u0x0\u0x0"
>>>> itoa(numberToPrint, (char*) str);>> putsUSART((char*) str);>> Was soll hier der Typecast nach char*?
Der Typecast ist nur für den Compiler damit er nicht meckert. Er macht
sonst einen impliziten Cast aber gibt immer eine Warnung aus, mit dem
cast kommt die halt nicht, hat also rein optische Gründe beim
kompilieren. Macht keinen unterschied bezüglich der Konvertierung in der
itoa
Steel schrieb:> Versuch mal>> static char str[7];>> statt>> char str[5];
Leider kein Erfolg.
Hier nun der gesammte Code mit allem anderen Entfernt (naja fast, die
Config bits sind sicherlich nicht alle nötig) was nicht nötig ist für
das Beispiel, die Ausgabe ist noch immer die selbe in der Console
(24880).
1
#include<p18F13K50.h>
2
#include<stdlib.h>
3
#include<usart.h>
4
#include<delays.h>
5
6
// PIC18F13K50 Configuration Bit Settings
7
// CONFIG1L
8
#pragma config CPUDIV = NOCLKDIV// CPU System Clock Selection bits (No CPU System Clock divide)
9
#pragma config USBDIV = OFF // USB Clock Selection bit (USB clock comes directly from the OSC1/OSC2 oscillator block; no divide)
Kommentier mal das itoa aus.
so:
static char str[7] = "12345";
// itoa(numberToPrint, str);
putsUSART(str);
btw: Du hattest schon wieder eine '0' zu viel in deinem String!!!
> Der Typecast ist nur für den Compiler damit er nicht meckert. Er macht sonst
einen impliziten Cast
Ein Cast von char* auf char*
Und dann verschwindet eine Warnung des Compilers?
Da steckt mehr dahinter, das muss dich stutzig machen.
Wie lautet die Warnung?
Steel schrieb:> Kommentier mal das itoa aus.>> so:> static char str[7] = "12345";> // itoa(numberToPrint, str);> putsUSART(str);>> btw: Du hattest schon wieder eine '0' zu viel in deinem String!!!
Ausgabe ist korrekt via UART: 00000
wie gesagt text geht ja auch korrekt über UART, U(S)RAT selbst scheint
also richtig konfiguriert.
(Null habe ich auch entfernt)
Karl Heinz Buchegger schrieb:>> Der Typecast ist nur für den Compiler damit er nicht meckert. Er macht sonst> einen impliziten Cast>> Ein Cast von char* auf char*> Und dann verschwindet eine Warnung des Compilers?>> Da steckt mehr dahinter, das muss dich stutzig machen.> Wie lautet die Warnung?
Hallo Heinz, sorry, da hab ich tatsächlich einen Cast zu viel gemacht,
wie du oben im Beispiel siehst, ist der Cast nun raus (uns es kommt
keine Warnung).
Einen Cast musste ich nur bei einem putrsUSART(...) machen:
putrsUSART((const rom far char *)"\r\nNothing to do");
Aber das ist in dem Beispiel nicht mehr drinnen und soll nun auch nicht
weiter Thema sein.
Das kommt dabei raus wenn man stundenlang nach jedem Zweig greift um das
Problem zu beheben :-)
Hallo!
Probier doch mal das Minimum im Simulator aus:
void main() {
int numberToPrint = 12345;
char str[7] = "000000";
itoa( numberToPrint, str );
}
Im Schrittmodus steht nach itoa bei mir tatsächlich "12345\\0\\0" im
String.
Alles andere hätte mich auch gewundert ...
vg
Jürgen
Paul K. schrieb:> Das kommt dabei raus wenn man stundenlang nach jedem Zweig greift um das> Problem zu beheben :-)
OK. mach mal folgendes.
Schreib eine eigene Version von itoa
1
voidmyUtoa(unsignedintnum,char*str)
2
{
3
unsignedchari;
4
5
for(i=0;i<5;++i)
6
{
7
str[4-i]=(num%10)+'0';
8
num=num/10;
9
}
10
str[5]='\0';
11
}
damit man mal feststellen kann, ob es ein Problem mit dem utoa oder mit
den UART Sachen im Zusammenhang mit char-Arrays gibt, die vom Optimizer
(wegen dem ihm bekannten konstanten String) bereinigt hat.
Jürgen Schmied schrieb:> Hallo!>> Probier doch mal das Minimum im Simulator aus:>> void main() {> int numberToPrint = 12345;> char str[7] = "000000";> itoa( numberToPrint, str );> }>> Im Schrittmodus steht nach itoa bei mir tatsächlich "12345\\0\\0" im> String.> Alles andere hätte mich auch gewundert ...>> vg>> Jürgen
Hab folgendes super minimal program probiert:
Jürgen Schmied schrieb:> Prüfe mal den Bibliothekspfad vieleicht hast Du XC8 und C18 Bibliotheken> gemeinsam auf Deinem Rechner ???> Oder zwei Versionen des C18? MPLAB alt??
XC8 hab ich nicht drauf, hab noch einen C30 Compiler drauf, aber C18 ist
auf default und auch nur der ist in dem Projekt angewählt.
Pfade sind alle Standard, da hab ich nix angepast.
Ich werde mal mplab x neu installieren, wollte das eh in eine virtuelle
Maschine umziehen. Dann ist alles Frisch und dann versuche ich es
nochmal.
Vielen Dank an alle die konstruktiv geantwortet haben!
>Karl Heinz, danke dir! Mit deiner customer Funktin geht es :-))))))
Ich würde dem Frieden nicht trauen. itoa läuft nicht erst seit der
letzten Version des Compilers. Wenn Du die jetzt selbst realisierst
wette ich, dass es bei einer der nächsten Bibliotheksfunktionen
knallt...
Das ist irgendetwas Grundlegendes falsch.
Schau mal ins Disassembly-listing, welche itoa überhaupt reingelinkt
wird - da stehen Dateinamen der Quellen drin.
vg
Jürgen
Jürgen Schmied schrieb:>>Karl Heinz, danke dir! Mit deiner customer Funktin geht es :-))))))>> Ich würde dem Frieden nicht trauen. itoa läuft nicht erst seit der> letzten Version des Compilers. Wenn Du die jetzt selbst realisierst> wette ich, dass es bei einer der nächsten Bibliotheksfunktionen> knallt...> Das ist irgendetwas Grundlegendes falsch.> Schau mal ins Disassembly-listing, welche itoa überhaupt reingelinkt> wird - da stehen Dateinamen der Quellen drin.>> vg>> Jürgen
Danke dir Jürgen das du der Sache noch auf den Grund gehen willst.
Im Disassembly-Listing steht tatsächlich ein Pfad drin
"C:/MCC18/src/traditional/stdclib/itoa.asm" den es garnicht gibt(!). [Da
ist auch kein unsichtbarer Systemordner oder sowas] Aber woher kommt
dann der assembler code dazu her? Wie dem auch sei, ich habe eingesehen
das mit meiner Installation wohl was im Eimer ist. Ich werde euch
nochmal berichten wenn es Frisch aufgesetzt ist.
Paul K. schrieb:> Im Disassembly-Listing steht tatsächlich ein Pfad drin> "C:/MCC18/src/traditional/stdclib/itoa.asm" den es garnicht gibt(!). [Da> ist auch kein unsichtbarer Systemordner oder sowas] Aber woher kommt> dann der assembler code dazu her?
langsam.
Der Originalcode stand mal auf diesem Verzeichnis.
Irgendwer hat dann mal alle Einzelteile, die zusammen die
Standard-Library bilden hergenommen und eine echte Library gebaut, die
vom Linker dann als Ganzes mit dazugelinkt wird.
Jetzt erhebt sich die Frage, ob jemand anderer, der dasselbe System hat,
dasselbe ausprobiert und dort die gleichen Pfade sieht oder nicht.
Habe im Angebot:
E:/c18v3.46/pic18-lt/cxx-framework/src/traditional/stdclib/itoa.asm
Die Verzeichnisnamen sehen nach einer Umorganisation aus. Hole Dir doch
mal den neusten C18 Compiler.
vg
Jürgen
So, kurzes update: Nach Neuinstallation von MPLAB X (v1.90) und C18
Compiler klappt nun alles. Naja, zumindest mit dem itoa.
Beim Versuch den pic zu programmieren hat mir MPLAB X dann beim Download
einer neuen Firmware mit neuem 'AP' und 'RS' den Pickit3 gebricked,
jetzt steht ich erst mal wieder ohne da und er wird nicht mehr erkannt
unter windows :-(
Aber das andere Problem ist gelöst.