Forum: Mikrocontroller und Digitale Elektronik 8bit Datentransfer von int16-Werten


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von grundschüler (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
ich habe zwei ucs, die Daten austauschen. Dazu habe ich zwei macros:
1
//Empfänger:
2
#define get_rx16(pos) owx_rx_buffer[pos]<<8|owx_rx_buffer[pos+1]
3
//Sender:
4
#define set_tx16(wert,pos) owx_tx_buffer[pos]=wert>>8;owx_tx_buffer[pos+1]=wert


 Das ganze funktioniert, nur bei negativen Werten nicht, d.h. int16 
werden richtig übertragen, solange sie nicht negativ sind.

Was ist falsch?

von Jobst Q. (joquis)


Bewertung
0 lesenswert
nicht lesenswert
Du musst wert als unsigned deklarieren und vor und nach der Ubertragung 
konvertieren.

Wenn du einen negativen int16 rechtsshiftest (>>), wird 1 statt 0 
nachgeschoben.

Oder dividier und multiplizier mit 256 für das H-Byte

von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> Was ist falsch?

Vermutlich weiss der empfangende µC gar nicht, welches das High- und 
welches das Low-Byte ist.

Ich erkenne in deinen Makros keinerlei Synchronisationsalgorithmus.

von grundschüler (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Jobst Q. schrieb:
> Wenn du einen negativen int16 rechtsshiftest (>>), wird 1 statt 0
> nachgeschoben.

klingt logisch, das wirds sein.

Wolfgang schrieb:
> Synchronisationsalgorithmus

Der Sender trägt  z.B. den Wert 325 in tx_buffer[10..11] ein. Der 
Empfänger holt ihn aus rx_buffer[10..11] raus. Was soll da 
synchronisiert werden?

von Jobst Q. (joquis)


Bewertung
-2 lesenswert
nicht lesenswert
Das Konvertieren zwischen unsigned und signed int macht man am besten 
über eine union.

union {
 int16 i;
 uint16 u;
 } wert;


Das heißt, es gibt für beide denselben Speicherplatz. Du schreibst den 
Integerwert als wert.i rein und holst ihn als unsigned mit wert.u raus. 
Oder umgekehrt.

Mit gcc kann man sogar direkt die Bytes herausholen:

#pragma pack(1) // Byteweise packen
typedef struct {
 char h;
 char l;
 } tbytes

union {
 int16 i;
 tbytes b;
 } wert;

#pragma pack() // Packweise zurückstellen

//Empfänger:
 wert.b.h=owx_rx_buffer[pos]; wert.b.l= owx_rx_buffer[pos+1];
//Sender:
owx_tx_buffer[pos]=wert.b.h;owx_tx_buffer[pos+1]=wert.b.l;

von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> Was soll da synchronisiert werden?

In deinen Makros steht nur etwas von Zugriffen auf Byte-Arrays. 
Irgendwie müssen die Daten doch vom µC1 zum µC2 rübergebeamt werden und 
genau da muss es einen Synchronisationsmechanismus geben. Sonst könntest 
du gleich deine 16Bit int16 Werte übertragen und dir die Byte-Arrays 
sparen.

Oder geht es hier gar nicht um den Datentransfer?

von 4328970765432459780876543 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
was spricht gegen einen uint8_t *ptr mit längenangabe für die 
sende/empfangsfunktion
so machen das alle üblichen verdächtigen

foo( uint8_t *ptr , uint32_t len )

{
     foo( (uint8_t *)&daten16bit , 2 /*sizeof(datatype)*/ )
}

beim empfang auch in einen 16bit oder in 8bit array[2] empfangen  mit 
8bit *ptr

weil bei jedem byte der pointer incrementiert wird sind die daten immer 
in der gleichen reihenfolge.


bei int16 oder short würde ich bei diversen architekturen aufpassen
das kann zum byteswap führen
Wenn ich eh nur 8bit übertragen kann ...
dann am besten mit uint8_t* pointer

von Kaj G. (Firma: RUB) (bloody)


Bewertung
0 lesenswert
nicht lesenswert
Jobst Q. schrieb:
> Das Konvertieren zwischen unsigned und signed int macht man am besten
> über eine union.
Nein. Denn das bedeutet unterm Strich, dass du einen Member schreibst, 
aber einen anderen liest. Und dies ist undefiniertes Verhalten. Man darf 
nur den Member eines union lesen, welcher zu letzt geschrieben wurde.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wolfgang schrieb:
> Irgendwie müssen die Daten doch vom µC1 zum µC2

uc1 misst Temperaturen, Stromverbrauch, Durchfluss und regelt nach 
diesen Werten die Heizung. Die Daten werden per Onewire an uc2 
übertragen, der die Werte grafisch darstellt und zusätzliche 
Steuerbefehle sendet. Die onewire-übertragung ist natürlich 
synchronisiert. Das ganze funktioniert - bis auf die Übertragung 
negativer Werte - perfekt.

von Jobst Q. (joquis)


Bewertung
-2 lesenswert
nicht lesenswert
Kaj G. schrieb:
> Jobst Q. schrieb:
>> Das Konvertieren zwischen unsigned und signed int macht man am besten
>> über eine union.
> Nein. Denn das bedeutet unterm Strich, dass du einen Member schreibst,
> aber einen anderen liest. Und dies ist undefiniertes Verhalten. Man darf
> nur den Member eines union lesen, welcher zu letzt geschrieben wurde.

Sind wir hier in einem schlechten Kindergarten, wo Regeln eingepaukt 
werden, ohne sie zu verstehen?

union heißt, dass Variablen unterschiedlichen Typs auf demselben 
Speicherplatz untergebracht werden. Oder andersherum, dass derselbe 
Speicherinhalt als Variable unterschiedlichen Typs behandelt werden 
kann. Da ist nichts am Verhalten undefiniert.

In diesem Fall ist es ja erwünscht, dass ein Integer mit Vorzeichen als 
vorzeichenloser Typ behandelt wird, um ihn problemlos in einzelne Bytes 
umzusetzen.

Wie würdest du das denn sonst machen?

Und wenn jetzt das Problem wäre, einen float-wert als einzelne Bytes zu 
übertragen?

Mit einer union wäre das kein Problem. Eine andere Möglichkeit wäre über 
einen gecasteten void-Pointer, aber Pointer sind ja auch nicht so 
beliebt, außer bei denen, die damit umgehen können.

von S. R. (svenska)


Bewertung
0 lesenswert
nicht lesenswert
Jobst Q. schrieb:
> Sind wir hier in einem schlechten Kindergarten, wo Regeln eingepaukt
> werden, ohne sie zu verstehen?

Das ändert nichts daran, dass dein Ansatz garantiert 
implementationsabhängiges Verhalten ist.

Ja, kann man so machen.
Wird auch funktionieren.
Ist nicht standardkonform.

Ein Cast über einen char-Pointer dagegen ist standardkonform.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
hab jetzt nochmal probiert. Mit mingw geht dieses:
1
#include <stdint.h>
2
#include <stdio.h>
3
4
//#define get_rx16(pos) owx_rx_buffer[pos]<<8|owx_rx_buffer[pos+1]
5
//#define set_tx16(wert,pos) owx_tx_buffer[pos]=wert>>8;owx_tx_buffer[pos+1]=wert
6
#define get_rx16(pos) buf[pos]<<8|buf[pos+1]
7
#define set_tx16(wert,pos) buf[pos]=wert>>8;buf[pos+1]=wert
8
9
int main(void)
10
{
11
int16_t a =-800,b;
12
uint8_t buf[2];
13
14
set_tx16(a,0);
15
//buf[0]=a>>8;
16
printf (": %d \n", a);
17
   
18
printf (": %d \n",buf[0]);
19
printf (": %d \n",buf[1]);
20
  
21
b=get_rx16(0);  
22
printf ("b: %d \n",b);
23
  return 0;
24
25
}

Mit meinem winavr - neuere toolchain - geht das get_rx16 nicht. Im 
Buffer steht richtig 0xfffe, ausgegeben wird 254.

Mit
#define get_rx16(pos) (i16)(owx_rx_buffer[pos]*256|owx_rx_buffer[pos+1])
kommt dann richtig -2 heraus.

Scheint also von der toolchain abhängig zu sein.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.