Forum: Mikrocontroller und Digitale Elektronik Hex in String umwandeln


von Sebastian (Gast)


Lesenswert?

Hallo zusammen,

ich habe folgendes Problem und stehe im Moment ein wenig auf der 
Leitung...

Ich habe 8 Byte Daten. In Hex würden die nur mal als Beispiel wie folgt 
aussehen.

88 77 66 55 44 33 22 11

Nun wollte ich diese Daten so vom µC per RS232 an den PC senden und in 
einem Terminal Programm ausgeben, so wie es oben steht. Wenn ich die 
Daten einfach so sende, wird nur Mist angezeigt, klar, weil die Werte 
falsch interpretiert werden, bzw nicht so, wie ich das möchte. Ich 
müsste die Daten ja in einen String umwandeln, um es dann zu senden. Das 
ganze müsste dann in Hex doch so aussehen 38 38 für angezeigte 88 im 
Terminalprogramm. Richtig?

Allerdings komm ich nicht drauf, wie ich das ganze entsprechend 
umwandle. Wäre klasse, wenn mir da jemand auf die Sprünge helfen könnte.

Vielen Dank.

Grüße
Sebastian

von Justus S. (jussa)


Lesenswert?

in C:
char s[17];
zahl = 0x88 77 66 55 44 33 22 11;
uart_puts(utoa(zahl,s,16));

von Sebastian (Gast)


Lesenswert?

Hallo,

vielen Dank erst einmal, aber irgendwie gibt mein Kompiler keine 
Funktion utoa oder ähnliches her, nur in umgekehrter Richtung. Ich 
verwende einen Kompiler von Cosmic für einen HC12 von Freescale.

Hat jemand vielleicht eine andere Lösung oder schon einmal eine eigene 
Funktion geschrieben oder so?

Vielen Dank!

Grüße
Sebastian

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Einige Varianten von printf können das auch.

unsigned char a=0x20, b=0x25, c=0x31;

printf("Hier kommen die Zahlen: %x %x %x", a, b, c);

Grüße,

Peter

von Eddy C. (chrisi)


Lesenswert?

Ich schätze, utoa reicht eh nicht, weil

a) Kleinbuchstaben gewandelt werden (mag akzeptabel sein)
b) Vornullen unterdrückt werden

Leider werden solche Details aus dem Beispiel nicht deutlich.

Mache folgendes:

Schreib eine Routine, die einen Nibble (=ein Hex-Zeichen) sendet:

void SendNibble(unsigned char Nibble)
{
   // Preserve range
   Nibble &= 0x0F;
   uart_putchar(Nibble <= 9 ? '0'+Nibble : 'A'+Nibble-10);
}

Und eine Routine zum Byte senden:

void SendByte(unsigned char Byte)
{
   // Send upper nibble
   SendNibble(Byte >> 4);
   // Send lower nibble
   SendNibble(Byte);
}

Feddisch. Da mögen jetzt noch Compilerfehler drin sein ;-)

von STK500-Besitzer (Gast)


Lesenswert?

Kann man itoa nicht auch mit Basis 16 betreiben?

von !nullchecker (Gast)


Lesenswert?

printf ist wohl die einfachste Lösung...

Dein Problem ist wohl schon in den 70'igern gelöst worden und in der 
ANSI C-Library berücksichtig worden.


http://www.cplusplus.com/reference/clibrary/cstdio/printf.html

von Sebastian (Gast)


Lesenswert?

Hallo,

ich habe das genze nun mit printf gelöst. Allerdings habe ich noch ein 
Problem dabei. Ich habe z.B. die Hex-Werte 11 22 33 44 55 66 77 88, 
geseichert in

CAN0TXFG[4]....CAN0TXFG[11]

1
for(ii = 0; ii < 8; ii++)
2
    {    
3
        zahl = CAN0TXFG[ii+4];
4
        Send(printf("%x", CAN0TXFG[ii+4]));
5
    }
Allerdings stimmt die Ausgabe dabei nicht. Es kommt raus:
0  22 33 44 55 66 77 88

Egal was ich mache und ausgeben lasse, der erste Wert ist immer die 
0...sollte in diesem Fall eigentlich eine 11 sein. Egal was ich mache, 
es wird als erstes immer eine 0 ausgegeben beim ersten 
Schleifendurchlauf. Hat jemand eine Idee, woran das liegen könnte oder 
was ich falsch mache?

Vielen Dank!

Grüße
Sebastian

von Ak T. (aktronik)


Lesenswert?

@Sebastian

