Forum: Mikrocontroller und Digitale Elektronik Lösungsansätze für Bitschieberei gesucht


von C. L. (calle)


Lesenswert?

Hallo zusammen,

stehe ein wenig auf dem Schlauch, vlt. kann mir jemand helfen.

Ich möchte ein Bit-Datenstream zusammenbauen von 148 Bit, dessen Daten 
nur Byte- /Nibbleweise vorliegen.

Beispiel:
Ein Byte hat im rechten Nibble die Einsen als Daten, welche in den 
Stream sollen. (0011_0011) Hier ist jetzt klar 11...
Bei den Nullen wird es schwierig, deswegen ist im linken Nibble immer 
gekennzeichnet, welche Bits für den Stream genommen werden sollen
z.B (0111 0000) heißst dann drei Nullen (Bit 0,1,2) in den Stream.
Dieser wächst dann -> 11000.
Noch ein Beispiel (1111 1111), hier ist im linken Nibble klar, das alle 
Bits aus dem rechten Nibble auch in den Stream sollen ->110001111.
So geht das weiter bis zum Schluss.
Also in dem rechten Teil der Bytes sind die eigentlichen Daten für den 
Stream mit wechselnden Längen von 1 bis 4 Bit.
In dem linken Teil ist die Kennung, welche/wieviele Bits es sind im 
rechten Teil.
Jetzt fehlen mir die Ideen, wie man das elegant angeht.
Einfach kopieren geht nicht, das sich immer die Längen ändern. Mal 1 
Bit, mal 2,3 oder 4 Bit. Mehr nicht.
Ich bin momentan herkömmlich dabei mit If / If else ... verrenne mich 
aber immer irgendwie.
Also ausmaskieren des linken Teils und den rechten dann entsprechend 
kopieren, dann jede volle neue 8Bit Information in des Stream einbauen.
Dabei den Überlauf beachten, weil die Längen sich ja ändern.
Ein Bit Array kann der Compiler nicht (C - MikroE für PIC)

Kann mir mal jemand Hilfestellung geben?
Hoffe, das ist einigermassen klar geworden.

Gruß CL

Beitrag #5036497 wurde von einem Moderator gelöscht.
Beitrag #5036513 wurde von einem Moderator gelöscht.
von Tom (Gast)


Lesenswert?

Können im linken Teil auch Lücken wie 0101_xxxx vorkommen?

von Curby23523 N. (Gast)


Lesenswert?

Versuchs mal so (keine Garantie auf Funktion, ungetestet). Kann man 
bestimmt auch noch etwas optimieren.
1
void setData(unsigned char cData){    
2
  static unsigned char cBuffer = 0;        //Ausgabepuffer
3
  static unsigned char cPos = 0;          //Aktuell zu befüllende Stelle bzw. Anzahl bereits gefüllter Stellen
4
5
  /*JETZT FÜLLEN WIR DEN BUFFER*/
6
  for(unsigned char x = 0; x < 4; x++){
7
    if(cData & 16){
8
      cBuffer |= (cData & 1) << cPos; //BUffer schreiben
9
    
10
      if(++cPos > 7){              //Buffer voll
11
        cPos = 0;              //Position auf 0 setzen
12
        //Daten verschicken.... usw.
13
        cBuffer = 0;            //Buffer leeren 
14
      }
15
    }
16
    cData >>= 1;
17
  }
18
}

von C. L. (calle)


Lesenswert?

Tom schrieb:
> Können im linken Teil auch Lücken wie 0101_xxxx vorkommen?

Nein. Entweder nur 1111, 0111, 0011 oder 0001

@ nils
Schaue ich mir nachher mal näher an.



Gruss cl

Schwerenöter schrieb im Beitrag #5036513:
> Es ist kaum auszuhalten

Verständnisschwierigkeiten ?

von Curby23523 N. (Gast)


Lesenswert?

Bei meiner Lösung kann im linken Teil irgendwas stehen. 1101, 1011, 
1000, 1010,....

von A. S. (Gast)


Lesenswert?

C. L. schrieb:
> nur 1111, 0111, 0011 oder 0001

Also nur genau 2 Mal 4 Werte...
Da ist ein Switch case schon gut genug, mehr optimieren nur mit 
ausmessen.

