Forum: Mikrocontroller und Digitale Elektronik Empfangene ASCII Zahlen in Hex Werte umwandeln


von Hans L. (Gast)


Lesenswert?

Hallo liebes Forum,
ich habe ein kleine Problem bei dessen Lösung ihr mir evtl. helfen 
könnt. Ich arbeite mit einem Atmega8 und C.
Ich versuche über UART einen String, den ich vorher in LabView erstellt 
habe zum µC zu schicken, ihn im µC zu zerlegen und am Ende 2 Bytes über 
SPI an ein DAC IC zu schicken um mir analoge Spannungen zu erzeugen.
Wenn ich nun die 2 Bytes direkt über SPI sende, ohne über den UART etwas 
zu empfangen:
SPI_MasterTransmit(0x02);
SPI_MasterTransmit(0x80);
Bekomme ich die korrekte Spannung ausgeben (die Kombination entspricht 
1,55 Volt).
Wenn ich mir aber nun mit Labview eine 2 und eine 80 schicke 
funktioniert das nicht mehr. Ich kann mir die 2 und die 80 auf dem 
Display anzeigen lassen um sicherzustellen, dass alles auch korrekt 
ankommt.

Wie schaffe ich es nun mir die beiden Hexzahlen in meine 
SPI_MasterTransmit Funktion einzubauen? Also quasi so:

SPI_MasterTransmit(Byte1);
SPI_MasterTransmit(Byte2);

Soweit ich es verstehe sendet mir Labview ASCII Zeichen und ich möchte 
ja reine Hex Zahlen haben. Wie kann ich mir die 2 und die 80 in Hex 
zahlen umwandeln damit sie mein DAC auch so interpretiert?
Eine 2 als ASCII ist ja auch eine 0x02 als Hex, die 80 ASCII ist ja aber 
als Hex eine 0x50, die ich ja nicht will.
Außerdem bin ich mir unsicher wie das mit den angehängten Nullen ist am 
Ende der Zeichenketten. Ich zerlege den empfangenen String mit strtok.

Ich komme hier leider nicht weiter. Herzlichen Dank für eure Tipps und 
Hilfen!
Viele Grüße
Hans

von Karl H. (kbuchegg)


Lesenswert?

Hans L. schrieb:


> Wenn ich mir aber nun mit Labview eine 2 und eine 80 schicke
> funktioniert das nicht mehr.

Was genau schickst du?

Schickst du ASCII Zeichen, also '2', '8', '0'?
Oder schickst du binär 2 Bytes vom PC an den µC?


> Soweit ich es verstehe sendet mir Labview ASCII Zeichen und ich möchte
> ja reine Hex Zahlen haben.

In erster Linie sind das erst mal nur Zahlen.
Hex ist eine SChreibweise, wie man eine Zahl darstellen kann, genauso 
wie Binär oder Dezimal. Aber Zahl ist Zahl.

> Eine 2 als ASCII ist ja auch eine 0x02 als Hex

Nö, ist sie nicht. Such dir eine ASCII Tabelle und sieh nach.

> die 80 ASCII ist ja aber
> als Hex eine 0x50, die ich ja nicht will.

Ich bin mir immer noch nicht sicher, ob du jetzt in Textform verschickst 
oder als binäre Bytes.

> Ende der Zeichenketten. Ich zerlege den empfangenen String mit strtok.

Also doch Text?

Eine einzelne Ziffer kannst du so in ihr numerisches Equivalent umformen

    number = digit - '0';

aus '2'  wird so 2
aus '4'  wird so 4
und aus '9' wird so 9
und um aus den Zeichen '2', '4' '9'  die Zahl 249 zu erzeugen, rechnet 
man dann ganz einfach:   2*100 + 4*10 + 9  und das ergibt dann die Zahl 
249




PS: Kleb nicht zu sehr an Hex. Du hast Zahlen! Du schickst vom PC einen 
String mit einer Zahl zum µC, der wandelt den String wieder in eine Zahl 
zurück, zerlegt die Zahl in ihre beiden Bytes und gibt die an den DA 
Wandler weiter. Die Textübertragung muss aber nicht in Form einer 
Hex-Darstellung sein.

Zeig mal deinen Code und was du du dem µC tatsächlich schickst.

von Martin (Gast)


Lesenswert?

Hallo Hans,

bei LabView gibts eine Funktion "Zahl nach String(Hexadezimal)". Weitere 
Umwandlungsfunktionen findest du in Funktionen: Programmierung -> String 
-> Konvertierung.

