Hallo zusammen, hat jemand einen Tipp wie zwei Bytes bitweise-alternierend zusammengefügt werden können. first Byte: [a b c d e f g h] second Byte: [1 2 3 4 5 6 7 8] -> Word(16Bit): [a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8] Danke.
1 | uint16_t u16Result = 0; |
2 | uint8_t u8A = 0b10101010; |
3 | uint8_t u8B = 0b01010101; |
4 | |
5 | for(uint8_t i = 0; i < 8; i++){ |
6 | if(u8A & (1<<i)) u16Result |= (1<<(i*2)); |
7 | if(u8B & (1<<i)) u16Result |= (1<<(i*2+1)); |
8 | }
|
for i= 0 bis 7 Word(16Bit) = Word(16Bit) | ((firstByte>>(7-i))&1) Word(16Bit) = Word(16Bit)<<1 Word(16Bit) = Word(16Bit) | ((secondByte>>(7-i))&1) Word(16Bit) = Word(16Bit)<<1 EndFor
So als Lösungsansatz (mein Assembler ist etwas eingestaubt). Eine Schiebeoperation sorgt dafür, dass das rausgeschobene Bit im Carry landet. Dann kann man ein "AddWithCarry" mit 0 machen, und das Ergebnis entsprechend weiterschieben. Das Ganze in einer kleinen Schleife.
vllt so? schrieb: > for i= 0 bis 7 > > Word(16Bit) = Word(16Bit) | ((firstByte>>(7-i))&1) > Word(16Bit) = Word(16Bit)<<1 > > Word(16Bit) = Word(16Bit) | ((secondByte>>(7-i))&1) > Word(16Bit) = Word(16Bit)<<1 > > EndFor uint16_t u16Result = 0; uint8_t u8A = 0b10101010; uint8_t u8B = 0b01010101; for(uint8_t i = 0; i < 8; i++){ u16Result |= u8A & 1; u8A >> 1; u16Result << 1; u16Result |= u8B & 1; u8B >> 1; u16Result << 1; }
result = fb[7] sb[7] fb[6] sb[6] fb[5] sb[5] fb[4] sb[4] fb[3] sb[3] fb[2] sb[2] fb[1] sb[1] fb[0] sb[0]; [] ist der Bit-Indizierungsoperator.
Ben S. schrieb: > uint16_t u16Result = 0; > uint8_t u8A = 0b10101010; > uint8_t u8B = 0b01010101; > > for(uint8_t i = 0; i < 8; i++){ > u16Result |= u8A & 1; > u8A >> 1; > u16Result << 1; > > u16Result |= u8B & 1; > u8B >> 1; > u16Result << 1; > } Fehler, dies getestet:
1 | uint16_t combine (uint8_t u8A, uint8_t u8B) { |
2 | uint16_t u16Result = 0; |
3 | |
4 | for (uint8_t i = 0; i < 8; i++) { |
5 | u16Result |= u8A & 1; |
6 | u8A >>= 1; |
7 | u16Result <<= 1; |
8 | |
9 | u16Result |= u8B & 1; |
10 | u8B >>= 1; |
11 | u16Result <<= 1; |
12 | }
|
13 | |
14 | return u16Result; |
15 | }
|
Alles klar. Damit kann ich etwas anfangen. Mir ging es primär um die Logik. Programmieren müsste ich das in SCL (SPS). Danke.
Ohne Schleife:
1 | int16_t shuffle16(std::uint8_t a, std::uint8_t b) |
2 | {
|
3 | uint16_t val = static_cast<uint16_t>(a) << 8 | b; |
4 | uint16_t mask; |
5 | mask = (val ^ (val >> 4)) & 0x00f0; |
6 | val = val ^ mask ^ (mask << 4); |
7 | mask = (val ^ (val >> 2)) & 0x0c0c; |
8 | val = val ^ mask ^ (mask << 2); |
9 | mask = (val ^ (val >> 1)) & 0x2222; |
10 | val = val ^ mask ^ (mask << 1); |
11 | |
12 | return val; |
13 | }
|
Caligulaminus schrieb: > Ohne Schleife: Auch schön, jedoch sollte man manchmal eine lesbare Version vorziehen. Zumindest finde ich deine Lösung nicht intuitiv - ist aber nur meine Meinung.
Ben S. schrieb: > uint16_t combine (uint8_t u8A, uint8_t u8B) { > uint16_t u16Result = 0; > > for (uint8_t i = 0; i < 8; i++) { > u16Result |= u8A & 1; > u8A >>= 1; > u16Result <<= 1; > > u16Result |= u8B & 1; > u8B >>= 1; > u16Result <<= 1; > } > > return u16Result; > } Die Schieberei am Ende liefert falsches Ergebnis.
1 | for (uint8_t i = 0; i < 8; i++) { |
2 | u16Result <<= 1; |
3 | u16Result |= u8A & 1; |
4 | u8A >>= 1; |
5 | |
6 | u16Result <<= 1; |
7 | u16Result |= u8B & 1; |
8 | u8B >>= 1; |
9 | }
|
In Assembler würde ich das angesichts heutiger Prozessoren "Speedcode-Style" schreiben, also 32 einfache Bitshifts über Carry, fertig. Vielleicht nicht ganz so elegant wie mit einer Schleife, aber moderne Prozessoren mit ihren großen Caches und Optimierungen dürften das in wenigen Takten erledigt haben und die paar Byte mehr Speicherplatzbedarf fallen heute nicht mehr auf.
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.