Also 16 bit-wert füllen per shift,
Shift zählen,
Nach mehr als 7 shifts die oberen 8 Bit rauskopieren und shift-=8 
(eigener case, kann nur 8..11 sein...)

Was ist denn dein Ansatz?

von A. S. (Gast)


Lesenswert?

1
typedef unsigned char BYTE;
2
3
extern BYTE ReadNibbleDibble(void);
4
extern void PutStream(BYTE data);
5
6
void doit_once(void)
7
{
8
unsigned short r; /* no need to clear */
9
int byte_cnt = 0;
10
int bit_cnt = 0;
11
12
   while(byte_cnt < 148)
13
   {
14
   BYTE B = ReadNibbleDibble();
15
     
16
      switch(B)
17
      {
18
      case 0x11: bit_cnt+=1; r<<=1; r|=0x01; break;
19
      case 0x33: bit_cnt+=2; r<<=2; r|=0x03; break;
20
      case 0x77: bit_cnt+=3; r<<=3; r|=0x07; break;
21
      case 0xff: bit_cnt+=4; r<<=4; r|=0x0f; break;
22
23
      case 0x10: bit_cnt+=1; r<<=1; break;
24
      case 0x30: bit_cnt+=2; r<<=2; break;
25
      case 0x70: bit_cnt+=3; r<<=3; break;
26
      case 0xf0: bit_cnt+=4; r<<=4; break;
27
28
      default: no_default_neccessary_as_we_collapse_immideately(); return;
29
      } 
30
      switch(bit_cnt)
31
      {
32
      case  8: bit_cnt-=8; byte_cnt++; PutStream((BYTE) (r>>0)); break;
33
      case  9: bit_cnt-=8; byte_cnt++; PutStream((BYTE) (r>>1)); break;
34
      case 10: bit_cnt-=8; byte_cnt++; PutStream((BYTE) (r>>2)); break;
35
      case 11: bit_cnt-=8; byte_cnt++; PutStream((BYTE) (r>>3)); break;
36
      }      
37
   }
38
}

von C. L. (calle)


Lesenswert?

Hey Leute...

erstmal vielen Dank für die vielen Ansätze.
Evtl. komme ich erst Sonntag dazu was umzusetzen weil ich morgen nicht 
da bin. Ich melde mich dazu auf jeden Fall noch!


Achim S. schrieb:
> Also nur genau 2 Mal 4 Werte...
Hä? Warum 2 mal 4 Werte???
Du meinst die 4 Werte pro Nibble? OK!
Deine Lösung sieht auch gut aus... (dito Nils)
Um das sauber zu verstehen, möchte ich das schon durcharbeiten,
bin aber momentan zeitlich etwas gebunden.

Achim S. schrieb:
> Was ist denn dein Ansatz?

Ich bin gerne noch herkömmlich unterwegs. Poiner usw. habe ich auch 
schon gemacht aber versuche es gerne ohne, auch wenn es etwas mehr Code 
braucht.
Hier mal ein Ausschnitt, wie ich das Datenbyte zusammensetze.
Es geht ja um einen Datenstrom am Empfangspin eines Funkmoduls.
Hier messe ich die Puls/Pausenbreite und die binären Zustände zu diesen 
Zeiten, speichere diese in Arrays. Dann durchlaufe ich die Arrays, prüfe 
die Breiten ab und fülle die Bytes, von denen ich oben gesprochen habe. 
Ich war bis gestern Abend dann mit IF (Kennung_Bits[k] & 0x10) usw. 
unterwegs um dann anhand der linken Nibbles die rechten zu kopieren.
Bin dann aber an dem Füllen des Stream gescheitert, weil ich es nicht 
hinbekommen habe, die unterschiedlichen Zustände in den Stream zu 
schieben. Den Codeansätze habe ich dann gestern wieder gelöscht und 
beschlossen hier zu fragen.
1
       if ((PulsPausenWerte[k] > 142) & (PulsPausenWerte[k] < 162))
2
          {
3
          Kennung_Bits[k] = PulsPausenBinaerWerte[k];         // Bitstelle 0
4
5
          temp = PulsPausenBinaerWerte[k] * 2;                 // Bitstelle 1
6
          Kennung_Bits[k] |= temp;
7
8
          temp = PulsPausenBinaerWerte[k] * 4;                 // Bitstelle 2
9
          Kennung_Bits[k] |= temp;
10
11
          temp = PulsPausenBinaerWerte[k] * 8;                 // Bitstelle 3
12
          Kennung_Bits[k] |= temp;
13
          Kennung_Bits[k] |= 0b11110000;                      // Kennung welche Bits zum Datenstrom gehören
14
          }

