Forum: Mikrocontroller und Digitale Elektronik Ökonomische Datenübertragung


von cerberus (Gast)


Lesenswert?

Hallo Freunde der "schwarzen Magie"
wo ich gerade dabei bin ein paar Daten zwischen den Systemen hin und her 
zu schicken ist mir etwas aufgefallen.
Meine bisherige Methode zur Datenverschiftung ist etwas ineffizient.
da wird eine einfache float-Variable, die doch mit 4 Byte auskommt mit 
speicherfressenden Befehlen, wie sprintf in -1.23456  in ganze 8 Byte 
aufgebauscht um dann zeichenweise ins UDR - Register verschoben zu 
werden, wo sie auf der anderen Seite Zeichen für Zeichen in einem String 
landet um mit hanebüchenem Aufwand oder atoi wieder in ihre 4 Byte Größe 
reduziert zu werden.
Aber wie macht man es besser?
Wie kann man das Bytemuster einer Variablen (int float ...) in einen 
String verwandeln den man via UART, CAN oder weiss der Teufel was 
verschicken kann und am Ende der Nahrungskette wieder zurück in eine 
float, int  ... ??

von Christian R. (supachris)


Lesenswert?

Wozu denn als String? Ich übertrage immer ganze Variablen und Strukte. 
Einfach einen pointer auf die variable setzen und dann mit dem 
sizeof-Operator die Größe in Bytes bestimmen, die übertragen werden 
muss. Dann halt (z.B. für einen Float-wert) 4 Bytes übertragen. Auf der 
anderen Seite genau andersrum. Da muss man natürlich immer genau wissen, 
was man überträgt. Aber das weiß man in aller regel ja.
Auch mit kompletten Strukten, die Variablen und Arrays enthalten klappt 
das bestens.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

union aus float und 4 char...

union{
 float Zahl;
 char Zeichen[4];
};

von cerberus (Gast)


Lesenswert?

???
Ich weiß, "Kanningham und Richie" Seite 155  oder wie das hier 
tausendfach zitierte Standardwerk heißt. Geht es ggf. etwas 
ausführlicher bitte?

von 6642 (Gast)


Lesenswert?

Ich lass den PC mit float rechnen. Meine Devices brauchen keinen Float. 
Da werden die Werte als integer ausgetauscht, und die Anzeige wird aufm 
PC nach float umgerechnet. Dabei spar ich auch gleich noch die Float 
library aufm Deveice.

von ARM-Fan (Gast)


Lesenswert?

Dein Float belegt vier Bytes. Soweit so gut.

Nun sende doch einfach diese vier Byte einzeln und setze sie
auf der Gegenseite wieder zusammen.

Der Haken ist, dass du noch ein Protokoll brauchst, das dem Empfänger
sagt, wann gehts los und wo ist Ende.

Die Strings hatten da den Charme, dass sie eine Null am Ende haben
oder evtl. mit <CR> abgeschlossen sind.

So weit klar?

Du könntest also so etwas wie:

<DLE> <STX> b3 b2 b1 b0 <DLE> <ETX>

senden.
DLE, STX und ETX sind ASCII Steuerzeichen die genau dafür gedacht sind.
(Data Link Escape, Start of Text, End of Text).

Nun sind aber wieder (min.) 8 Byte geworden, die gesendet werden müssen.

Aber so ist das Leben, ohne Protokolloverhead geht (fast) nix.

von ARM-Fan (Gast)


Lesenswert?

Ach so und nochmal zu deiner Frage:

>Wie kann man das Bytemuster einer Variablen (int float ...) in einen
>String verwandeln den man via UART, CAN oder weiss der Teufel was
>verschicken kann und am Ende der Nahrungskette wieder zurück in eine
>float, int  ... ??

Das haben meine Vorredner zwar schon erschöpfend behandelt...

Wer sagt denn, dass man nur "Strings" über die serielle Schnittstelle
schieben kann. Da werden "Zeichen" übermittelt, die je nach 
eingestellten
Parametern 7,8 oder z.B. 9 bit lang sein können. In der Regel heutzutage
aber nunmal 8 bit. Also ein BYTE. Also: Jeder beliebige Wert von 0..255
kann an UDR gegeben werden.

