我想要做的是使用宏访问代码。但编译器给了我这个错误
标识符“BUTTON___button”未定义
#define BUTTON_1 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8)
#define BUTTON_2 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9)
#define BUTTON_3 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
#define BUTTON_4 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)
#define BUTTON_5 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)
#define BUTTON_6 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_14)
#define BUTTON_7 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_12)
#define BUTTON_8 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_11)
#define BUTTON_9 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15)
#define BUTTON_10 HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_0)
#define BUTTON_11 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_10)
#define BUTTON_12 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)
#define BUTTON_13 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)
#define BUTTON_14 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_2)
#define BUTTON_15 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11)
#define BUTTON_16 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2)
#define BUTTON_17 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_0)
#define BUTTON_18 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1)
#define BUTTON_19 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5)
#define BUTTON_20 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4)
#define BUTTON(...) BUTTON_##__VA_ARGS__
for(uint8_t _button = 1; _button < 21; _button++)
BUTTON(__button) //=> This should give me BUTTON(1) , BUTTON(2) ... each iteration.But not working
通过使用可变参数宏,我能得到我想要的吗?
答案 0 :(得分:6)
您必须记住,预编译器事件是在编译代码之前发生的,并且是严格的纯文本替换。
因此,取决于由于运行时循环而具有不同值的变量是没有意义的,并且不起作用。
执行此操作的正确方法是将端口地址(GPIOA
等)与每个端口的相应引脚一起放在一个数组中:
static const struct {
const GPIO_TypeDef *port;
uint32_t pin;
} buttons[] = {
{ GPIOB, GPIO_PIN_8 },
{ GPIOB, GPIO_PIN_9 },
...
};
然后迭代数组中的数据:
for (size_t i = 0; i < sizeof buttons / sizeof *buttons; ++i)
{
if (HAL_GPIO_ReadPin(buttons[i].port, buttons[i].pin))
{
...
}
}
答案 1 :(得分:3)
preprocessor在编译时工作,很早就参与进来(请阅读translation phases)。因此,您无法使用for
循环生成宏。阅读documentation of cpp
以及之后的C标准(例如n1570)。
您可以使用不同的程序生成C代码 - 可以是其他预处理器,如GPP或m4,或某些脚本(或您自己的其他程序),以及自上个世纪以来,生成C文件是一种常见做法(例如,查看yacc或rpcgen,但您会发现许多其他文件)。然后,您需要配置build automation工具(可能是make
或ninja
)以适当地调用此类C代码生成器。
您可以获取预处理表单,例如如果使用GCC,则使用gcc -C -E
。因此,您可以了解编译器(预处理后的翻译阶段)正在获取的内容。
通过使用可变参数宏,我能得到我想要的吗?
不,你不能。阅读documentation of variadic macros。
答案 2 :(得分:1)
Variadic宏在这里没有解决任何问题。您有两个选项,查找表或X宏。查找表是首选,因为它们最具可读性。但是如果你需要最小化代码重复,X宏可能很有用,虽然它们有点难以阅读。
查找表版本:
typedef struct // I'm not sure about the exact types used here
{
volatile uint8_t* port;
uint8_t pin;
} button_t;
const button_t BUTTON[20] =
{
{&GPIOB, 8},
{&GPIOB, 9},
...
};
for(uint8_t i = 0; i<20; i++)
{
HAL_GPIO_ReadPin(BUTTON[i].port, BUTTON[i].pin);
}
X宏版本:
#define BUTTON_LIST \
/*button port pin */ \
X(1, B, 8) \
X(2, B, 9) \
X(3, B, 4) \
X(4, B, 5) \
X(5, C, 13)
...
for(uint8_t button = 0; button<20; button++)
{
#define X(button, port, pin) HAL_GPIO_ReadPin(GPIO##port, GPIO_PIN_##pin);
BUTTON_LIST
#undef X
}