AVR清洁引脚混叠解决方案 - 枚举I / O位

时间:2014-12-21 20:22:36

标签: c avr avr-gcc

我在Arduino设备上使用C语言,其中的引脚标记不同。我使用的是PLAIN C,而不是Arduino的“语言”。

每个引脚由其端口(例如PORTB)和端口中的引脚(位)定义(例如PB0)。

我想简洁别名别名,所以我可以制作宏或函数,就像Arduino使用的那样:

pin_direction(D2, 1); // D2 as output
set_pin(D2, 0); // write zero to D2
pin_direction(D3, 0); // D3 as input
enable_pullup(D3, 1); // enable D3 pullup

相反(atm)我必须使用像这样丑陋的东西:

#define D0 0
#define D1 1
#define D2 2
#define D3 3
...
#define D10 2
#define D11 3

#define PORT_D0 PORTD
#define PORT_D1 PORTD
#define PORT_D2 PORTD
#define PORT_D3 PORTD
...
#define PORT_D10 PORTB
#define PORT_D11 PORTB

// the same for PIN_xx and DDR_xx

然后我可以使用宏来完成工作:

#define sbi(port, bit) (port) |= _BV(bit)
#define cbi(port, bit) (port) &= ~ _BV(bit)

sbi(DDR_D2, D2); // D2 to output
cbi(PORT_D2, D2); // D2 to output
sbi(DDR_D3, D3); // D3 as input
sbi(PORT_D3, D3); // D3 pullup enable

现在这样可行,但它非常混乱。任何想法 - 如果没有巨大的switch之类的怪物开销 - 做得更好 - 更像我的第一个例子?以某种方式枚举所有位,然后动态解析正确的寄存器?

我正在使用avr-libc avr-gcc。

2 个答案:

答案 0 :(得分:3)

您可以定义扩展为多个令牌的宏,例如

#define PIN_D0    PORTD, 0
#define PIN_D1    PORTD, 1
...
#define PIN_D10   PORTB, 2

然后在宏中使用它们,例如:

sbi(PIN_D0);  // expands to sbi(PORTD, 0)

可能对这些宏有用的一些实用程序宏是:

#define PORT_OF(port, bit) port
#define BIT_OF(port, bit)  bit

可以在以下语境中使用:

PORT_OF(PIN_D10)  // expands to PORTB
BIT_OF(PIN_D10)   // expands to 2

答案 1 :(得分:1)

这是我使用的解决方案。

在我的util.h中(我所有的AVR项目都很常见):

#define DDR_REG(port) DDR ## port
#define PORT_REG(port) PORT ## port
#define PIN_REG(port) PIN ## port

#define SET_BIT(port, bit) do { (port) |= (1 << (bit)); } while(0)
#define CLR_BIT(port, bit) do { (port) &= ~(1 << (bit)); } while(0)
#define BIT_IS_SET(port, bit) ((((uint8_t)(port)) >> ((uint8_t)(bit))) & 0x1)

#define IO_SET_INPUT_AUX(port, bit) CLR_BIT(DDR_REG(port), bit)
#define IO_SET_AS_INPUT(io) IO_SET_INPUT_AUX(io)

#define IO_SET_OUTPUT_AUX(port, bit) SET_BIT(DDR_REG(port), bit)
#define IO_SET_AS_OUTPUT(io) IO_SET_OUTPUT_AUX(io)

#define IO_OUTPUT_0_AUX(port, bit) CLR_BIT(PORT_REG(port), bit)
#define IO_OUTPUT_0(io) IO_OUTPUT_0_AUX(io)

#define IO_OUTPUT_1_AUX(port, bit) SET_BIT(PORT_REG(port), bit)
#define IO_OUTPUT_1(io) IO_OUTPUT_1_AUX(io)

#define IO_GET_INPUT_AUX(port, bit) BIT_IS_SET(PIN_REG(port), bit)
#define IO_GET_INPUT(io) IO_GET_INPUT_AUX(io)

在我的pin映射文件中:

#define UPBTN_IO B,7
#define DOWNBTN_IO D,0
#define ENTERBTN_IO D,1
(etc)

在代码中:

IO_SET_AS_INPUT(UPBTN_IO);

这依赖于一些有趣的预处理器位,就像在宏参数上只有一轮宏扩展一样。