Der Hinweis mit der union oben war, wie du nun komfortabel auf die
einzelnen 4 Speicherstellen deines Floats zugreifen kannst.

Möglichkeiten gibts aber noch genug andere.

Obacht nur bei der Endianness der beiden Systeme beim Zerlegen und
wieder Zusammensetzen der Zahlen!

von crazy horse (Gast)


Lesenswert?

und vor allem - solange nicht der Übertragungskanal zum Flaschenhals 
wird - warum nicht ein paar Bytes mehr senden als nötig? Mir tut es 
nicht weh, auch 20 Zeichen für eine Variable zu senden, solange mir 
nicht die Übertragungszeit ausgeht. Und auch das 
Auseinanderpuzzeln/Zusammensetzen - tutu doch auch nicht weh, 
normalerweise. Gut, es gibt Anwendungen, wo es alles knapp wird. Hast du 
so eine? Oder ist es "nur" sportlicher Ehrgeiz, overhead einzusparen?

von cerberus (Gast)


Lesenswert?

... Da steh ich nun ich armer Tor
und bin so schlau als wie zuvor ...

> Hast du so eine?

Nun ja, ich spiele mit dem Gedanken ein bisschen mit dem CAN-Bus zu 
übertragen und da sind 8 Byte das Maximum. Natürlich kann ich eine 
Information zerlegen und im Ziel wider zusammenschrauben, was aber blöd 
wäre, wenn ich doch eigentlich eh nur 4Byt bräuchte, + 1 um den Inhalt 
der Nachricht einer Bestimmung zuzuweisen, was wieder 255 verschiedene 
Möglichkeiten, also weit mehr als gebraucht, ergibt.

von Christian R. (supachris)


Lesenswert?

Kannst doch einige Informationen (Paket-Typ...) auch im Identifier 
kodieren.

von crazy horse (Gast)


Lesenswert?

naja, gerade am CAN ist es doch besonders einfach, die Daten sozusagen 
binär zu übertragen, da du alles, was du sonst noch brauchst, schon vom 
CAN-Frame erledigt wird.
Ohne die IDs unendlich aufzublähen: das 1.Byte der Botschaft sagt, 
welche Variable in dieser Botschaft steckt.

von cerberus (Gast)


Lesenswert?

Ja, das war mein Gedanke.
- die 4 Byte zu übertragen statt den Ascii-Wert
...
Alleine an der Umsetzung hapert es.
Und an dieser Stelle hatte ich gehofft hier hler zu finden, aber da ich 
schon zu doof war den Beitrag ins GCC-Forum zu schreiben ...
Mit Union und struct ist vermutlich irgend etwas zu gewinnen und auch 
die Sache mit dem Pointer scheint mir nicht all zu falsch, aber sobald 
ich irgend wo ein Stern setzt schreit der Compiler was von Pointer from 
Integer without a cast... Mit dem Mist konnte ich bisher noch keinen 
Blumnentopf gewinnen.

von crazy horse (Gast)


Lesenswert?

union ist in dem Fall genau das richtige.
Senden: float-zahl in die union schreiben, dann die 4 chars in den 
messagebuffer kopieren, ab dafür.
empfangen: 4 chars aus der der Empfangsbotschaft in die union schreiben, 
anschliessen float lesen, fertig.

von cerberus (Gast)


Lesenswert?

Super. Gibt es irgend wo ein Beispiel dafür?

von Arc N. (arc)


Lesenswert?

Kurzes Beispiel ohne union.
1
Type v1;
2
3
unsigned char *ptr = (unsigned char *)&v1;
4
5
for (int i = 0; i < sizeof(Type); i++) {
6
   uart_send(ptr[i]);
7
   // oder
8
   uart_send(*ptr); ptr++;
9
}

von cerberus (Gast)


Lesenswert?

@arc net
Vielen Dank.
Kann ich das reziprok auf der Empfangsseite auch verwenden?

von ARM-Fan (Gast)


Lesenswert?

cerberus, ich glaub du solltest wirklich erst noch ein paar Grundlagen
"pauken". Ist nicht böse gemeint, ist aber Fakt, wenn du bei Pointern
nur "Sterne" siehst ;-)

