Hallo! Ich habe ein Array von 54 Byte in meinem ATmega 644p, über SPI eingelesene Werte. Nun interessiert mich jedes dritte Bit, also aus dem ersten Byte die Positionen 2 und 5, aus dem 2. Byte die 0, 3 und 6, dann aus dem dritten Byte 1,4 und 7, dann gehts wieder von vorne los. Wie code ich sowas effizient? Der Rest des Programms ist C, inline asm würde aber zur Not auch gehen. Im Prinzip würde ich gern Bit [2] testen, drei mal rechtsschieben, Bit[2} testen, schieben, testen,... Aber ich kann ja schlecht die kompletten 54 Byte am Stück schieben. Müsste also im Prinzip 2Byte schieben, und wenn der Inhalt des oberen Byte komplett raus geschoben ist, das nächste Byte nachladen. Hat jemand spontan eine bessere Idee? Fehlen noch wesentliche Infos, die ich bislang vergessen hab mitzuteilen? Grüße, Christoph
Was willst du denn mit den Bits dann machen? Das wär noch interessant. Im prinzip könntest du schon die 56 Byte durschschieben. In Assambler mit cpc, dauert halt etwas... ich denke, ich würde mir eine Schleife bauen, die immer 3 Byte auf die von dir genannten Bits testet (explizit die drei bit, ohne schieben) und dann die nächsten 3 Byte durchmacht. Dürfte wohl am schnellsten gehn. Aber genau sagen kann man das erst, wenn man weiß, was mit den Bits dann passieren soll. Sebastian
Christoph schrieb: > würde aber zur Not auch gehen. Im Prinzip würde ich gern Bit [2] testen, > drei mal rechtsschieben, Bit[2} testen, schieben, testen,... Das klingt soch schon fast wie wenn es ein vernünftiges Konzept wäre. Die Frage ist nur, was du unter 'testen' verstehst. > Aber ich > kann ja schlecht die kompletten 54 Byte am Stück schieben. Ah, geh. Deine Abfolge wiederholt sich doch alle 3 Bytes. Und zufällig ergeben die auch noch in Summe 8 Bits. Passt doch perfekt. Die Zählung versteh ich nicht ganz: > also aus dem > ersten Byte die Positionen 2 und 5, aus dem 2. Byte die > 0, 3 und 6, dann aus dem dritten Byte 1,4 und 7, + + + + + + + + 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 Byte n Byte n+1 Byte n+2 Jeweils die mit + markierten Bits möchtest du haben
1 | j = 0; |
2 | for( i = 0; i < 54; i = i + 3 ) |
3 | Result[j++] = ( ( Data[i] & 0x20 ) << 2 ) | // Bit 7 |
4 | ( ( Data[i] & 0x04 ) << 4 ) | // 6 |
5 | ( ( Data[i+1] & 0x80 ) >> 2 ) | // 5 |
6 | ( ( Data[i+1] & 0x10 ) ) | // 4 |
7 | ( ( Data[i+1] & 0x02 ) << 2 ) | // 3 |
8 | ( ( Data[i+2] & 0x40 ) >> 4 ) | // 2 |
9 | ( ( Data[i+2] & 0x08 ) >> 2 ) | // 1 |
10 | ( ( Data[i+2] & 0x01 ) // 0 |
11 | ;
|
In Result hast du jetzt nur noch die dich interessierenden Bits in der richtigen Reihenfolge.
In den 54 Byte stecken 144 Input Pins, die ich aus einer Boundary Scan Kette eingelesen habe. Je Pin gibts drei Bit, Input, Output, Output Enable. Für den Status interessiert mich in diesem Fall nur der Input. Alle Inputs, die auf low-Pegel liegen, werden in einen Puffer eingetragen. Ich teste also "wenn am dritten Bit des i-ten Triple low Pegel ist, schreibe i in den Puffer". Vermutlich ist Überprüfen von je drei Byte geschickter und schneller, als die ganze Manipulation des Arrays, und auch besser als das ausknobeln, an welcher Stelle ich nun prüfe. Ich muss alle 144 Pins nacheinander durchscannen und Werte zurückschreiben, daher ist das ganze schon ein wenig zeitkritisch.
Christoph schrieb: > In den 54 Byte stecken 144 Input Pins, die ich aus einer Boundary Scan > Kette eingelesen habe. Je Pin gibts drei Bit, Input, Output, Output > Enable. Für den Status interessiert mich in diesem Fall nur der Input. > Alle Inputs, die auf low-Pegel liegen, werden in einen Puffer > eingetragen. Ich teste also "wenn am dritten Bit des i-ten Triple low > Pegel ist, schreibe i in den Puffer". Ach sag das doch gleich. Da muss man doch gar nicht die Bits extra extrahieren. Du fasst dein ByteArray als fortlaufendes Bitarray auf. Bit Nr x findet sich dann in Byte x / 8 Und dort ist es das Bit an der Position 7 - ( x % 8 ) Um das dich interessierende Statusbits des Sensors i zu finden, suchst du also nach dem Bit Nr 3 * i + 2 Astelle des extensiven Schiebens bei der Ausmaskierung des Bits, würd ich eine Tabelle mit Masken nehmen.
1 | uint8_t bitMask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; |
2 | |
3 | uint8_t isSet( uint8_t sensorNr, uint8_t bitOffset ) |
4 | {
|
5 | uint8_t bitNr = sensorNr * 3 + bitOffset; // jeweils 3 Bits pro Sensor |
6 | uint8_t byteNr = bitNr / 8; |
7 | uint8_t maskNr = 7 - bitNr % 8; |
8 | |
9 | if( data[byteNr] & bitMask[maskNr] ) |
10 | return 1; |
11 | return 0; |
12 | }
|
13 | |
14 | uint8_t isStatusSet( uint8_t sensorNr ) |
15 | {
|
16 | return isSet( sensorNr, 2 ); // status ist das 3-te Bit des Triplets |
17 | }
|
18 | |
19 | uint8_t isInputSet( uint8_t sensorNr ) |
20 | {
|
21 | return isSet( sensorNr, 1 ); // input ist das 2-te Bit des Triplets |
22 | }
|
23 | |
24 | uint8_t isOutputSet( uint8_t sensorNr ) |
25 | {
|
26 | return isSet( sensorNr, 0 ); // output ist das 1-te Bit des Triplets |
27 | }
|
> Ach sag das doch gleich. Sorry. :-) Ich bin noch ziemlich unerfahren im Programmieren, manchmal fehlt mir noch der Blick für die wirklich relevanten Infos... > + + + + + + + + > 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 > Byte n Byte n+1 Byte n+2 fast. Die Bytes n+1 und n+2 müssen getauscht werden: + + + + + + + + 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 Byte n Byte n+1 Byte n+2 Um das ganze nicht per Funktionsaufruf zu machen, wäre das ganze dann so zu lösen, oder (Maske umsortiert, spart wieder berechnungs-Aufwand):
1 | uint8_t bitMask[] = {0x04, 0x20, 0x01, 0x08, 0x40, 0x02, 0x10, 0x80}; |
2 | for (i=0; i<54;i++){ |
3 | uint8_t byteNr = (i * 3) / 8; |
4 | if (!(bsInBuffer[byteNr] & bitMask[i%8])) addTxBuffer(i); |
5 | }
|
6 | }
|
Vielen Dank schonmal für deine/eure Hilfe!
Christoph schrieb: >> + + + + + + + + >> 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 >> Byte n Byte n+1 Byte n+2 > > fast. Die Bytes n+1 und n+2 müssen getauscht werden: > > + + + + + + + + > 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 > Byte n Byte n+1 Byte n+2 Dann stimmt an deiner Zählerei etwas nicht :-) <Zitat> Nun interessiert mich jedes dritte Bit </Zitat> Fang links zum zählen an und zähl jedes dritte Bit. Ahhhh. Du fängst bei 0 an zu zählen. Ja geht auch. Siehst du, das sind so die kleinen Informationen. Ehe man sich ein Verfahren überlegt, muss man exakt wissen, was wo steht, in welcher Richtung gezählt wird, etc. Drum ist es immer gut, sich ein Schaubild zu malen. Die sind nämlich meist ziemlich eindeutig, was man von textuellen Beschreibungen nicht sagen kann. > Um das ganze nicht per Funktionsaufruf zu machen, kannst du machen. Aber wahrscheinlich wird der Compiler sowieso da eine inline Version daraus generieren :-): Genauso, wie er lokale Variablen rausschmeissen wird. > wäre das ganze dann so > zu lösen, oder (Maske umsortiert, spart wieder berechnungs-Aufwand): Da deine Zählweise anders rum ist, hebt sich das dann auf :-) Also Maske so wie bei mir, aber Berechnung der MaskenNr als i % 8 > [c] > uint8_t bitMask[] = {0x04, 0x20, 0x01, 0x08, 0x40, 0x02, 0x10, 0x80}; Die ist dir wohl etwas durcheinandergekommen :-) uint8_t byteNr = (i * 3) / 8; if (!(bsInBuffer[byteNr] & bitMask[i%8])) Stimmt auch nicht. i ist nicht die Bitnummer. Lass doch die Hilfs-Variablen drinnen, wenn du ansonsten durcheinander kommst. Dein Compiler kann viel besser optimieren, als du denkst. Der schmeisst sie dann wieder raus bzw. hält das Zwischenergbenis in einem Register. Aber die Übersicht ist für dich als Programmierer mit den Hilfsvariablen viel besser! Solche Low-Level Optimierungen wie Funktionen inlinen oder Hilfsvariablen eliminieren oder konstante Ausdrücke zusammenfassen, überlasst man am Besten dem Compiler. Probiers mit Papier und Bleistift durch. Oder mach erst mal eine Version am PC und lass dir die ByteNr und die Maske ausgeben. Dann siehst du sehr schnell, ob die Zugriffe dort sind, wo du sie haben möchtest.
Aber eine Optimierung, für die ich meine Hand nicht ins Feuer legen würde, dass sie der Optimizer schafft, ist diese hier
1 | for (i = 0, bitNr = 0; i < 54; i++, bitNr += 3 ) |
2 | {
|
3 | if( !(bsInBuffer[bitNr/8] & bitMask[bitNr%8]) ) |
4 | addTxBuffer( i ); |
5 | }
|
6 | }
|
Damit bist du die (kostspielige) Multiplikation mit 3 innerhalb der Schleife los. Manche Optimizer finden sowas raus, manche nicht.
Nur so als Idee, wenn es auf zeit ankommt: Der AVR kann in den unteren Registern auch Bit-Operationen direkt durchführen. D.h. er kann set, clr, tst... in einem Zyklus auf ein Bit eines der unteren Register anwenden. Das wird vermutlich einen längeren Assembler Code erfordern, aber an Geschwindigkeit kaum zu übertreffen sein. ATMEL hat für solche Operationen bei den neueren CPUs extra ein 'virtulles' GPIO Register dort unten abgelegt (GPIOR0). Es kann mit allen Bit-Befehlen angesteuert werden, die auch die I/O-Ports unterstützen, nur das an diesem Register eben keine realen I/O Pinne hängen. Gruß, Ulrich
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.