Hey Leute,
ich muss über CAN Daten schicken. Leider sind die Informationen Byte
übergreifend, d.h. es gibt z.B. Daten die bei Byte 0 Bit 6 beginnen und
bis Byte 1 Bit 3 gehen. Das Bitfeld würde mir die möglichkeit geben, die
Daten strukturiert einzutragen und sie dann aneinanderstehen auszulesen.
Leider habe ich noch keine Möglichkeit gefunden, wie ich das Bitfeld
Byte-weise auslesen kann um meinen CAN-Frame mit Daten zu füllen.
Wisst ihr wie man sowas machen kann?
Viele Grüße
Falls du mit C arbeitest:
Sortier es halt passend in eine Bit-Struktur:
struct blala
{ int B0:1; int B1:1; ... }
und definier dir einen unsigned char-union über die Struktur (union). Da
fummelt dir der Compiler alles so zusammen, dass du es mit normalen
Byte-Operationen überziehen kannst.
Johann L. schrieb:> Na lies das Bitfeld eben aus, der Compiler bastelt den Wert schon> korrekt zusammen (abhängig vom ABI der jeweiligen Architektur).
Danke für den Tipp, wenn ich wüsste wie, hätte ich nicht gefragt ;)
René B. schrieb:> Falls du mit C arbeitest:
Ja, tue ich.
> Sortier es halt passend in eine Bit-Struktur:> struct blala> { int B0:1; int B1:1; ... }> und definier dir einen unsigned char-union über die Struktur (union). Da> fummelt dir der Compiler alles so zusammen, dass du es mit normalen> Byte-Operationen überziehen kannst.
1
unionCANFeld{
2
struct
3
{
4
uint8_tbit1:6;
5
uint8_tbit2:7;
6
uint8_tbit3:1;
7
}BitFeld;
8
};
Aber wie greife ich nun mit Bit-Operationen darauf zu, sodass ich z.B.
die Variable uint8_t test mit den ersten 8 bit der union fülle? Hab noch
keine Möglichkeit gefunden. Was ich nicht möchte ist das hier:
Du hast doch schon mit dem union angefangen. Nun fehlt parallel zur
Struktur noch dein Byte array.
Allerdings ist deine Lösung arg architekturabhängig.
Die Shiftoperationen sind allgemeingültig.
Wenn dein Prozessor keine Bitoperationen unterstützt kann es sogar
bedeuten, dass deine Bitoperationen mehr Code erzeugen.
Steffen Rose schrieb:> Du hast doch schon mit dem union angefangen. Nun fehlt parallel zur> Struktur noch dein Byte array.
Okay, also ich hatte mir vorgestellt, das Ganze auch in eine Struktur zu
verpacken. Nochmal der Code für die Union und mein CAN-Struct zusammen.
Ist jetzt erstmal eine Rohfassung, aber es geht auch einfach eher darum,
die Daten irgendwie sortiert zu kriegen.
1
unionCANFeld{
2
struct
3
{
4
uint8_tbit1:6;
5
uint8_tbit2:7;
6
uint8_tbit3:1;
7
}BitFeld;
8
};
9
10
structCANFrame{
11
uint32_tID;
12
uint8_tDLC;
13
uint8_tByte0;
14
uint8_tByte1;
15
uint8_tByte2;
16
uint8_tByte3;
17
uint8_tByte4;
18
uint8_tByte5;
19
uint8_tByte6;
20
uint8_tByte7;
21
}CAN_Msg;
Den DLC (DataLengthCode) und ID (Identifier) werde ich selbst schreiben,
die Bytes sollen jetzt mit den Daten aus der union CANFELD gefüllt
werden. Das heißt ich schreibe die ersten 8bit der union in
CAN_Msg.Byte0, die zweiten 8bit in Byte1 usw.
Da fehlt mir jetzt jeglicher Ansatz. Kann ich da mit Pointern arbeiten?
Ich habe das mal mit Strukturen probiert, allerdings hat man dort das
Problem, dass die Datentypen nicht übereinstimmen, der Compiler gibt
hier eine Fehlermeldung aus.
eine union mit nur einem Member ist sinnlos. Wozu soll das gut sein.
Der Trick bei einer union besteht doch genau darin, dass
1
uniona{
2
intm1;
3
longm2;
4
};
die beiden Mitglieder der union (m1 und m2) in genau demselben Speicher
angelegt werden. Die beiden (können auch mehr sein) teilen sich
praktisch denselben Speicher. Es ist, wie wenn du 2 Schablonen aus Folie
über den Speicher legst, auf der einen steht m1 (mitsamt der Zuordnung
der Bytes zu einem int) und auf der anderen steht m2 (ebenfalls mitsamt
der Zuordung derselben Bytes zu diesmal einem long). Das ein long mehr
Bytes im Speicher braucht als ein int, tangiert dich nur insofern, als
dann eben bei m1 nicht der komplette für die union reservierte Speicher
benutzt wird, sondern nur Auszüge davon. Die union ist immer genau so
groß, wie der größte Member, derer die übereinander gelegt werden.
du hast eine
1
uniona{
2
structirgendwas
3
};
mit wem teilt sich denn diese Struct denselben Speicher? Das gibt es ja
keinen 2.ten Member.
Du könntest
1
uniona{
2
structirgendwas;
3
unsignedcharbytes[länge];
4
};
dann teilt sich die struct mit dem Array denselben Speicher. De facto
hast du damit 2 Zugriffspfade in den Speicher geschaffen. In dem einen,
über die struct, hast du dem Speicher eine Struktur übergestülpt, in der
du über einem Problem angepasste logische Namen auf den Speicher
zugreifen kannst. Im andern Teil der union fasst du genau denselben
Speicher einfach nur als Array von unsigned char (also Bytes) auf -
jegliche logische Einteilung (deshalb hat man sich ja eine struct
gebaut) bzw. Aufteilung derselben Speicherplätze ist nicht mehr
vorhanden.
> Da fehlt mir jetzt jeglicher Ansatz. Kann ich da mit Pointern arbeiten?
Kann man auch.
> Ich habe das mal mit Strukturen probiert, allerdings hat man dort das> Problem, dass die Datentypen nicht übereinstimmen, der Compiler gibt> hier eine Fehlermeldung aus.
Wenn man weiß was man tut und sich sicher ist, das richtig zu machen,
dann kann man den Compiler mit einem Cast ruhig stellen. Aber dann muss
man sicher sein, auch wirklich zu wissen was man tut.
Hmmm... okay, dann ist meine union vielleicht gar nicht nötig? Ich habe
das wegen diesem Beitrag in eine Union verpackt:
René B. schrieb:> Sortier es halt passend in eine Bit-Struktur:> struct blala> { int B0:1; int B1:1; ... }> und definier dir einen unsigned char-union über die Struktur (union)
Was ich will ist, das Bitfeld Byteweise mit hintereinanderstehenden
Daten in meine einzelnen Bytes der CAN-Message zu übertragen.
Mal ein anderes Beispiel. Ich möchte auch hier mein uint8_t byte1 mit
den ersten 8bits aus meiner Struktur füllen. Folgenden Code habe ich
dazu geschrieben:
1
structtest
2
{
3
uint8_tbit1:6;
4
uint8_tbit2:7;
5
uint8_tbit3:1;
6
};
7
8
intmain(void)
9
{
10
structtestBitFeld;
11
structtest*Ptr;
12
13
Ptr=&BitFeld;
14
15
BitFeld.bit1=0x2A;
16
BitFeld.bit2=0x2A;
17
18
uint8_tbyte1;
19
20
for(inti=0;i<8;++i)
21
{
22
byte1|=((uint8_t)Ptr[i])<<i;
23
}
24
25
printf("%d\n",byte1);
26
27
return0;
28
}
Folgende Fehlermeldung erhält man:
1
error: invalid cast from type 'test' to type 'uint8_t {aka unsigned char}'
2
byte1 |= (uint8_t) Ptr[i];
Zumal dieser Code vermutlich nicht das machen wird, was ich möchte. Kann
ich mit dem Index des Pointers auf die einzelnen Bits zugreifen?
Vermutlich springt er nicht nur ein Bit weiter, sondern um die Größe der
struct test...
Karl Heinz schrieb:>> Da fehlt mir jetzt jeglicher Ansatz. Kann ich da mit Pointern arbeiten?>> Kann man auch.
Aber bei dir brauchts das eigentlich gar nicht, schon alleine deshalb
weil du in CANFrame kein Array hast (was ich sowieso nicht so recht
verstehe. welchen Sinn hat es Variablen durchzunummerieren anstelle von
gleich einem Array? Verkomplizert doch nur alles, weil man nicht
ordentlich und vernünftig mit Schleifen arbeiten kann. durchnummerierte
Variablen, die alle vom selben Datentyp sind, sind IMHO ein
Designfehler. Eigentlich sollte das ein Array sein.
1
structCanBits
2
{
3
uint8_tbit1:6;
4
uint8_tbit2:7;
5
uint8_tbit3:1;
6
};
7
8
unionCANFeld{
9
structCanBitsBitField;
10
uint8_tBytes[sizeofstructCanBits];
11
};
12
13
structCANFrame{
14
uint32_tID;
15
uint8_tDLC;
16
uint8_tByte0;
17
uint8_tByte1;
18
uint8_tByte2;
19
uint8_tByte3;
20
uint8_tByte4;
21
uint8_tByte5;
22
uint8_tByte6;
23
uint8_tByte7;
24
};
25
26
...
27
unionCANFieldvalues;
28
structCANFrameMsg;
29
30
// befüllen über die Struktur.
31
// Der Compiler kümmert sich darum, dass die Bits an die richtigen
32
// Stellen in der Struktur kommen
33
values.BitField.bit1=4;
34
values.BitField.bit2=8;
35
values.BitField.bit3=1;
36
37
// übertragen in den CANFrame, diesmal über den anderen Pfad der union
38
// zugreifen, in dem ganz einfach auf die Bytes im Array zugegriffen wird.
Willy M. schrieb:> Was ich will
Was du eigentlich wollen solltest, ist erst mal ein C-Buch
durcharbeiten!
> ... Vermutlich ...
Basierend auf 'vermutlich' kann man nicht programmieren. Entweder man
kennt seine Sprache oder man kennt sie nicht. Wenn man sie nicht kennt,
dann muss man sie eben lernen. Dazu gibt es LIteratur.
Aber das hab ich dir mitlerweile schon 15 mal gesagt. Warum glaubst du
es denn nicht?
Oh man... Jetzt habe ich es glaube ich verstanden. Steht ja auch in den
Kommentaren, aber ich möchhte das nochmal in eigene Worte fassen.
Man definiert sich eine Union mit einem Bitfeld und einem Array mit
Bytes. Man beschreibt nun das Bitfeld mit den entsprechenden Daten,
liest sie aber über das Array aus. Was dann passiert ist, dass die Daten
des Bitfeldes anders Interpretiert werden, d.h. in Bytes gefasst werden,
auf die ich nun zugreifen kann.
Ist das so richtig?
Das ist natürlich genial, aber ich wäre niieeeeee darauf gekommen. Danke
vielmals für deine Bemühungen, du hast mir sehr weitergeholfen :) Danke
natürlich auch an die anderen :)
Viele Grüße
Willy
EDIT:
Karl Heinz schrieb:>> Was ich will>> Was du eigentlich wollen solltest, ist erst mal ein C-Buch> durcharbeiten!>>> ... Vermutlich ...>> Basierend auf 'vermutlich' kann man nicht programmieren. Entweder man> kennt seine Sprache oder man kennt sie nicht. Wenn man sie nicht kennt,> dann muss man sie eben lernen. Dazu gibt es LIteratur.>> Aber das hab ich dir mitlerweile schon 15 mal gesagt. Warum glaubst du> es denn nicht?
Die Antwort war vor deinem, ich hab bloß solange gebraucht den zu
schreiben, deswegen hatte ich deinen nicht gelesen, danach konnte ich
den Beitrag leider nicht mehr löschen ;) Nochmals vielen Dank :)
Was mein Compiler tut ist, dass er die Daten an den Anfang eines neuen
Bytes schreibt, wenn der Inhalt der Variable des Bitfelds nicht mehr in
das Restbyte passt.
Beispiel:
1
structCANBits{
2
uint8_tbit1:6;
3
uint8_tbit2:3;
4
uint8_tbit3:6;
5
};
6
7
...
8
9
test.BitFeld.bit1=0x7;// 00 0111
10
test.BitFeld.bit2=0x3;// 011
11
test.BitFeld.bit3=0;// 00 0000
12
13
// Ausgabe
14
15
sizeof:3
16
Byte1:7// eigentlich sollte es so aussehen: 011|00 0111
17
Byte2:3// da das letzte bit aber nicht mehr ins Byte reinpasst
18
Byte3:0// wird es an den Anfang des nächsten Bytes geschrieben
Nun habe ich wieder das Problem, dass ich die Daten nicht Byte
übergreifend schreiben kann. Weiß jemand, ob man den Compiler da
austricksen kann?
Willy M. schrieb:> Hmmm... okay, dann ist meine union vielleicht gar nicht nötig?
Ich wüßte auch nicht, wozu man hier extra eine zusätzliche union
brauchen sollte, abgesehen davon, daß unions dafür auch gar nicht
gedacht sind.
Willy M. schrieb:> Was mein Compiler tut ist, dass er die Daten an den Anfang eines neuen> Bytes schreibt, wenn der Inhalt der Variable des Bitfelds nicht mehr in> das Restbyte passt.
Kein Wunder. Du beschränkst es ja selbst auf 8 Bit, indem du als Typ
uint8_t angibst.
Willy M. schrieb:> Man definiert sich eine Union mit einem Bitfeld und einem Array mit> Bytes. Man beschreibt nun das Bitfeld mit den entsprechenden Daten,> liest sie aber über das Array aus. Was dann passiert ist, dass die Daten> des Bitfeldes anders Interpretiert werden, d.h. in Bytes gefasst werden,> auf die ich nun zugreifen kann.>> Ist das so richtig?> Das ist natürlich genial,
Das ist tatsächlich einigermaßen genial, bloß alles andere als portabel.
Leider erlaubt der C-Standard den Compilern alle Arten von Freiheiten,
was die Implementierung von Bitfeldern angeht (insbesondere packing,
alignment und byte order) und was mit einem Compiler funktioniert, kann
mit einem anderen ein völlig anderes Ergebnis liefern.
Wenn Du sicher gehen willst, bleibt nichts anderes als die Bytes "zu
Fuß" zusammenzupfriemeln.
Markus F. schrieb:> Wenn Du sicher gehen willst, bleibt nichts anderes als die Bytes "zu> Fuß" zusammenzupfriemeln.
Es gibt nun mal zwei Welten: Big- und Little Endian.
Und die tolle Programmiersprache C kommt auch nach 40 Jahren nicht damit
zurecht ...