Gcc 一个人如何颠倒“的低8位的顺序?”;int";值,并保持高位8位不变?

Gcc 一个人如何颠倒“的低8位的顺序?”;int";值,并保持高位8位不变?,gcc,int,embedded,microcontroller,atmel,Gcc,Int,Embedded,Microcontroller,Atmel,我的应用程序要求我将值存储在16位计数器中,但由于pcb问题,它要求计数器的低8位反转(01001110到011110010)。代码是用C(GCC)编写的,计数器寄存器是“int”类型(16位)。我的应用程序使用的是Atmel ATtiny 8位MCU。我知道,如果我将计数器寄存器声明为“int”类型,编译器将分配2个RAM位置。我是否只是用掩码提取低位字节,然后重新排列位,然后用类似的东西将它们粘贴回去 counter = counter & 0x00 clear lowe

我的应用程序要求我将值存储在16位计数器中,但由于pcb问题,它要求计数器的低8位反转(01001110到011110010)。代码是用C(GCC)编写的,计数器寄存器是“int”类型(16位)。我的应用程序使用的是Atmel ATtiny 8位MCU。我知道,如果我将计数器寄存器声明为“int”类型,编译器将分配2个RAM位置。我是否只是用掩码提取低位字节,然后重新排列位,然后用类似的东西将它们粘贴回去

counter = counter & 0x00       clear lower byte value
counter = counter + (register with the reversed 8 bits)   

// Then, Replace lower byte value with new value
这样行吗? 谢谢你的打字错误:

应该是

counter = counter & 0xFF00;

清除低位字节。您可以通过一次旋转一位到另一个变量来反转位。如果计时非常关键,您需要在组装中执行此操作,因为C没有旋转操作符,并且必须模拟特征,例如

new_byte = 0;

if (orig_byte & 0x80)
    new_byte |= 0x01;

if (orig_byte & 0x40)
    new_byte |= 0x02;
...
etc.可能是C语言中最快的方法之一。 或者,如果您可以节省256字节的闪存,那么只需使用一个表,例如

__flash unsigned char rotated_bytes[] = { 0x00, 0x80, 0x40, 0xC0, 0x20, ... };

new_byte = rotated_byte[orig_byte];

(用编译器的扩展关键字替换“flash”,表示“程序内存”)

您对过程的文字描述是正确的,但您的伪代码说明不准确且不完整

您需要先复制
计数器的LSB,然后才能清除它;否则,您将丢失需要反转的位。您需要正确清除LSB,并且您可以按如下方式将LSB位直接反转回计数器LSB:

// Copy counter LSB
uint8_t lsb = (uint8_t)(counter & 0xFFu) ;

// Clear counter LSB
counter &= 0xff00u ;

// Reverse LSB bits and mask into counter LSB
for( uint8_t mask = 0x80u;  
     mask != 0; 
     lsb >>= 1, mask >>= 1 )
{
    counter |= ((lsb & 0x01u) != 0) ? mask : 0 ;
}
您还应该使用stdint.h类型
uint16\u t
uint8\u t
进行此操作,而不是依赖
int
作为任何特定的大小-这将使代码在
int
不是16位的系统上更易于移植和测试。通常,在执行逐位操作时,应该使用无符号类型

一种稍微快一点的方法是使用查找表,尽管可能需要更多的ROM空间。256字节的查找表生成起来相当麻烦,而且在内存使用方面也相当禁止。相反,使用16字节查找几乎同样有效,如下所示:

// Copy counter LSB
uint8_t lsb = (uint8_t)(counter & 0xFFu) ;

// Clear counter LSB
counter &= 0xff00u ;

static const uint8_t lookup[] = { 0x0, 0x8, 0x4, 0xC, 
                                  0x2, 0xA, 0x6, 0xE, 
                                  0x1, 0x9, 0x5, 0xD, 
                                  0x3, 0xB, 0x7, 0xF } ;

counter |= lookup[lsb & 0xf] << 4 | lookup[lsb >> 4] ;
测试很少涉及执行时间,但如果代码大小很关键,那么带有空间优化的循环算法(
-Os
)可能是最佳选择

无论优化级别如何,查找表无疑都会更快,并且具有任一优化的16字节查找表可能是一种合理的平衡。对于
-O3
而言,它比88指令展开循环整体更小更快。它还有一个明显的优点,即代码大小的变化要小得多,优化设置可以在调试和发布版本之间切换时将意外情况降至最低


8字节的查找除了非常有趣之外几乎没有什么优点。

在字节中反转位的简单方法是使用联合和位字段,如下所示

> struct ST_BYTE {
    unsigned char b0    :   1;
    unsigned char b1    :   1;
    unsigned char b2    :   1;
    unsigned char b3    :   1;
    unsigned char b4    :   1;
    unsigned char b5    :   1;
    unsigned char b6    :   1;
    unsigned char b7    :   1;

} ;

