Wil*_*ote 2 embedded int microcontroller gcc atmel
我的应用程序要求将值存储在16位计数器中,但是由于pcb问题,它要求将计数器的低8位反转(01001110至01110010)。该代码以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
Run Code Online (Sandbox Code Playgroud)
应该行吗?谢谢
您对该过程的单词描述是正确的,但是您的伪代码插图不准确且不完整。
你需要复制的LSB counter您清除之前; 否则,您将丢失需要反转的位。您需要正确清除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 ;
}
Run Code Online (Sandbox Code Playgroud)
你也应该使用stdint.h类型uint16_t,并uint8_t针对此操作而不是依赖于int被任何特定的大小-它将使代码的可移植性和可测试的系统,其中上int是不是16位。通常,在执行按位运算时,应使用无符号类型。
尽管可能需要更多的ROM空间,但是一种更快的方法是使用查找表。生成一个256字节的查找表非常麻烦,并且在ATtiny上,在内存使用方面相当高。相反,使用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] ;
Run Code Online (Sandbox Code Playgroud)
您甚至可以打包查找表并仅使用8个字节(0x80、0xC4等):
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) ;
Run Code Online (Sandbox Code Playgroud)
但是,通过增加额外的位操作来增加代码大小并不能证明查找表大小的减少是合理的,而且这样做有点“太聪明”,花了一段时间才把它弄对了!
第一种方法的优点是可以应用于任意数量的位。两种查找表解决方案都可以扩展为4位倍数的任何字长,而无需更改查找表大小,因此可以很好地扩展。
标杆管理
我在https://godbolt.org/上使用三种不同的优化设置对设置为AVR GCC 4.6.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 |
Run Code Online (Sandbox Code Playgroud)
该测试几乎没有说明执行时间,但是如果代码大小至关重要,则使用空间优化(-Os)的循环算法可能是最佳选择。
无论优化级别如何,查找表无疑都更快,并且采用任一优化的16字节查找表可能是一个合理的平衡。对于-O3它的整体,更小,比88指令展开循环更快。它还具有明显的优势,即通过优化设置,代码大小的可变性要小得多,这可以在调试版本和发行版本之间切换时最大程度地减少意外。
8字节查找没有什么好处,也许还有其他有趣之处。