www.mikrocontroller.net

Forum: Compiler & IDEs Problem bei konvertiren eines char[] in einen integer


Autor: Michael O. (michi26206)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich übertragen via USART an einen Atmega16 Daten. Diese kommen dort in 
einem char array an. Nun möchte ich diesen char Array in einen Integer 
umwandeln.

ich habs mit folgendem versucht:
uint32_t recived_time_ticks;
char usart_string[7];

recived_time_ticks += ((usart_string[0] - '0') * 10000); //1
recived_time_ticks += ((usart_string[1] - '0') * 1000);
recived_time_ticks += ((usart_string[2] - '0') * 100);
recived_time_ticks += ((usart_string[3] - '0') * 10);
recived_time_ticks += (usart_string[4] - '0');
ich habe vom PC aus 72000 an den µC gesendet angekommen is aber: 64640. 
Dannach habe ich testweise die mit 1 kommentierte Zeile auskommentiert, 
jetzt kam 2000 an. Das würde passen. Irgendwie scheint ihm also die 
Multiplikation mit 10000 nicht zu gefallen.

Kann mir wer einen Tipp geben?

Gruß

Autor: Lukas K. (carrotindustries)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verscuhe mal
recived_time_ticks += (((uint32_t)usart_string[0] - (uint32_t)'0') * (uint32_t)10000); //1
Cast heißt das Zauberwort

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Irgendwie scheint ihm also die Multiplikation mit 10000 nicht zu gefallen.
> Kann mir wer einen Tipp geben?

Die Multiplikation in 32 Bit ausführen, sonst gibts bei 16 Bits einen 
Überlauf.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist doch schon 32 Bit,

uint32_t recived_time_ticks;

kann aber auch sein, dass durch ein 5732te Sonderregel von C das bei der 
verkürzten Schreibweise nicht erkannt wird. Dann kann man das aber auch 
ohne Monster-Panik-Cast(ing) machen. Einfach ein L an die 10000 anfügen, 
damit wird das eine 32 Bit Konstante.

recived_time_ticks += ((usart_string[0] - '0') * 10000L); //1

MFG
Falk

Autor: Michael O. (michi26206)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke an euch schon mal. Hab beides probiert.
Geht leider immer noch nicht. Werde mich jetzt aber mal schlafen legen 
und morgen weiter machen.

Gruß

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk Brunner schrieb:
> Ist doch schon 32 Bit,

Nein.

> uint32_t recived_time_ticks;

Das hat aber absolut nichts damit zu tun, mit welcher Bitbreite die 
Multiplikation durchgeführt wird.

> kann aber auch sein, dass durch ein 5732te Sonderregel von C das bei der
> verkürzten Schreibweise nicht erkannt wird.

Das hat nichts mit Sonderregeln oder einer verkürzten Schreibweise zu 
tun, sondern liegt schlicht daran, daß der Typ, mit dem eine Operation 
durchgeführt wird, immer nur von den Operanden abhängt und nie davon, 
was später mit dem Ergebnis gemacht wird.
Bei
((usart_string[0] - '0') * 10000)
sind beide Operanden der Multiplikation vom Typ int, also wird die 
Multiplikation in int durchgeführt.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Rolf Magnus (Gast)

>Das hat nichts mit Sonderregeln oder einer verkürzten Schreibweise zu
>tun, sondern liegt schlicht daran, daß der Typ, mit dem eine Operation
>durchgeführt wird, immer nur von den Operanden abhängt und nie davon,
>was später mit dem Ergebnis gemacht wird.

Schon klar, aber

>((usart_string[0] - '0') * 10000)

>sind beide Operanden der Multiplikation vom Typ int, also wird die
>Multiplikation in int durchgeführt.

Falsch, dein "Zitat" ist ausserdem unvollständig.

recived_time_ticks += ((usart_string[0] - '0') * 10000); // Original
recived_time_ticks = recived_time_ticks + ((usart_string[0] - '0') * 10000); // Äquivalent

Somit steht jetzt eine 32 Bit Zahl auf der rechten Seite, womit ALLE 
anderen Zahlen erstmal in 32 Bit konvertiert werden, bevor gerechnet 
wird. Oder nicht?

MfG
Falk

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk Brunner schrieb:

> Schon klar, aber
>
>>((usart_string[0] - '0') * 10000)
>
>>sind beide Operanden der Multiplikation vom Typ int, also wird die
>>Multiplikation in int durchgeführt.
>
> Falsch, dein "Zitat" ist ausserdem unvollständig.

Nein, das ist nicht falsch, und das Zitat enthält alles, was für die 
Beantwortung der Frage, mit welchem Typ die Multiplikation durchgeführt 
wird, notwendig ist.

> recived_time_ticks += ((usart_string[0] - '0') * 10000); // Original
> recived_time_ticks = recived_time_ticks + ((usart_string[0] - '0') * 10000); // 
Äquivalent
>
> Somit steht jetzt eine 32 Bit Zahl auf der rechten Seite, womit ALLE
> anderen Zahlen erstmal in 32 Bit konvertiert werden, bevor gerechnet
> wird. Oder nicht?

Nein. Du mußt jede Operation einzeln betrachten. Deshalb: Es ist egal, 
was später mit dem Ergebnis passiert, es zählen ausschließlich die 
Operanden. Das heißt, es spielt keine Rolle, daß du das Ergebnis der 
Multiplikation später einer 32-Bit-Variablen zuweist.
Die Berechnung läuft in dieser Reihenfolge ab:

Durch die Klammerung kommt zuerst:
(ich führe mal für das Zwischenergebnis eine Variable 'tmp' ein)
tmp = usart_string[0] - '0'

