Hallo Gemeinde,
ich stehe gerade irgendwie auf dem Schlauch...
In einer Modbus-Anwendung wird der HEX Wert in Form von ASCI Zeichen
übertragen....
Beispiel:
unsigned char zeichen = 0x48;
wird übertragen als ['4','8'].
Wenn ich das Modbus Telegram nun wieder einlese, möchte diese beiden
Bytes wieder zu einem 0x48 umwandeln... aber wie?
Kann mir vielleicht jemand auf die Sprünge helfen?
LG, sunny
Hallo,
ziehen jeweils von jedem Zeichen der Dezimalwert von '0' ab und addiere
die Ziffer mit ihrer Wertigkeit und addiere sie.
Zahl a = 10^1*a1 + 10^0*a0
Jede dezimal Zahl x lässt sich auf diese Art und Weise auf Basis von
*10^n* darstellen!
Hey,
vielen Dank für eure Antworten.
Ich habe das mal ausprobiert und erhalte leider nicht das Ergebnis, was
ich erhofft habe.
Was mache ich denn wohl falsch?
Funktioniert bis 32-bittige Werte (8 digits), und sowohl für Groß- als
auch Kleinschreibung.
Großartige Plausibilitätsprüfung wird zugunsten der Perfomance nicht
gemacht.
"G7" ergäbe natürlich Unsinn.
Sunny schrieb:> Ich habe das mal ausprobiert und erhalte leider nicht das Ergebnis, was> ich erhofft habe.
Guck dir mal als Grundlage in einer ASCII-Tabelle die Werte der Ziffern
'0'..'9' und die der Buchstaben 'A'..'F' bzw. 'a'..'f' an.
Die Umwandlung Klein- nach Großbuchstaben kann man einfach durch
Maskierung des 0x20-Bits machen, ganz ohne große Fallunterscheidung.
Aus
Joe F. schrieb:> if (*str >= 'A')> val |= *str - 'A' + 10;> else if (*str >= 'a')> val |= *str - 'a' + 10;
wird dann
if (*str >= 'A')
val |= (*str & ~0x20) - 'A' + 10;
Wolfgang schrieb:> Die Umwandlung Klein- nach Großbuchstaben kann man einfach durch> Maskierung des 0x20-Bits machen, ganz ohne große Fallunterscheidung.
Dafür gibt es in der C-Umgebung auch die Macros tolower und toupper.
Rufus Τ. F. schrieb:> die Macros tolower und toupper
Bin gar nicht sicher, ob das wirklich Macros sind.
Schneller als ein if() werden die auch nicht sein, und im ungünstigsten
Fall knallen die eine ziemlich große Lookuptable in die Firmware.
Hatte allerdings noch einen Fehler in hex2bin, denn 'a'-'z' hat höhere
Ascii Werte als 'A'-'Z'.
Wolfgang schlug ein schnelles toupper() vor, genauso einfach wäre dann
ein tolower(), indem man das 6. Bit auf 1 zwingt.
Sunny schrieb:> unsigned char wert = 16^1 * modbus[0] + 16^0 * modbus[1];
Hier klafft die Schreibweise von Basic und C auseinander. Der Dir den
Vorschlag gemacht hat, meinte 16 hoch 1 also. In Basic schreibt man das
auch 16^1. In C bedeutet ^ jedoch bitweises exklusiv oder.
0
16 = 1
1
16 = 16
16 exklusiv oder 0 = 16
16 exklusiv oder 1 = 17
das ergibt natürlich nur Grütze.
1
unsignedcharwert=16*modbus[0]+modbus[1];
Denke ich, kann man schreiben, ohne es so stark vereinfacht zu haben,
dass es niemand mehr nachvollziehen kann.
Hallo zusammen,
vielen Dank für eure Antworten.
Da ich Kleinbuchstaben im Telegramm nicht erhalte, habe ich mir nun mit
Eurer Hilfe folgende Funktion geschrieben:
Sunny schrieb:> Damit funktioniert das Vergleichen der Werte prima.
Was bringen dir die ganzen Vergleiche?
Wenn die Daten ok sind, kommen keine anderen Zeichen vor und wenn die
Daten nicht ok sind, gibst du fehlerhafte Daten aus deiner Funktion
zurück, ohne es zu merken. Wenn du schon die anderen Fälle aussortierst,
sollte ein Fehlerzähler hochlaufen, damit man merkt, dass die
zurückgegebenen 0-en falsch sind. Oder ist in deinen Modbustelegrammen
ausgeschlossen, dass der Fehlerwert 0 auch als übertragene "0" vorkommt?
Sunny schrieb:> Da ich Kleinbuchstaben im Telegramm nicht erhalte
Na, dann hätte ich noch diesen Vorschlag für ein Macro mit einer
Lookup-Table.
Da zwischen Zahlen und Großbuchstaben nur 7 Zeichen liegen, ist die
Speicherplatzverschwendung vernachlässigbar.
Hallo,
@Joe: Das sieht auch interessant und übersichtlich aus... werde das mal
ausprobieren und dann evtl. die Funktion durch das Makro ersetzen.
@Wolfgang:
Im Grunde ist mir der Inhalt des Modbus Telegrams garnicht so wichtig,
weil ich eigentlich nur wissen will, ob überhaupt ein vollständiges
Telegram angekommen ist.
Allerdings ist im Telegramm eine LRC Summe enthalten, die ich noch
prüfen will, bevor ich die Daten weiterreiche.
Das LRC wird ebenfalls Form von 2 ASCII Zeichen übertragen, z.B. ['3',
'F'], die aber ein 0x3F repräsentieren...
Wenn also das Modbus Telegram z.B. so aussieht:
:0103000600043F[CR][LF] (alles ASCII Zeichen, wohlbemerkt)
Dann muss ich ja selbst auch ein LRC bilden um es mit dem übertragenen
LRC vergleichen zu können.
Dafür die Umrechnung der ASCII Zeichen in entsprechende hex Werte.
Sollte ein Byte im Telegramm kaputt sein und die chr2val() Funktion eine
0 zurückgeben, würde ja auch der LRC Check fehlschlagen und das
Telegramm wird aussortiert.
So zumindest meine Theorie ;)
LG, Sunny
Sunny schrieb:> @Joe: Das sieht auch interessant und übersichtlich aus... werde das mal> ausprobieren
Der Nachteil dieser Lösung ist, sie setzt voraus, dass keine unerlaubten
Zeichen verwendet werden. Ansonsten entstehen Array-Indizes, die
ausserhalb des Arrays liegen. Kann gutgehen, kann aber auch das Programm
zum Absturz bringen.
Da bei einer Datenübertragung immer auch mit Fehlern gerechnet werden
muss, hier nochmal eine Alternative der Makro-Lösung, die zumindest das
Programm nicht crahed.
Bei 'illegalen' Zeichen kommt dann einfach ein falscher Wert raus.
Hi
Wie schon geschrieben wurde, werden von den Zeichen nur der Wert von '0'
abgezogen.
Wenn das Ergebnis dann noch >9 ist, werden weitere 7 abgezogen.
Wenn das Ergebnis immer noch >15 ist, ziehen wir 32 ab
"0" 0x30
"9" 0x39
"A" 0x41
"F" 0x46
"a" 0x61
"z" 0x66
0-9 wird zu Wert 0...9
A Wird zu Wert 17, ist somit >9, wir ziehen 7 weitere ab -> 10
a wird dadurch aber nur zu 42, ist somit >15, wir ziehen 32 ab -> 10
wenn jetzt immer noch Werte >15 vorliegen, war das Zeichen nicht für uns
bestimmt ;)
MfG
Wenn ich die Syntax halbwegs gefressen habe, könnte Das passen:
1
unsigned char chr2val(unsigned char c) {
2
wert=c-'0'
3
if (wert>9)
4
wert=wert-7;
5
if (wert>15)
6
wert=wert-32;
7
}
8
}
9
if (wert>15)
10
wert=0xff;
11
}
12
return(wert);
13
}
Im Fehlerfall liefert die Funktion 0xFF, statt einer 0