Ich kann mich noch gut an die Zeiten erinnern, als ich "mit sowas"
nichts zu tun haben wollte... Sich mal 2-3 Stunden damit befassen und
verstehen, wirkt aber wunder. Glaubs mir!

Wenn du deine Nachrichten über CAN versenden willst, vereinfacht sich
doch der Protokollkram schon wieder.

Du kannst einfach über den Identifier bestimmen, welche Nachricht
da gerade versendet wird.

Andererseits ist es in propriertären Systemen erlaubt und auch Usus,
den Identifier dahingehend zu "mißbrauchen", dass darin Absender,
Adressat, Nachrichtentyp, etc. Platz finden können. Und Nachrichten
größer 8 Byte werden, wie von dir vermutet, gesplittet. Auch da ist
alles erlaubt, was Spaß macht.

von ARM-Fan (Gast)


Lesenswert?

>Kann ich das reziprok auf der Empfangsseite auch verwenden?

Theoretisch ja, wenn du wie oben von mir geschrieben auf die
Endianness der Systeme achtest.

von cerberus (Gast)


Lesenswert?

> Sich mal 2-3 Stunden damit befassen und verstehen, wirkt aber wunder. Glaubs 
mir!

Ich habe diesen Mist mit den Pointern noch nie verstanden. Mir ist 
durchaus klar, was das ist, und wie es theoretisch funktioniert, aber 
wenn ich nur ein Sternchen im Programm wage pisst mich sofort der 
Compiler an. Ich warte auf den tag an dem er mir bei einem "/*" Argument 
makes Pointer from integer without a cast ausspuckt.
ERGO Ich glaube es Dir nicht.
Aber danke für die Hilfe. Ich glaube ich bekomme es so hin.
Ein weg für die Rückwandlung habe ich schon von der Eprom-Routine

von ARM-Fan (Gast)


Lesenswert?

Mit * und & muß es einfach mal "Klick" machen.

Danach wunderst du dich, warum du je ein Problem hattest das zu 
verstehen.
Vielleicht findet sich ja mal jemand, der dir das beim Bier mal
in Ruhe erklären kann :-)

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Ist doch eigentlich nicht so schwer:

float Wert;     //Eine Variable vom Typ float
Wert=-1.234;    //Der Wert -1.234 wird nach IEEE 754 als Gleitkommazahl
                  in 4 Byte abgelegt (BF 9D F3 B6).

Jetzt bastelt man sich einen Zeiger:

char *Zeiger;

und sagt ihm er soll auf die Adresse im Speicher Zeigen wo die Zahl 
liegt.

Zeiger=&Wert; //Zeigt auf das Erste Byte vom Wert (BFh);

printf("%c", *Zeiger);     //Gibt den ASCII Wert von BFh aus.
printf("%c", *(Zeiger+1)); //Gibt den ASCII Wert von 9Dh aus.
printf("%c", *(Zeiger+2)); //Gibt den ASCII Wert von F3h aus.
printf("%c", *(Zeiger+3)); //Gibt den ASCII Wert von B6h aus.


Und genau das machst du stillschweigend auch mit dem Union.

Mit:
- Zeiger kommst du an die Speicheradresse auf die der Zeiger zeigt.

- *Zeiger bekommst du den Inhalt dessen was an der Speicheradresse liegt 
die in Zeiger gespeichert ist, interpretiert mit dem Typ des Zeigers.

- &Zeiger kommst du an die Speicheradresse des Zeigers selbst (dieses 
geht natürlich auch bei anderen Variablen).

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Beim AVR Microcontroller natürlich in umgekehrter Reihenfolge, da der 
Wert -1.234 rückwärts in die 4 Byte abgelegt wird -> (B6 F3 9D BF).

http://de.wikipedia.org/wiki/Byte-Reihenfolge

von Gast (Gast)


Lesenswert?

Benutze doch eine Base64 (3 Byte weden auf 4 abgebildet), dann hast du 
nur Ascii Zeichen. Oder gleich Base 85 (4 Byte werden auf 5 abgebildet)
Das sollte jede Serielle Verbindung schaffen
Gruß

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.