Forum: Mikrocontroller und Digitale Elektronik Verzweifelt: serielle Übertragung 7 Bit ASCII umrechnen in HEX Werte?


von Mirko (Gast)


Lesenswert?

Hallo zusammen,

ich stehe gerade irgendwie auf dem Schlauch.

Ein Prüfgerät sendet mir Modbus Telegramme, die ich einlesen will.

Laut Dokumentation erfolgt die Übermittlung mit 9600 baud, 7 Datenbits, 
2 Stopp-Bits und Even Parity. So habe ich den UART des ATMEGA328p auch 
konfiguriert...
1
// Enable Receiver, Enable Transmitter, Enable Receive Interrupt
2
UCSR0B |= (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0);
3
4
//          7 Bit        2 Stopp       Even Parity
5
UCSR0C = (1<<UCSZ01) | (1 << USBS0) | (1 << UPM01)


Der Telegraminhalt soll sein:
1
[Startzeichen]         => ':'
2
[Clientadresse]        => 1 Byte
3
[Befehl]               => 1 Byte
4
[zu lesendes Register] => 2 Byte
5
[Anzahl Bytes]         => 2 Byte
6
[LRC]                  => 1 Byte
7
[CR]                   => 1 Byte 
8
[LF]                   => 1 Byte

also bspw:
1
:0103003B0001C0[CR][LF]

Da die Übertragung als ASCII erfolgt, möchte ich das Telegram zunächst 
wieder umrechnen in die entsprechenden Werte, damit ich damit vernünftig 
arbeiten kann.

Leider scheitere ich daran irgendwie...



Im RX Interrupt werden die empfangenen ASCII Bytes zunächst mittels 
char2val() in ihren korrespondieren Wert umgerechnet.
1
ISR(USART_RX_vect) {
2
3
unsigned char rcvdByte = UDR0;
4
//  ...
5
6
uint8_t data[currentTelegramPosition] = chr2val(rcvdByte);
7
}
8
9
uint8_t chr2val(unsigned char c) {
10
11
  if (c >= '0' && c <= '9')
12
  return(c - '0');
13
14
  if (c >= 'A' && c <= 'F')
15
  return(10 + c - 'A');
16
17
  return(0);
18
}

Wenn das Telegram vollständig ist, setze ich ein Flag und werte es aus.
1
uint8_t clientAddress   = data[1]  * 16 + data[2];
2
uint8_t command         = data[3]  * 16 + data[4];
3
uint8_t startRegister_H = data[5]  * 16 + data[6];
4
uint8_t startRegister_L = data[7]  * 16 + data[8];
5
uint8_t count_H         = data[9]  * 16 + data[10];
6
uint8_t count_L         = data[11] * 16 + data[12];
7
uint8_t lrc             = data[13] * 16 + data[14];


Es werden auch Daten empfangen und die Erkennung von Telegram-Start und 
das Zählen der empfangenen Bytes klappt ebenfalls wie gewünscht.

Nur haben die umgerechneten Daten hinterher nicht den Wert, den sie laut 
ASCII Telegramm eigentlich haben sollten.

Sieht jemand spontan, wo das Problem liegen könnte?
Vermutlich sehe ich den Wald vor lauter Bäumen nicht... aber ich komme 
einfach nicht drauf.

Wäre für jede Hilfestellung dankbar.

LG, Mirko

von Jens M. (schuchkleisser)


Lesenswert?

Wo ist denn das Problem genau?
Werden die Bytes richtig empfangen?
Konvertiert chr2val richtig?

Beides ist doch mit 3 Zeilen Testcode auszuprobieren und zeigt dir wo 
der Bock ist.

: Bearbeitet durch User
von Mario M. (thelonging)


Lesenswert?

Zeige das ganze Programm, sonst kann man hier nur raten. Das Wörtchen 
'volatile' sagt Die was?

von Mirko (Gast)


Lesenswert?

Hi Jens,

vielen Dank für Deine Antwort.
Soweit konnte ich das Problem bisher leider noch eingrenzen.

Ich werde mir gleich noch einen Adapter zum "Mithören" bauen, damit ich 
sehen kann, was das Prüfgerät tatsächlich an den Controller sendet und 
dann mittels eines simplen echos vom uC schauen, was dort angekommen 
ist... vor und nach chr2val.

Aber dazu muss ich mir erst noch ein "Mithörkabel" bauen ;)

Das Resultat folgt dann hier, sobald ich den Test gemacht habe.

Danke schonmal.

LG, Mirko

von Mirko (Gast)


Lesenswert?

Mario M. schrieb:
> Zeige das ganze Programm, sonst kann man hier nur raten. Das Wörtchen
> 'volatile' sagt Die was?

Ja, ... das data Array ist global als volatile definiert...

volatile uint8_t data[17];

Das ganze Programm werde ich gleich mal auf den relevanten Teil 
verkleinern und hier noch posten.

von K. S. (the_yrr)


Lesenswert?

wo und wie ist
> currentTelegramPosition
definiert?

> uint8_t clientAddress   = data[1]  * 16 + data[2];
starten Arrays in C nicht bei 0? Oder ist das etwa absicht dass der 
erste Wert weggelassen wird?
Edit:
scheint absicht zu sein, der Start sollte ein ":" sein. eventuell fängst 
du miten in einem Frame an aufzunehmen, könnte helfen den Start des 
Frames auszuwerten und alles davor zu verwerfen.

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