für Strings:
1
char cHexValue = 0xf3;
2
CString s;
3
4
s.Format("%02X, cHexValue);

für Arrays:
1
char cArray[128];
2
char cHex[8];
3
4
sprintf(cArray, "%02X %02X %02X %02X %02X %02X %02X %02X",
5
  cHex[0],cHex[1],cHex[2],cHex[3],cHex[4],cHex[5],cHex[6],cHex[7]);

MfG
Ak Tronik

von Sebastian (Gast)


Lesenswert?

Hallo,

ja, das habe ich soweit, ich habe nur das Problem, dass wenn ich nun 
mein Array wie oben angegeben in einer Schleife ausgebe, ist der erste 
Wert immer 00 egal ob da 0x11, 0x22, 0x99 drin steht. Beim ersten 
Schleifendurchlauf wird immer 00 ausgegeben. Ich habe nun einmal die 
Schleife durch 8 Zeilen  der Art PutStSCI0(printf("%02X", CAN0TXFG[4])); 
ersetzt  CAN0TXFG[4]...CAN0TXFG[11]. der erste Wert ist immer 00. Wenn 
ich dann die Reihenfolge der Ausgabe ändere, ist immer der erste Wert 
der ausgegeben wird 00.
CAN0TXFG[4]...CAN0TXFG[11] -> 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
Ausgabe 00 22 33 44 55 66 77 88

CAN0TXFG[5]...CAN0TXFG[11]CAN0TXFG[4]
0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x11

Ausgabe 00 33 44 55 66 77 88 11

Jemand eine Idee, was das sein könnte?

Vielen Dank!
Grüße
Sebastian

von Ak T. (aktronik)


Lesenswert?

@Sebastian

und wenn Du sprintf oder CString verwendest.

Oder poste mal den kompletten Codeschnippsel.

MfG
Ak Tronik

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Wie wäre es hiermit, ohne printf etc. und für ein Byte:
1
uint8_t n2hex(uint8_t val)
2
{
3
  if (val > 9){
4
    return val + 'A' - 10;
5
  }
6
  else{
7
  return val + '0';
8
  }
9
}
10
11
void byte2hex(uint8_t val,char *str)
12
{
13
  *str++ = n2hex(val >> 4);
14
  *str = n2hex(val & 0x0f);
15
}
16
17
...
18
19
byte2hex(byte_wert, s);

von Sebastian (Gast)


Lesenswert?

Hallo,

mit sprintf erhalte ich gar keine Ausgabe.

Hier mal der Codeschnipsel...
1
    PutStSCI0(printf("%02X", CAN0TXFG[5]));  // 0x22
2
    PutStSCI0(printf("%02X", CAN0TXFG[6]));  // 0x33
3
    PutStSCI0(printf("%02X", CAN0TXFG[7]));  // 0x44
4
    PutStSCI0(printf("%02X", CAN0TXFG[4]));  // 0x11
5
    PutStSCI0(printf("%02X", CAN0TXFG[8]));  // 0x55
6
    PutStSCI0(printf("%02X", CAN0TXFG[9]));  // 0x66
7
    PutStSCI0(printf("%02X", CAN0TXFG[10])); // 0x77
8
    PutStSCI0(printf("%02X", CAN0TXFG[11])); // 0x88
9
    /*for(ii = 0; ii < NumBytes; ii++)
10
    {    
11
        zahl = CAN0TXFG[ii+4];
12
        PutStSCI0(printf("%02X", CAN0TXFG[ii+4]));
13
    }*/

Die Ausgabe ist aber: 00 33 44 11 55 66 77 88 Egal in welcher 
Reihenfolge das ganze ausgegeben wird, die erste Ausgabe ist immer 00!!!

>Wie wäre es hiermit, ohne printf etc. und für ein Byte:
>
>uint8_t n2hex(uint8_t val)
>{
>  if (val > 9){
>    return val + 'A' - 10;
>  }
>  else{
>  return val + '0';
>  }
>}
>
>void byte2hex(uint8_t val,char *str)
>{
>  *str++ = n2hex(val >> 4);
>  *str = n2hex(val & 0x0f);
>}
>
>...
>
>byte2hex(byte_wert, s);

..-> noch nicht getestet...

Vielen Dank!

Grüße
Sebastian

von Tommy (Gast)


Lesenswert?

Hallo Sebastian,

Könnte es sein, dass Du nach dem Einschalten der
Betriebsspannung gleich anfängst über RS232 zu
senden? Denk dran, dass der MAY232 eine Zeit braucht,
bis die Ladungspumpen die Spannungen aufgebaut haben.
Mach doch mal einen richtig langen delay bevor Du
anfängst zu senden. Ruhig 1,2,3... Sekunden.

von Tommy (Gast)


Lesenswert?

Uups, das sollte natürlich MAX232 heissen...

von Sebastian (Gast)


Lesenswert?

Hallo,

> Könnte es sein, dass Du nach dem Einschalten der
> Betriebsspannung gleich anfängst über RS232 zu
> senden?

Ich sende schon voher Text. Der wird einwandfrei übertragen.

Ich habe mal folgendes probiert:
1
    zahl= 170;   // 0xAA
2
    PutStSCI0(printf("%02X", zahl));
3
    PutStSCI0(printf("%02X", CAN0TXFG[4]));  // 0x11
4
    PutStSCI0(printf("%02X", CAN0TXFG[5]));  // 0x22
5
    PutStSCI0(printf("%02X", CAN0TXFG[6]));  // 0x33
6
    PutStSCI0(printf("%02X", CAN0TXFG[7]));  // 0x44
7
    PutStSCI0(printf("%02X", CAN0TXFG[8]));  // 0x55
8
    PutStSCI0(printf("%02X", CAN0TXFG[9]));  // 0x66
9
    PutStSCI0(printf("%02X", CAN0TXFG[10])); // 0x77
10
    PutStSCI0(printf("%02X", CAN0TXFG[11])); // 0x88

Dabei sieht die Ausganbe dann wie folgt aus:
AA 11 22 33 44 55 66 77 88, also so, wie es sein soll. Nehme ich 
PutStSCI0(printf("%02X", zahl)); wieder raus gehts wieder so los 00 22 
33 44....

Grüße
Sebastian

von Sebastian (Gast)


Lesenswert?

Hallo,

mit
1
zahl= 170;
2
PutStSCI0(printf("%02X", zahl));
3
for(ii = 0; ii < NumBytes; ii++)
4
    {    
5
        PutStSCI0(printf("%02X", CAN0TXFG[ii+4]));
6
    }

geht es auch. Lässt man PutStSCI0(printf("%02X", zahl)); weg, fängt auch 
hier das ganze wieder mit 00 22 33 44...... an

Grüße
Sebastian

von Karl H. (kbuchegg)


Lesenswert?

Sebastian wrote:

> Dabei sieht die Ausganbe dann wie folgt aus:
> AA 11 22 33 44 55 66 77 88, also so, wie es sein soll. Nehme ich
> PutStSCI0(printf("%02X", zahl)); wieder raus gehts wieder so los 00 22
> 33 44....

Zeig mal mehr Code (am besten ein vollständiges kleines(!) Programm, 
welches den Fehler zeigt). Aus dem Snippet kann man nicht wirklich was 
entnehmen.

von Sebastian (Gast)


Lesenswert?

Hallo,

das Programm ist zu umfangreich, um es hier alles anzugeben. Die 
Funktion, in der das ganze ablaufen soll, ist folgende:
1
void SendCANMessage(unsigned char NumBytes, unsigned char *TXBuf)
2
{
3
    unsigned char NACAN, ii;
4
    unsigned char data[9];
5
    unsigned int zahl;
6
    PutStSCI0("Nachricht senden (hex): ");
7
    while(!CAN0TFLG);                   // Wait for available buffer
8
    NACAN = CAN0TFLG;                   // Get the next aveilable CAN buffer
9
    CAN0TBSEL = NACAN;
10
11
    CAN0TXFG[0] = 0x00;                 // Set the Transmit ID
12
    CAN0TXFG[1]=  0x00;       // ... Identifier: 00, höchste Priorität
13
    if(NumBytes > 8)
14
        NumBytes = 8;
15
    for(ii = 0; ii < NumBytes; ii++)
16
        CAN0TXFG[ii+4] = *TXBuf++;            // Store the data
17
                                              // Data Segment Registers (DSR0-7); site 42
18
    CAN0TXFG[12] = NumBytes;                  // Set Number of Bytes to send
19
                                              // Data Lenght Register (DLR); Site 42
20
    NACAN = CAN0TBSEL;
21
    CAN0TFLG = NACAN;                         // Start transmission
22
    zahl= 170;
23
    PutStSCI0(printf("%02X", zahl));
24
    /*PutStSCI0(printf("%02X", CAN0TXFG[4]));
25
    PutStSCI0(printf("%02X", CAN0TXFG[5]));
26
    PutStSCI0(printf("%02X", CAN0TXFG[6]));
27
    PutStSCI0(printf("%02X", CAN0TXFG[7]));
28
    PutStSCI0(printf("%02X", CAN0TXFG[8]));
29
    PutStSCI0(printf("%02X", CAN0TXFG[9]));
30
    PutStSCI0(printf("%02X", CAN0TXFG[10]));
31
    PutStSCI0(printf("%02X", CAN0TXFG[11]));*/
32
    for(ii = 0; ii < NumBytes; ii++)
33
    {    
34
        zahl = CAN0TXFG[ii+4];
35
        PutStSCI0(printf("%02X", zahl));
36
    }
37
    PutStSCI0(" OK\n");
38
}

Das ganze gehört zu einem Projekt in dem es unter anderem um CAN geht. 
Mit der obigen Funktion werden eben CAN-Botschafen gesendet. Das 
funktioniert auch prima. Weiter sollen halt bestimmte Daten über RS232 
an den PC gesendet werden, in diesem Fall eben die per CAN gesendeten 
Daten.

So wie es oben steht funktioniert das ganze. die ausgabe sieht dann wie 
folgt aus:
AA 11 22 33 44 55 66 77 88 (die AA kommen aus der zahl= 170; der Rest 
ist eben in CAN0TXFG[4]...CAN0TXFG[11] gespeichert.
Wenn ich nun die Zeile "PutStSCI0(printf("%02X", zahl));" 
auskommentiere, sieht die Ausgabe wie folgt aus: 00 22 33 44 55 66 77 
88.

Alle anderen Textausgaben usw. funktionieren einwandfrei. Werte im Array 
habe ich mehrfach überprüft. Die stimmen, also sind z.B. 11 auch wenn 
die 00 ausgegeben wird. Das ganze stimmt nur, wenn vor der eigentlichen 
Ausgabe schon was mit PutStSCI0(printf("%02X", zahl)); ausgegeben wird.

Grüße
Sebastian

von Karl H. (kbuchegg)


Lesenswert?

OK.

Ich kann aus dem Codeschnipsel immer noch nicht erkennen, ob CAN0TXCFG 
korrekte Werte enthält oder nicht, ob du das Array überläufst oder 
nicht, etc.

Aber seis drum.

WO hast du eigentlich diesen Schwachsinn her
    PutStSCI0(printf("%02X", zahl));

printf dazu einzusetzen, einen temporären String aufzubauen, der von 
printf verwaltet wird, ist ja wohl mehr als gefährlich. Ausserdem stimmt 
der Return Wert von printf nicht. Alles in allem, sollte man dir dafür 
alleine schon einen nassen Fetzen um den Kopf schlagen :-)

Eine Stringausgabe kann man sich zb so vorbereiten

     char Buffer[20];

     sprintf( Buffer, "%02X", zahl );

jetzt hast du in Buffer einen String, den du mit der Stringausgabe 
ausgeben kannst:

     PutStSCI0( Buffer );

von Sebastian (Gast)


Lesenswert?

Hallo,

ich habe das ganze mal wie folgt geändert:
1
    zahl= 170;
2
    sprintf(Buffer, "%02X", zahl) 
3
    PutStSCI0(Buffer);
4
    for(ii = 0; ii < NumBytes; ii++)
5
    {    
6
         zahl = CAN0TXFG[ii+4];
7
         sprintf( Buffer, "%02X", zahl );
8
         PutStSCI0(Buffer);
9
    }
Die Ausgabe hierbei ist AA1122334455667788.

Lässt man hier die Zeilen vor der Schleife weg, ergibt sich die folgende 
Ausgabe: 001122334455667788.

Dies sind die Daten, die gesendet werden sollen, diese werden ja an die 
obige Funktion übergeben:
1
   TXBuf[0]= 0x11;
2
   TXBuf[1]= 0x22;
3
   TXBuf[2]= 0x33;
4
   TXBuf[3]= 0x44;
5
   TXBuf[4]= 0x55;
6
   TXBuf[5]= 0x66;
7
   TXBuf[6]= 0x77; 
8
   TXBuf[7]= 0x88;

Grüße
Sebastian

von Karl H. (kbuchegg)


Lesenswert?

Sebastian wrote:

> Lässt man hier die Zeilen vor der Schleife weg, ergibt sich die folgende
> Ausgabe: 001122334455667788.

mysteriös. (und ich mein das wirklich nicht ironisch)


Bei solch mysteriösen Dingen ist es oft so, dass der eigentliche Fehler 
ganz woanders steckt und du nur die Auswirkungen siehst. Wird dir wohl 
nichts anderes übrig bleiben, als abspecken, abspecken, abspecken, bis 
der Fehler verschwindet. Die Wahrscheinlichkeit ist hoch, dass der 
eigentliche Fehler im zuletzt abgespeckten Bereich war. Fehler 
korrigieren und das abgespeckte (=auskommentierte) wieder stückchenweise 
freigeben und Ausschau nach sonstigen ungewöhnlichen Effekten halten.

von P. S. (Gast)


Lesenswert?

Sebastian wrote:

> das Programm ist zu umfangreich, um es hier alles anzugeben. Die
> Funktion, in der das ganze ablaufen soll, ist folgende:

Dann reduziere es. So geht das nunmal beim Debugging.

von Oha (Gast)


Lesenswert?

>Einige Varianten von printf können das auch.

Das printf monster ist nicht totzukriegen. Wenn man das in ein 
embedded projekt hinzulinkt kann man gleich den Strick bestellen...

von Sebastian (Gast)


Lesenswert?

Hallo,

> Das printf monster ist nicht totzukriegen. Wenn man das in ein
> embedded projekt hinzulinkt kann man gleich den Strick bestellen...


Andere Vorschläge?

Ich glaube, ich habe den Fehler gefunden. Es liegt anscheinend daran, 
dass ich die Daten vorher schon einmal verarbeite/verwende. Ich verwende 
nun nicht die Register CAN0TXFG[ii+4] usw. sondern direkt *TXBuf++. 
Damit funktioniert es nun.

Vielen Dank!

Grüße
Sebastian

von Markus S. (bastetfur)


Lesenswert?

Hmm...
Hier mein, eben aus der Hand geschüttelter, Vorschlag:
1
unsigned char hex2chrtab[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
2
char Hex2String(unsigned char i, char *out)
3
{
4
  out[1] = hex2chrtab[i & 15];
5
  out[0] = hex2chrtab[((i & 240)>>4)];
6
  out[2] = '\0';
7
  return i;
8
}
Ungetestet, sollte aber so tun.
Am besten vorher mit einem normalem C Programm testen.
Vorteil meiner Lösung: Keine externe Lib. ;)

von Sebastian (Gast)


Lesenswert?

Hallo,

vielen Dank!

> unsigned char hex2chrtab[] =
> {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
> char Hex2String(unsigned char i, char *out)
>
>   out[1] = hex2chrtab[i & 15];
>   out[0] = hex2chrtab[((i & 240)>>4)];
>   out[2] = '\0';
>   return i;
> }

Das funktioniert auch!!

Grüße
Sebastian

von Markus S. (bastetfur)


Lesenswert?

Freut mich, kann ich also doch programmieren. :D

Kann das einer der C Cracks noch kleiner/schneller machen?

von Peter (Gast)


Lesenswert?

>Kann das einer der C Cracks noch kleiner/schneller machen?
out[1] = (i & 15)<10?(i & 15) + '0':(i & 15) + 'A'
out[0] = (i & 240)>>4)?(i & 240)>>4) + '0':(i & 240)>>4) + 'A'
out[2] = '\0';