Nach diesem Prinzip war ich das angegangen.

CL

von Orcan (Gast)


Lesenswert?

In asm ist das pillepalle, aber in C muss man da auch nicht
verzweifeln:

  In-Byte = XXXXYYYY

  Ctrl-Byte = In-Byte
  Ctrl-Byte >>= 4          ; Ctrl-Byte = Hi-Nibble von In-Byte

  n = 4
while ( Ctrl-Byte & 0x01 && n)
  {  STREAM <<= 1
     if (In-Byte & 0x01)
       STREAM += 1
    In-Byte >>= 1
    Ctrl-Byte >>= 1
     n -= 1
  }


Wenn die Bits andersrum einsortiert werden sollen:

  In-Byte = XXXXYYYY

  Ctrl-Byte = In-Byte
  Ctrl-Byte >>= 4          ; Ctrl-Byte = Hi-Nibble von In-Byte

  n = 4
while ( Ctrl-Byte & 0x01 && n)
  {  STREAM <<= 1
     if (In-Byte & 0x08)
       STREAM += 1
    In-Byte <<= 1
    Ctrl-Byte >>= 1
     n -= 1
  }

von C. L. (calle)


Lesenswert?

Hallo,

ich habe das gestern umgesetzt und für die Nachwelt möchte ich meine 
Lösung hier (noch unkommentiert) mitteilen.
Orcans Ansatz habe ich dann schließlich verwendet und auf das System 
umgemünzt. Die übergebenen Bytebreiten Infos/Daten werden hier in max. 
acht 32Bit Wörtern umgeschrieben. Dann kann man den Stream 
weiterverwenden.
Danke an alle, die mir weitergeholfen haben...
In diesem Sinne, wieder was gelernt...

CL
1
          Stream_cnt = 0;
2
          
3
          for(l=0; l<=180; l++)
4
          {
5
          In_Byte = Kennung_Bits[l];
6
 
7
          Ctrl_Byte = In_Byte;
8
          Ctrl_Byte >>= 4;          // Ctrl-Byte = Hi-Nibble von In-Byte
9
 
10
          x = 4;
11
          while ( Ctrl_Byte & 0x01 && x)
12
            {
13
            Stream_cnt +=1;
14
            
15
            if ((Stream_cnt >= 1) &(Stream_cnt <= 32))
16
              {
17
              STREAM_1 <<= 1;
18
              if (In_Byte & 0x01){STREAM_1 += 1;}
19
              }
20
            if ((Stream_cnt >= 33) &(Stream_cnt <= 64))
21
              {
22
              STREAM_2 <<= 1;
23
              if (In_Byte & 0x01){STREAM_2 += 1;}
24
              }
25
            if ((Stream_cnt >= 65) &(Stream_cnt <= 96))
26
              {
27
              STREAM_3 <<= 1;
28
              if (In_Byte & 0x01){STREAM_3 += 1;}
29
              }
30
            if ((Stream_cnt >= 97) &(Stream_cnt <= 128))
31
              {
32
              STREAM_4 <<= 1;
33
              if (In_Byte & 0x01){STREAM_4 += 1;}
34
              }
35
            if ((Stream_cnt >= 129) &(Stream_cnt <= 160))
36
              {
37
              STREAM_5 <<= 1;
38
              if (In_Byte & 0x01){STREAM_5 += 1;}
39
              }
40
            if ((Stream_cnt >= 161) &(Stream_cnt <= 192))
41
              {
42
              STREAM_6 <<= 1;
43
              if (In_Byte & 0x01){STREAM_6 += 1;}
44
              }
45
            if ((Stream_cnt >= 193) &(Stream_cnt <= 224))
46
              {
47
              STREAM_7 <<= 1;
48
              if (In_Byte & 0x01){STREAM_7 += 1;}
49
              }
50
            if ((Stream_cnt >= 225) &(Stream_cnt <= 256))
51
              {
52
              STREAM_8 <<= 1;
53
              if (In_Byte & 0x01){STREAM_8 += 1;}
54
              }
55
            In_Byte >>= 1;
56
            Ctrl_Byte >>= 1;
57
            x -= 1;
58
            }
59
          }

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Kann man denn nicht den Zaehler x einfach weglassen? Wenn Ctrl_Byte 0 
ist, ist der Drops doch eh' fertig gelutscht.