Mfg Martin

von Hans L. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
erstmal danke für die schnellen Antworten.
Ich schicke einen String mit Labview der so aussieht: 1,82!188!2!80
Übersetzt bedeutet das: Trennzeiche ist !, die Spannung soll 1,82 Volt 
sein, das entspricht entspricht nach der Berechnungsformel aus dem DAC 
Datenblatt 188 ( 2*UREFIN*188/1023=1,82 ) ; UREFIN=4,98V. Insgesamt 
braucht der DAC 16 Bit. Diese setzen sich aus 4 Upper Dummy Bits, 10 
Databits (188) und 2 extra Bits zusammen. Diese 16 Bit Kombination 
erstelle ich in Labview und teile sie in 2 x 8 Bit, das ergibt als Binär 
00000010 oder 0x02 (Byte1) und 11110000, 0xF0 (Byte2).
Wenn ich wie beschrieben das
SPI_MasterTransmit(0x02);
SPI_MasterTransmit(0x80);
oder
SPI_MasterTransmit(0b00000010);
SPI_MasterTransmit(0b11110000);
sende zeigt mein Voltmeter 1,82 Volt an.
Wenn ich aber mit Labview über den UART einen String mit der 2 und der 
80 oder Binärzahlen schicke und über SPI ausgeben will, als Byte1 und 
Byte 2 werden keine 1,82 Volt ausgegeben sondern 1,40V. Auf dem Display 
kann ich die Zahlen korrekt darstellen.
Mein Code ist im Anhang, evtl. passiert der Fehler ja schon beim Teilen 
des Strings?

von Der Neue (Gast)


Lesenswert?

Sorry, aber was soll denn sowas im Code:
1
while( (token = strtok(NULL,"!") ))
2
 {
3
 ...
4
 }

Hans L. schrieb:
> Auf dem Display kann ich die Zahlen korrekt darstellen.
Dann liegt es wahrscheinlich daran, dass Du den String im uC falsch in 
einen HEX-Wert wandelst. Du müsstest also von "80" als String irgendwie 
zu 80h kommen. Schau Dir mal die Funktion atoi in der stdlib.h an.

Hans L. schrieb:
> Mein Code ist im Anhang, evtl. passiert der Fehler ja schon beim Teilen
> des Strings?

Beim Teilen kann ich mir nicht vorstellen, wenn die Zeichen richtig auf 
dem Display wiedergegeben werden. Aber wahrscheinlich wie oben schon 
gesagt in der Wandlung von String zu HEX.

Grüße

von Karl H. (kbuchegg)


Lesenswert?

Hans L. schrieb:
> Hallo,
> erstmal danke für die schnellen Antworten.
> Ich schicke einen String mit Labview der so aussieht: 1,82!188!2!80
> Übersetzt bedeutet das: Trennzeiche ist !, die Spannung soll 1,82 Volt
> sein, das entspricht entspricht nach der Berechnungsformel aus dem DAC
> Datenblatt 188 ( 2*UREFIN*188/1023=1,82 ) ; UREFIN=4,98V. Insgesamt
> braucht der DAC 16 Bit. Diese setzen sich aus 4 Upper Dummy Bits, 10
> Databits (188) und 2 extra Bits zusammen. Diese 16 Bit Kombination
> erstelle ich in Labview und teile sie in 2 x 8 Bit, das ergibt als Binär
> 00000010 oder 0x02 (Byte1) und 11110000, 0xF0 (Byte2).

Kopfschütttel.

Machs doch nicht so kompliziert.
Dass du die 1,82 (übrigens: gewöhn dir an, dass wir mit Dezimalpunkten 
arbeiten und nicht mit einem Komma! In Programmiersprachen [ausser in 
bescheuerten Deutschen Übersetzungen und Excel] hat man immer einen 
Dezimalpunkt) noch mitschickst kann ich verstehen, weil du im µC nicht 
mit Floating Point arbeiten willst. Aber lass doch den µC die Aufteilung 
machen. Rechne im Labview aus

    1.82 * 1023 / 2*UREFIN   -> x

und diese Zahl (korrigiert um die beiden Extrabits) schickst du zum µC. 
Der muss sowieso aus dem Text erst mal eine Zahl machen und die in die 
Bytes zerlegen, dass er sie zum DAC weiter geben kann. Da brauchst du 
dir wirklich keinen Kopf machen, dass du ihm das alles in Bytes 
aufbereitest. Das kostet den µC nur ein müdes Lächeln die Aufteilung zu 
machen. Und zum Testen per Textsenden aus Hyperterminal ist es auch 
einfacher.

