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


von grundschüler (Gast)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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)


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.

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.