Der linke Operand ist vom Typ char, der rechte vom Typ int, also wird 
zuerst der linke nach int konvertiert ("integer promotion"), dann wird 
die Subtraktion in int durchgeführt. tmp wäre also auch vom Typ int.

Jetz kommt
tmp2  = tmp * 10000;

tmp ist vom Typ int, 10000 auch, also wird die Multiplikation auch mit 
dem Typ int durchgeführt, und tmp2 ist ebenfalls vom Typ int. Jetzt 
kommt
received_time_ticks += tmp2;

received_time_ticks it vom typ uint32_t, tmp2 ist vom Typ int, also wird 
jetzt tmp2 nach uint32_t konvertiert und dann die Additon durchgeführt. 
Das heißt, daß nur diese eine Addition in 32 Bit abläuft, der Rest aber 
in 16 Bit.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Rolf Magnus (Gast)

>Nein. Du mußt jede Operation einzeln betrachten. Deshalb: Es ist egal,
>was später mit dem Ergebnis passiert, es zählen ausschließlich die
>Operanden.

Ok, das ist dann wohl der Knackpunkt, der mir bisher nicht bekannt war. 
Ich dachte das wird auf die gesamte Rechnung auf einmal bezogen. Danke 
für die Aufklärung.

>Das heißt, daß nur diese eine Addition in 32 Bit abläuft, der Rest aber
>in 16 Bit.

Dann sollte aber mein Tip mit 10000L funktionieren. Oder der Fehler 
steckt woanders, wahrscheinlich in einem Pufferüberlauf und einem 
verschluckten ersten Zeichen. ;-)

@ OP

Um die Routine zu prüfen solltest du mal explizit im Programm den Puffer 
füllen und nicht per UART.

MfG
Falk

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk Brunner schrieb:

> Um die Routine zu prüfen solltest du mal explizit im Programm den Puffer
> füllen und nicht per UART.

@OT
uint32_t recived_time_ticks;
char usart_string[7];

recived_time_ticks += ((usart_string[0] - '0') * 10000); //1

zb wäre es schon von Vorteil, recived_time_ticks zunächt mit 0 zu 
initialisieren. Oder aber in der ersten Rechnung kein += sondern ein 
simples = zu machen.

Ansonsten:
Den String zum Sender zurücksenden oder sonst irgendwo ausgeben um 
nachzusehen, ob auch tatsächlich das angekommen ist, was du denkst das 
angekommen sein sollte. In der Kette

   Eingange  ->  Verarbeitung  ->  Ausgabe

kann der Fehler überall stecken. Auch im Schritt Eingabe. Ist die schon 
falsch, kannst du hinten nach suchen so viel du willst. Eine viel zu oft 
vergessene Regel sagt schliesslich "garbage in - garbage out". Wenn 
vorne schon Müll hineingesteckt wird, wird hinten auch immer Müll 
rauskommen.

Autor: Michael O. (michi26206)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Buffer ist in Ordnung, ich hab ihn mir vor dem Verarbeiten immer 
ausgeben lassen.
Werde mich später melden, wenn ich mehr weis.

Autor: Michael O. (michi26206)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abend,

ich bin endlich wieder dazu gekommen:

habe folgendes ohne Erfolg versucht:
recived_time_ticks = 0;
recived_time_ticks = usart_string[0] - '0';
recived_time_ticks = (uint32_t)recived_time_ticks * (uint32_t)10000L; //1

leider ohne Erfolg. Hat jemand noch nen Tipp oder kennt wer ne 
unproblematischere Lösung um den char array in einen integer zu 
bekommen? Oder evtl. sogar ne einfachere Möglichkeit die 72000 über 
USART in den µC zu bekommen?

Gruß

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Michael O. (michi26206)

>habe folgendes ohne Erfolg versucht:

Das ist reine Panik, bringt aber rein gar nichts. Dein Problem liegt 
woanders. So reicht es.

recived_time_ticks = recived_time_ticks * usart_string[0] * 10000L; //1

Wie debuggst du denn? Vielleicht ist der Fehler in deiner Debugausgabe.

MfG
Falk

Autor: Michael O. (michi26206)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abend,

so ich bin jetzt alles nochmal durchgegagen.
Es war wie Ihr gesagt habt, die Rechnung war in Ordnung, aber die 
Ausgabe des Ergebnisses hat nicht gepasst, ich habe den Integer beim 
Ausgeben wieder in einen String umgewandelt, hierfür habe ich allerdings 
nicht die 32Bit (utoa) Methode verwendert sondern die 16 Bit (itoa).

Gruß & Danke @ all

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael O. schrieb:
> Abend,
>
> so ich bin jetzt alles nochmal durchgegagen.
> Es war wie Ihr gesagt habt, die Rechnung war in Ordnung, aber die
> Ausgabe des Ergebnisses hat nicht gepasst, ich habe den Integer beim
> Ausgeben wieder in einen String umgewandelt, hierfür habe ich allerdings
> nicht die 32Bit (utoa) Methode verwendert sondern die 16 Bit (itoa).

Immer noch falsch

   itoa      int              16 Bit mit Vorzeichen
   utoa      unsigned int     16 Bit ohne Vorzeichen
   ltoa      long             32 Bit mit Vorzeichen
   ultoa     unsigned long    32 Bit ohne Vorzeichen

Autor: Michael O. (michi26206)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da gebe ich dir natürlich sofort Recht ;-)
War ein Tippfehler meinerseits hier im Forum. Sry.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das zentrale Problem wird leicht übersehn. Dittrich Drahtlos ;-)

http://www.elektronik-bastelbude.de/Drahtlos/kap7a.htm

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.