d.h. du schickst zum µC

  1,82!640

fertig.

Auf dem µC brauchst du auch kein strtok um den Text kompliziert 
auseinanderzunehmen.

Der erste Teil ist klar: Vom Stringbeginn bis zum ! ist das Text, der 
auf die Anzeige muss. D.h. du fängst vorne in der Textzeile an und 
schiebst alle Zeichen auf das LCD, bis du auf den '!' stösst.
Nach dem '!' kommt die Zahl, die zum DAC muss. Also holt man sich alle 
Zeichen, die zur Zahl gehören und baut sich die Zahl wieder als 
numerische Zahl zusammen. Die wird dann in High-Byte und Low-Byte 
aufgeteilt und zum DAC geschoben.
1
  uint16_t Value;
2
  uint8_t HighByte, LowByte;
3
  uint8_t charIndex;
4
5
  while(1)
6
  {
7
    charIndex = 0;
8
9
    // der erste Teil ist der anzuzeigende Text
10
    lcd_setcursor(0,1);
11
    while( stringbuffer[charIndex] && stringbuffer[charIndex] != '!' )
12
      lcd_char( stringbuffer[charIndex++] );
13
14
    // den ! überlesen
15
    charIndex++;
16
17
    // nach dem ! geht es mit dem Wert weiter, der zum DAC muss
18
    // also erst mal aus dem Text eine numerische Zahl formen.
19
    // da die Zahl dezimal übertragen wird, setzen wir sie auch
20
    // wieder dezimal zusammen
21
    Value = 0;
22
    while( isdigit( stringbuffer[charIndex] ) )
23
      Value = 10*Value + stringbuffer[charIndex++] - '0';
24
25
    // den Wert in 2 Bytes aufteilen
26
    HighByte = Value >> 8;
27
    LowByte  = Value;
28
29
    // und zum DAC schicken
30
    SPI_MasterTransmit( HighByte );
31
    SPI_MasterTransmit( LowByte );
32
  }

ferig. Mehr brauchts dazu nicht.

Klemm dich an dein Hyperterminal (oder was auch immer du sonst noch 
benutzt) und schick an den µC den Text

1.82!640(Return)

und die 640 werden (aufgeteilt) in Bytes an den DAC weitergegeben. (als 
ein Byte mit dem Wert 0x02 und ein Byte mit dem Wert 0x80. Dran denken 
Hex ist NUR eine Schreibweise! In erster Linie hast du eine Zahl. Ob du 
sie als dezimal 640 schreibst oder hex 0x0280 ist gehupft wie 
gesprungen. Es ist immer dieselbe Zahl und hat daher auch dasselbe 
Bitmuster)

Deine UART Empfangsfunktion funktioniert? So dass du in Stringbuffer 
IMMER (das ist zu jedem Zeitpunkt, selbst wenn eine Übertragung gerade 
im Gange ist) eine komplette Zeile zur Verfügung hast, die sich erst mit 
dem Empfang des Zeilenende Zeichens (zb einem Return) ändert? Denn wenn 
du einen String zerlegst, dann sollte der auch tunlichst vollständig 
sein.

Und achte ein wenig mehr auf deine Programmformatierung! Speziell die 
Einrückungen. Es ist nämlich mehr als Zufall, dass immer ausgerechnet 
diejenigen mit dem scheuslichsten Code immer die sind, bei denen nix 
funktioniert.

von Hans L. (Gast)


Lesenswert?

Hallo,
herzlichen Dank für die super Hilfe Karl Heinz. Das Programm 
funktioniert nun einwandfrei. Ich habe eine Weile gebraucht um das 
Programm zu verstehen, deshalb die späte Antwort.

@ Der Neue:
Was soll das?
"Sorry, aber was soll denn sowas im Code:"
Wie soll ich mit diesem Satz meine Fehler korrigieren oder verstehen wo 
meine Fehler liegen? Wenn ich es besser gewusst hätte, hätte ich es so 
nicht gemacht oder müsste hier gar nicht nachfragen.
Mit so einem Satz wird hier Niemandem geholfen!
Karl Heinz Antwort war absolut vorbildlich und zielführend. Ich habe 
meine Fehler erkannt, das Programm läuft und weitere Leser können Fehler 
durch diesen Thread evtl. vermeiden oder ihre Programme verbessern ohne 
einen neuen Thread zu erröffnen.

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.