Forum: Mikrocontroller und Digitale Elektronik Mit atoi() aus char-String-Array ein uint64_t machen?


von Wolfgang B. (logox2)


Lesenswert?

Guten Morgen,

Kann ich mit atoi() aus
1
// ein array mit hex-werten als ASCII-Zeichen
2
uint8_t array[24] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '\r', '\n', 0, 0, 0, 0, 0, 0};
ein einfaches int64
1
uint64_t = 0x0123456789ABCDEF
machen?

Wolfgang

von Fred S. (Gast)


Lesenswert?

Hallo Wolfgang,

für "string" mit anderen Basen als 10 nach "unsigned long int" benötigst 
Du "strtoul(..)". Ob "unsigned long int" identisch mit uint64_t ist, 
hängt vom Compiler ab.

Gruß

Fred

von Wolfgang B. (logox2)


Lesenswert?

Hi Fred,

danke für erste Info.

AVR-GCC: typedef unsigned long long int uint64_t

Ich hätte vielleicht mein Problem noch ein wenig genauer beschreiben 
sollen:
Ich verwende WinAVR und einen atmega128 und möchte eine Zeichenkette die 
ich über UART empfange in eine 'echte' Zahl umwandeln. Die Zeichenkette 
ist dabei max. 14 'Hex-Zeichen' lang. Dabei entspricht das erste Zeichen 
dem höchstwertigen Nibbel in der Zahl, das letzte Zeichen, dem 
niederwertigsten Nibbel, die uint64_t muß also (nachdem alle Zeichen 
empfangen worden sind) von rechts her aufgebaut werden.

Wolfgang

von Karl H. (kbuchegg)


Lesenswert?

Wolfgang Birner wrote:

> ist dabei max. 14 'Hex-Zeichen' lang. Dabei entspricht das erste Zeichen
> dem höchstwertigen Nibbel in der Zahl, das letzte Zeichen, dem
> niederwertigsten Nibbel, die uint64_t muß also (nachdem alle Zeichen
> empfangen worden sind) von rechts her aufgebaut werden.

Das kannst du on-the-fly zusammenbauen.

Frei nach dem Muster

  Result = 0

  while( nächstes Zeichen gehört zur Hex Zahl ) {
    Result = Result * 16 + HexDigit( nächstes Zeichen )
  }

Getreu dem (Dezimal)Muster

1287 = 1 * 1000 + 2 * 100 + 8 * 10 + 7 * 1 =
       (((( 1 * 10 ) + 2 ) * 10 ) + 8 * 10 ) + 7


Mit der Hilfsfunktion:  HexDigit
1
int HexDigit( char Digit )
2
{
3
  if( Digit >= '0' && Digit <= '9' )
4
    return Digit - '0';
5
6
  return Digit - 'A' + 10;
7
}

Das hat den Vorteil, dass du theoretisch die Character
gar nicht zwischenspeichern musst, sondern die Zahl aufbauen
kannst während die Ziffern über die UART eintrudeln.

Aufpassen auf die Datentypen!

von Fred S. (Gast)


Lesenswert?

Hallo Wolfgang,
> AVR-GCC: typedef unsigned long long int uint64_t
also wird es nicht gehen, da "typedef long int uint32_t"! Ausweg: Du 
wandelst zuerst die unteren 8 Zeichen um (gibt Dir die unteren 4 Bytes), 
dann die oberen (gibt Dir die oberen 4) und fügst alles zusammen.
> niederwertigsten Nibbel, die uint64_t muß also (nachdem alle Zeichen
> empfangen worden sind) von rechts her aufgebaut werden.
Sowohl atoi() als auch strtoul() machen es so!

Wenn Du nur mit 16 als Basis arbeitest, ist doch eine Ziffer immer ein 
Nibble. Du kannst also leicht selbst eine Funktion schreiben, die den 
String zeichenweise umwandelt und die Ergebnisse Byte-weise in eine 
Union mit Deiner uint64_t Variablen schreibt!

Gruß

Fred

P.S. Karl-Heinz war schneller - hätte ich mal nicht zwischendurch 
telefoniert!

von Wolfgang B. (logox2)


Lesenswert?

Also theoretischer Weiße müßte ich jetzt alles haben, aber es geht 
nicht:
1
typedef union{
2
  uint8_t b8[8];
3
  uint64_t ll;
4
} rfid_uid_t;
5
6
void main(void)
7
{
8
  uint8_t zwischen[20] = {'E', 'A', '4', 'E', '8', 'E', 'A', '4', '\r', '\n', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
9
  rfid_uid_t rfid;
10
  uint8_t l = 0;
11
12
  rfid.ll = 0;
13
14
      for(l = 0; zwischen[l] != '\r'; l++);
15
      {
16
        rfid.ll = rfid.ll * 16 + ( zwischen[l] >= '0' && zwischen[l] <= '9' ? zwischen[l] - 48 : zwischen[l] - 55 );
17
      }
18
}

In rfid.ll steht danach aber: 0x17F55555555697A7 und nicht 
0x08000000EA4E8EA4

Was mach ich bloß falsch?

von Karl H. (kbuchegg)


Lesenswert?

Wolfgang Birner wrote:

Schau dir mal diese Zeile an. Schau sie dir genau an!

>
1
>       for(l = 0; zwischen[l] != '\r'; l++);
2
>

Siehst du den ; am Ende der Zeile?


PS: Ich werde mein Lebtag nicht verstehen, wass so schön daran ist
48 anstatt '0' zu schreiben.

von Wolfgang B. (logox2)


Lesenswert?

Danke für den Hinweiß, mach mal sieht man den Wald vor Bäumen nicht.

Ich habs jetzt mal mit einer anderen ID ausprobiert (04055859EE0281) da 
steht jetzt in rfid.ll = 0x9EE027DF55556A47, was immer noch nicht 
0x0004055859EE0281 ist.

von Wolfgang B. (logox2)


Lesenswert?

Danke nochmal.

Ich hab gerade eine Möglichkeit gefunden meinen RFID-Reader binär 
auszulesen, jetzt werde ich halt mal versuchen, das zu realisieren. Die 
Sache mit der Umrechnung bekomme ich nicht gebacken.

Wolfgang

von Fred S. (Gast)


Lesenswert?

Hallo Wolfgang,

zwei Anmerkungen:
1. Ich glaube, der Fehler liegt irgendwie in der Art und Weise, wie Du 
rfid.ll anzeigst, nicht im obigen Code (nach Entfernen des ';').
2. Deine fast klammerlose Zeile rfid.ll=.... ist korrekt. Gerade beim 
Konstrukt "bedingung?a:b" gibt es aber Unterschiede zwischen 
verschiedenen Compilern (C vs. C++; ich bin diesbezüglich mal gewaltig 
reingefallen!) -- deshalb setze ich gerne Klammern (gibt ja keinen extra 
Code, macht die Sache aber übersichtlicher).

Gruß

Fred

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.