Forum: Mikrocontroller und Digitale Elektronik Bitblöcke auslesen


von Toby M. (toby_sx)


Lesenswert?

Hallo,

ich würde gerne möglichst effizient CAN Nachrichten auswerten. Diese
bestehen immer aus 1..8 zusammenhängenden Bytes. Beispielsweise kann ein
Signal bei bit 2 starten und 10bit lang sein. Ich wollte nun
schrittweise immer zwei Byte (damit maximal 16Bit breite Worte) mit
einem Short-Zeiger auswählen und dann mit entsprechender Maskierung
verUNDen. Leider lässte der kompiler die conversion von char* zu short
int* nicht zu.

Folgendes wollte ich also tun:

short * block;
char msg[]="ABCDEFG";

/*lenght soll die länge meine wortes in bit angeben, starbit ist
selbsterklärend*/

block = &msg; // also damit sollte der short auf das untere Byte zeigen
block = block & ((short)(pow(2,length) << startbit));

nun sollte eigentlich meine nachrichtig fertig maskiert in block stehen,
sodass ich diese nur wieder um startbit in die gegenrichtung shiften
müsste.

gibt es vielleicht eine elegantere lösung, um aus einem 2er Byteblock
einen beliebig langen (max16) bitblock zu lesen?

grüße und danke für ideen,
toby

von Briegel (Gast)


Lesenswert?

Hi!
Deklariere doch einfach ein bitfield Typen. Das ist imho die Art, sowas 
zu tun.

von Toby M. (toby_sx)


Lesenswert?

Danke, aber das hilft mir nicht viel weiter. Ich kann doch bits aus 
bitfelder nicht mit einem befehl beschreiben, jedenfalls steht das 
nirgends in den definitionen...

für den fall ich hätte ein bitfeld mit b0 bis b7 wäre ein befehl:

bitfeld.b0 = 0x41; recht brauchbar, wenn er die anderen bits nach b0 
überschreiben würde. funktioniert aber nicht.
Weitere tips?

gruß,
toby

von Peter D. (peda)


Lesenswert?

2 Sachen:

1.
pow() ist eine float-Funktion, d.h. es dauert ewig lange und kostet zich 
kB Code. Beschäftige dich besser mal mit Schiebeoperatoren.

2.
Die Byteorder in mehrbytigen Variablen ist nicht definiert.
Was auf der einen CPU mit dem einen Compiler funktioniert, kann Dir mit 
ner anderen großen Mist produzieren.
Daher macht man es üblicher Weise kompatibel:
1
short val = byte_low | (byte_high << 8);



Um nun z.B. die Bits 2..9 zu extraieren, maskiert man oben und schiebt 
nach unten:
1
val9_2 = (val & (1 << 9 + 1) - 1) >> 2;


Peter

von Toby M. (toby_sx)


Lesenswert?

Hallo Peter!

Vielen Dank für die Hilfe, die Möglichkeiten der Bitoperationen habe 
ich, wie es scheint, nicht ausgenutzt.

Ich versuche gerade die Bitextraktion zu verstehen. Irgendwie steh ich 
auf dem Schlauch.

val9_2 = (val & (1 << 9 + 1) - 1) >> 2;

Wie läuft dieser Vergleich ab? wozu die -1? Welche Operation hat vorrang 
in der klammer?


vielleicht ist es einfach schon ein bisschen spät! Auf jeden Fall 
funktioniert es schon mal!

Gruß,
Toby

von Karl H. (kbuchegg)


Lesenswert?

> Wie läuft dieser Vergleich ab

In diesem Ausdruck ist kein einziger Vergleich!

  >>  bedeutet 'bitweise nach rechts schieben'
  <<           'bitweise nach links schieben'

  i = k << 2;

der Inhalt wird also um 2 Bits nach links verschoben und das
Ergebnis wird i zugewiesen.

Zu deinem ursprünglichen Ansatz:
> leider .. char* zu short int* nicht zu.

Ja, klar. Ein Pointer auf int ist nunmal kein Pointer auf char.
Wenn du allerdings sicher bist, dass du genau das willst,
dass der Compiler so tut, als ob der Pointer auf char
einer auf int wäre, kannst du ihn immer überstimmen: mit
einem Cast

block = (short*) &msg;

Aber Vorsicht: Ein Cast ist eine Waffe. Effektiv schaltest du
damit das Typ-Prüfsystem des Compilers ab und zwingst ihn die
Zuweisung wider besseren Wissens zu akzeptieren. Der Programmierer
sollte also besser wissen was er hier tut.

Die Anmerkungen bezüglich Nicht-Portabilität gelten natürlich
weiterhin.

von Karl heinz B. (kbucheg)


Lesenswert?

> aber was macht die -1?

Probiers doch einfach aus!
Hinweis: Du musst dir das binär, also auf Bitebene ansehen.

Die Fragestellung lautet: wenn du eine Binärzahl hast
die eine 2-er Potenz ist ( 1 << x liefert logischerweise
immer eine 2-er Potenz) und dann 1 davon abziehst, wie
sieht dann das Ergebnis aus, welchem Muster folgt es?

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.