union  U_BYTE
{
    struct ST_BYTE byteflag;
    unsigned char charflag;
};
unsigned char Reverse_Bits_in_Byte(U_BYTE local_byte)
{
    U_BYTE Byte_Var2;

    Byte_Var2.byteflag.b0 =local_byte.byteflag.b7;
    Byte_Var2.byteflag.b1 =local_byte.byteflag.b6;
    Byte_Var2.byteflag.b2 =local_byte.byteflag.b5;
    Byte_Var2.byteflag.b3 =local_byte.byteflag.b4;
    Byte_Var2.byteflag.b4 =local_byte.byteflag.b3;
    Byte_Var2.byteflag.b5 =local_byte.byteflag.b2;
    Byte_Var2.byteflag.b6 =local_byte.byteflag.b1;
    Byte_Var2.byteflag.b7 =local_byte.byteflag.b0;

    return (Byte_Var2.charflag);

}
void main()
{

    int i;
    for(i=0;i<8;i++)
    {
        Byte_Var1.charflag = pow(2,i);
        printf("\nBefore Reverse %02X\n", Byte_Var1.charflag);
        Byte_Var1.charflag = Reverse_Bits_in_Byte(Byte_Var1);
        printf("\nAfter Reverse %02X\n", Byte_Var1.charflag);
    }


}
结构ST_字节{ 无符号字符b0:1; 无符号字符b1:1; 无符号字符b2:1; 无符号字符b3:1; 无符号字符b4:1; 无符号字符b5:1; 无符号字符b6:1; 无符号字符b7:1; } ; 联合U_字节 { struct ST_BYTE byteflag; 无符号字符标志; }; 无符号字符反向字节(U字节本地字节) { U_字节BYTE_Var2; Byte_Var2.byteflag.b0=local_Byte.byteflag.b7; Byte_Var2.byteflag.b1=local_Byte.byteflag.b6; Byte_Var2.byteflag.b2=local_Byte.byteflag.b5; Byte_Var2.byteflag.b3=local_Byte.byteflag.b4; Byte_Var2.byteflag.b4=local_Byte.byteflag.b3; Byte_Var2.byteflag.b5=本地_Byte.byteflag.b2; Byte_Var2.byteflag.b6=local_Byte.byteflag.b1; Byte_Var2.byteflag.b7=local_Byte.byteflag.b0; 返回(Byte_Var2.charflag); } void main() { int i; 对于(i=0;i这里我的方法:

uint16_t Flipper(uint8_t hi, uint8_t reversed_lo)
{
    uint8_t lo=0;
    if (reversed_lo & 0x01) lo |= 0x80;
    if (reversed_lo & 0x02) lo |= 0x40;
    if (reversed_lo & 0x04) lo |= 0x20;
    if (reversed_lo & 0x08) lo |= 0x10;
    if (reversed_lo & 0x10) lo |= 0x08;
    if (reversed_lo & 0x20) lo |= 0x04;
    if (reversed_lo & 0x40) lo |= 0x02;
    if (reversed_lo & 0x80) lo |= 0x01;
    return (hi<<8) | lo;
}

这就是我要做的。如果你的处理器有一个反向位操作,这可能是最快的方法,否则,反向操作也不算太糟糕。关于如何做,这里有很多例子。仅供参考,你的按位and语句将清除所有位。如果它是一个计数器,它应该类似于
计数器&=0xFF00
16位的value.and与0xFF00.plus一起工作,但与位相关太多或感觉更好。plus没有错…不要依赖任何特定大小的
int
-或使用带符号的类型,使用
uint16\u t
。不要发布“谢谢”答案(甚至评论)问答不是讨论论坛。你通过接受和/或向上投票的答案来表达对问答的赞赏。你的查找表值不正确,所需的操作不是“轮换”在任何情况下。当问题中没有提到任何要求时,您也强调了性能-这是一个过早的优化。您是对的,我在写表格时脑子有问题。我开始写0b10000000、0b01000000、0b11000000等等。不知怎的,我说,“让我们用小数来做,把它弄得一团糟。哎呀。阿提尼有2K到16K的闪存rom,所以我相信优化最终会变得很重要,即使不是马上。此外,在嵌入式编程中,把空间和代码的权衡看作是“技巧袋”是很好的。是的,我的意思是写“移出”位。也许吧,但内存限制表明更可能进行空间优化而不是时间优化,并且展开循环或查找都不节省代码空间。您可能已经更正了查找-我已经为您修复了它。一个好的折衷办法是对半字节(4位)进行16字节的查找值。使用八个
if
s的简单方法是最好的。Atmel提供了很好的位操作指令。我的gcc将
if(orig_byte&0x40)new_byte |=0x02;
转换为两条汇编指令!(SBRC:如果寄存器中的位被清除,则跳过下一条指令,然后是
static const uint8_t lookup[] = { 0x80, 0xC4, 
                                  0xA2, 0xE6,  
                                  0x91, 0xD5,  
                                  0xB3, 0xF7 } ;

uint8_t msnib = ( lsb & 0x01 ) ? lookup[(lsb & 0xf) >> 1] >> 4 : 
                                 lookup[(lsb & 0xf) >> 1] & 0xf ;

uint8_t lsnib = ( lsb & 0x10 ) ? lookup[(lsb & 0xf0) >> 5] >> 4 : 
                                 lookup[(lsb & 0xf0) >> 5] & 0xf ;
counter |= (lsnib | msnib << 4) ;
|          |  Instruction Count |               |
|Algorithm | No Opt | -O3 | -Os | + Data (bytes)|
|----------|:------:|:---:|:---:|:-------------:|
| Loop     |   38   |  88 |  23 |       0       |
| LookUp16 |   59   |  38 |  37 |      16       |
| LookUp8  |  137   |  65 |  62 |       8       |
> struct ST_BYTE {
    unsigned char b0    :   1;
    unsigned char b1    :   1;
    unsigned char b2    :   1;
    unsigned char b3    :   1;
    unsigned char b4    :   1;
    unsigned char b5    :   1;
    unsigned char b6    :   1;
    unsigned char b7    :   1;

} ;

union  U_BYTE
{
    struct ST_BYTE byteflag;
    unsigned char charflag;
};
unsigned char Reverse_Bits_in_Byte(U_BYTE local_byte)
{
    U_BYTE Byte_Var2;

    Byte_Var2.byteflag.b0 =local_byte.byteflag.b7;
    Byte_Var2.byteflag.b1 =local_byte.byteflag.b6;
    Byte_Var2.byteflag.b2 =local_byte.byteflag.b5;
    Byte_Var2.byteflag.b3 =local_byte.byteflag.b4;
    Byte_Var2.byteflag.b4 =local_byte.byteflag.b3;
    Byte_Var2.byteflag.b5 =local_byte.byteflag.b2;
    Byte_Var2.byteflag.b6 =local_byte.byteflag.b1;
    Byte_Var2.byteflag.b7 =local_byte.byteflag.b0;

    return (Byte_Var2.charflag);

}
void main()
{

    int i;
    for(i=0;i<8;i++)
    {
        Byte_Var1.charflag = pow(2,i);
        printf("\nBefore Reverse %02X\n", Byte_Var1.charflag);
        Byte_Var1.charflag = Reverse_Bits_in_Byte(Byte_Var1);
        printf("\nAfter Reverse %02X\n", Byte_Var1.charflag);
    }


}
uint16_t Flipper(uint8_t hi, uint8_t reversed_lo)
{
    uint8_t lo=0;
    if (reversed_lo & 0x01) lo |= 0x80;
    if (reversed_lo & 0x02) lo |= 0x40;
    if (reversed_lo & 0x04) lo |= 0x20;
    if (reversed_lo & 0x08) lo |= 0x10;
    if (reversed_lo & 0x10) lo |= 0x08;
    if (reversed_lo & 0x20) lo |= 0x04;
    if (reversed_lo & 0x40) lo |= 0x02;
    if (reversed_lo & 0x80) lo |= 0x01;
    return (hi<<8) | lo;
}
;reversed_lo sits in R22
;hi          sits in R21
;lo          goes to R18
000007DF 60.fd                SBRC R22,0        Skip if bit in register cleared 
000007E0 02.c0                RJMP PC+0x0003        Relative jump 
000007E1 20.e0                LDI R18,0x00      Load immediate 
000007E2 01.c0                RJMP PC+0x0002        Relative jump 
000007E3 20.e8                LDI R18,0x80      Load immediate 
000007E4 61.fd                SBRC R22,1        Skip if bit in register cleared 
000007E5 20.64                ORI R18,0x40      Logical OR with immediate 
000007E6 62.fd                SBRC R22,2        Skip if bit in register cleared 
000007E7 20.62                ORI R18,0x20      Logical OR with immediate 
000007E8 63.fd                SBRC R22,3        Skip if bit in register cleared 
000007E9 20.61                ORI R18,0x10      Logical OR with immediate 
000007EA 64.fd                SBRC R22,4        Skip if bit in register cleared 
000007EB 28.60                ORI R18,0x08      Logical OR with immediate 
000007EC 65.fd                SBRC R22,5        Skip if bit in register cleared 
000007ED 24.60                ORI R18,0x04      Logical OR with immediate 
000007EE 66.fd                SBRC R22,6        Skip if bit in register cleared 
000007EF 22.60                ORI R18,0x02      Logical OR with immediate 
000007F0 66.23                TST R22       Test for Zero or Minus 
000007F1 0c.f4                BRGE PC+0x02      Branch if greater or equal, signed 
000007F2 21.60                ORI R18,0x01      Logical OR with immediate 
000007F3 30.e0                LDI R19,0x00      Load immediate 
000007F4 a9.01                MOVW R20,R18      Copy register pair 
000007F5 58.2b                OR R21,R24        Logical OR 
000007F6 ca.01                MOVW R24,R20      Copy register pair 
000007F7 08.95                RET       Subroutine return