K. S. schrieb:
> Oder ist das etwa absicht dass der
> erste Wert weggelassen wird?

Vielleicht liegt in data[0] das Startzeichen.
Who knows ...

von K. S. (the_yrr)


Lesenswert?

Wolfgang schrieb:
> Vielleicht liegt in data[0] das Startzeichen.
> Who knows ...
ist mir jetzt auch aufgefallen...
Allerdings sollte man das auch auswerten, falls nicht sichergestellt ist 
dass der ATmega nicht bei einem laufenden Telegram aktiviert wird, sonst 
kann da nur was Falschen rauskommen.


Mirko schrieb:
> Nur haben die umgerechneten Daten hinterher nicht den Wert, den sie laut
> ASCII Telegramm eigentlich haben sollten.
Hilfreich wär vor allem wenn du mal Beides posten könntest, muss nicht 
von derselben Transaktion sein. Nur damit man mal die Art des Fehlers 
abschätzen kann.

von B. P. (skorpionx)


Lesenswert?


von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Mirko schrieb:
> Nur haben die umgerechneten Daten hinterher nicht den Wert, den sie laut
> ASCII Telegramm eigentlich haben sollten.
Sondern welchen? Welche Werte bekommst du bei der obigen Zeile heraus?

> unsigned char rcvdByte = UDR0;
Bekommst du da noch die korrekten Zeichen herein?

> uint8_t data[currentTelegramPosition] = chr2val(rcvdByte);
Steht das genau so in deinem Code?
Was steht hinterher in dem data-Array?

: Bearbeitet durch Moderator
von HBose (Gast)


Lesenswert?

Hallo,

welches der 3 Modbus Protokolle sendet dein Meßgerät?

- RTU
- ASCII
- TCP

laut deiner Beschreibung müßte es ASCII sein. Ist es aber RTU oder TCP 
dann hast du es mit Binär Daten zu tun die anders ausgewertet werden 
müssen.

Salu Hans

von Schorsch X. (bastelschorsch)


Lesenswert?

HBose schrieb:
> - TCP

Gibt´s nur bei Ethernet-Schnittstelle.
Was steht denn in data[] nach Empfang des gesamten Telegramms ?

von Nick M. (Gast)


Lesenswert?

Schorsch X. schrieb:
>> - TCP
> Gibt´s nur bei Ethernet-Schnittstelle.

Pffffff ...
Ist halt 2 Draht-Ethernet mit 9600 7E2

von Ozvald K. (Gast)


Lesenswert?

Mirko schrieb:
> Da die Übertragung als ASCII erfolgt, möchte ich das Telegram zunächst
> wieder umrechnen in die entsprechenden Werte, damit ich damit vernünftig
> arbeiten kann.
.
.
.
> Wenn das Telegram vollständig ist, setze ich ein Flag und werte es aus.
> uint8_t clientAddress   = data[1]  * 16 + data[2];
> uint8_t command         = data[3]  * 16 + data[4];
> uint8_t startRegister_H = data[5]  * 16 + data[6];
> uint8_t startRegister_L = data[7]  * 16 + data[8];
> uint8_t count_H         = data[9]  * 16 + data[10];
> uint8_t count_L         = data[11] * 16 + data[12];
> uint8_t lrc             = data[13] * 16 + data[14];

Wenn die Werte als ASCII empfangen werden, dann ist die Umrechnung so 
falsch.
ASCII "5" = 35h.

Du müsstest 30h abziehen (48d) von den Werten, dann in Integer umrechnen

von Dirk B. (dirkb2)


Lesenswert?

Ozvald K. schrieb:
> Wenn die Werte als ASCII empfangen werden, dann ist die Umrechnung so
> falsch.
> ASCII "5" = 35h.
>
> Du müsstest 30h abziehen (48d) von den Werten, dann in Integer umrechnen

Dafür ist wohl die chr2val Funktion da.

Beitrag #6028648 wurde vom Autor gelöscht.
von Ozvald K. (Gast)


Lesenswert?

ok, der Punkt geht an euch :-)

von Eric B. (beric)


Lesenswert?

>

Mirko schrieb:
> uint8_t data[currentTelegramPosition] = chr2val(rcvdByte);

Steht das wirklich direkt so in deinem Code?
Deklaration vom ganzen Array (mit Länge currentTelegramPosition ) und 
zuweisung in einer Zeile? Ob das so gewollt ist, fehlerfrei kompiliert 
und dann auch funktioniert, wage ich zu bezweifeln!

EDIT: Zeige deinen Code, deinen vollständigen Code und nichts anderes 
als deinen Code!

: Bearbeitet durch User
von Christian M. (Gast)


Lesenswert?

Nick M. schrieb:
> Ist halt 2 Draht-Ethernet mit 9600 7E2

Ethernet ist Layer 2 im OSI-Modell, serielle Schnittstelle Layer 1...

Gruss Chregu

von Wolfgang (Gast)


Lesenswert?

Ozvald K. schrieb im Beitg #6028568:
> Wenn die Werte als ASCII empfangen werden, dann ist die Umrechnung so
> falsch.
> ASCII "5" = 35h.
>
> Du müsstest 30h abziehen (48d) von den Werten, dann in Integer umrechnen

Was meinst du, was die folgende Zeile bewirkt?
1
c - '0'

Mirko schrieb:
> if (c >= '0' && c <= '9')
>   return(c - '0');

Beitrag #6028797 wurde vom Autor gelöscht.
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.