Bei schneller bin ich mir nicht sicher, kommt auf den optimieren an, 
eventuell mit hilfsvariable machen.

von Niffko _. (niffko)


Lesenswert?

Peter (Gast) schrieb:
> out[1] = (i & 15)<10?(i & 15) + '0':(i & 15) + 'A'
> out[0] = (i & 240)>>4)?(i & 240)>>4) + '0':(i & 240)>>4) + 'A'
> out[2] = '\0';

Ja, der Fred ist schon etwas älter ... aber da mir dieser Codeschnipsel 
hier am meisten weiter geholfen hat - obwohl er so nicht funktioniert -, 
nachfolgend nochmal die leicht bearbeitete Version für's Protokoll.

1
out[1] = (i & 15)<10 ? (i & 15)+'0' : (i & 15)+'7';
2
out[0] = ((i & 240)>>4)<10 ? ((i & 240)>>4)+'0' : ((i & 240)>>4)+'7';
3
out[2] = '\0';

//Niffko

von Erich (Gast)


Lesenswert?

Zum Ursprungsproblem:
>Nun wollte ich diese Daten so vom µC per RS232 an den PC senden
>und in einem Terminal Programm ausgeben, (...)

Dann solltest du ganz einfach ein Terminalprogramm nehmen, welches 
konfiguriert werden kann, alle ankommenden Bytes (0x00 ... 0xFF)
als jeweils 2 Asciizeichen + nachfolgendes Leerzeichen darzustellen.

Lies mal hier weiter
Beitrag "Neues Terminal-Programm für Windows"
bzw.
http://www.der-hammer.info/terminal/index.htm

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.