我正在進入微控制器黑客行爲,雖然我很熟悉按位運算符和正確的硬件說話,但我發現代碼非常冗長,並且沒有樣板。我的高級程序員想要找到一種有效但有效的方法來清理它。C預處理器宏將位域打包爲一個字節?
例如,有一個在寄存器中很多設置的標誌:
/* Provided by the compiler */
#define SPIE 7
#define SPE 6
#define DORD 5
#define MSTR 5
#define CPOL 4
#define CPHA 3
void init_spi() {
SPCR = (1 << SPE) | (1 << SPIE) | (1 << MSTR) | (1 << SPI2X);
}
值得慶幸的是還有一些隱藏實際的端口IO操作(左側)宏,所以它看起來像一個簡單的任務。但是,對我來說,所有的語法都是混亂的。
的要求是:
- 它只有處理多達8位,
- 位位置必須能夠以任意順序進行傳遞,並
- 應該只需要設置位被通過。
我想的語法是:
SPCR =位(SPE,SPIE,MSTR,SPI2X);
我想出迄今最好的是一個組合的宏/功能:
#define bits(...) __pack_bits(__VA_ARGS__, -1)
uint8_t __pack_bits(uint8_t bit, ...) {
uint8_t result = 0;
va_list args;
va_start(args, bit);
result |= (uint8_t) (1 << bit);
for (;;) {
bit = (uint8_t) va_arg(args, int);
if (bit > 7)
break;
result |= (uint8_t) (1 << bit);
}
}
這將編譯在我的特定構建築32個字節,並採取61-345週期執行(取決於有多少位通過)。
理想情況下本應在預處理器來完成,因爲結果是恆定的,並且輸出機器指令shouldBe這樣只是一個8位的值與寄存器的分配。
這可以做得更好嗎?
這可能是我會如果沒有做已經由特定架構的編譯器支持定義位的位置定義(在這種情況下avr-gcc)。 我覺得很蠢。如果有任何地方他們必須使用,而不是作爲左移參數...我找不到它。但是它就是這樣啊。 –
此外,我目前看到的代碼在使用1 << XX表單和使用_BV(XX)之間有所不同。 _BV是提供的宏(1 << n)。但這仍然意味着打字太多。 –
好主意。但是出於安全原因,我會加上一些大括號,如果你知道,宏可以是討厭的。想象有人使用BIT(5-1)的宏... – Roland