Gruss
WK

von achim.s (Gast)


Lesenswert?

Dergute W. schrieb:
> Kann man denn nicht den Zaehler x einfach weglassen?

Da kann man soviel weglassen. Der UP hat wohl Orcans Version genommen, 
da war es schon drin. Da Orcan das eigentliche Problem (die Bytegrenzen) 
garnicht berücksichtigt hat, ist es so groß geworden.

Normal straight (und komplett) wäre sowas
1
typedef unsigned char BYTE;
2
BYTE STREAM[32];       /* wo immer diese Werte auch herkommen */
3
BYTE Kennung_Bits[181];/* so sind sie momentan im UP-Code */
4
5
void doit(void)
6
{
7
unsigned int l;
8
unsigned int bit_cnt = 0;
9
10
    for(l=0; l<=180; l++)
11
    {
12
    BYTE In_Byte = Kennung_Bits[l];
13
14
        while(In_Byte & 0x10)
15
        {
16
            STREAM[bit_cnt/8]<<1;
17
            STREAM[bit_cnt/8]+=B&1;
18
            In_Byte>>=1;
19
            if(++bit_cnt>255) {/* errorhandling hier */ return;}
20
        }        
21
    }
22
}

von achim.s (Gast)


Lesenswert?

achim.s schrieb:
> STREAM[bit_cnt/8]<<1;
STREAM[bit_cnt/8]<<=1;

und vermutlich noch mehr Flüchtigkeitsfehler....

von C. L. (calle)


Lesenswert?

Hi!


achim.s schrieb:
> Der UP hat wohl Orcans Version genommen,
> da war es schon drin. Da Orcan das eigentliche Problem (die Bytegrenzen)
> garnicht berücksichtigt hat, ist es so groß geworden.
Richtig, das fehlte, deswegen habe ich es mit den IF´s gemacht.

Was heisst denn UP? habe ich auf die schnelle nicht gefunden.
Kenne wohl TO oder TE...
Und was ist das mit dem B? Wo ist das denn initialisiert?
achim.s schrieb:
> STREAM[bit_cnt/8]+=B&1;

achim.s schrieb:
> BYTE STREAM[32];       /* wo immer diese Werte auch herkommen */
das ist der fertige "zusammengesetzte" Stream. Hatte oben ja geschrieben 
das der Compiler ein BIT Array nicht hinbekommt, oder ich bin zu d**f.
32*8 Bit ist quasi ein Container.

Ich finde es trotzdem erstaunlich, wie kompakt Ihr das dann oft macht.
Dazu fehlt mir noch die Erfahrung, scheinbar.
Ich werde auch diese Routine mal antesten, mache momentan aber erstmal 
mit dem Code weiter um erste Ergebnisse zu erzielen.

Dafür nochmal Thx!!!

von Orcan (Gast)


Lesenswert?

Wenn man nach verquast-überfrachteten Vorschlägen einen
praktikablen Lösungs-ANSATZ (!) bietet, wagen sich natürlich
wieder die Klugsch... aus der Deckung.

Hauptsache, der TO kam dem Ziel näher!
Freut mich.

von A. S. (Gast)


Lesenswert?

Orcan schrieb:
> wagen sich natürlich wieder die Klugsch... aus der Deckung

Du siehst aber schon, dass mein neuer Code meinem Alten entspricht?

Halt auf Deine Benamung umgestellt (weil der TO diese übernommen hat) 
und durch bitweise Verarbeitung halt kleiner. Ich dachte er wollte ein 
In_Byte auf einmal zu verarbeiten, darum hatte ich das ausgerollt. Du 
hast Deinen Beitrag ja auch erst nach der Konkretisierung des TO 
gepostet.

C. L. schrieb:
> Und was ist das mit dem B?
sorry, "B" ist "In_Byte".

STREAM[bit_cnt/8]+=In_Byte&1;

Orcans Version ist hier aber besser (lesbarer, wartbarer):
if (In_Byte & 0x01) {STREAM[bit_cnt/8]++;}


Thread-Owner (TO) und Urposter(UP) meinen (bei mir) das gleiche.

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.