-3

What I want to do is access code with macros. But the complier gives me this error

identifier "BUTTON___button" is undefined

#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

By using variadic macros, can I get what I want?

Lundin
  • 195,001
  • 40
  • 254
  • 396

3 Answers3

5

You must remember that preprocessor things happen before the code is compiled, and is strictly text-only replacement.

Thus, depending on a variable that has different values because of a run-time loop makes no sense, and doesn't work.

The proper way to do this is to put the port addresses (GPIOA etc) in an array, together with the corresponding pin for each port:

static const struct {
  const GPIO_TypeDef *port;
  uint32_t            pin;
} buttons[] = {
  { GPIOB, GPIO_PIN_8 },
  { GPIOB, GPIO_PIN_9 },
  ...
};

then iterate over the data in the array:

for (size_t i = 0; i < sizeof buttons / sizeof *buttons; ++i)
{
  if (HAL_GPIO_ReadPin(buttons[i].port, buttons[i].pin))
  {
     ...
  }
}
unwind
  • 391,730
  • 64
  • 469
  • 606
2

The preprocessor works at compile-time, and is involved very early (read about translation phases). So you can't generate macros with a for loop. Read documentation of cpp and later your C standard (e.g. n1570).

You could generate your C code with a different program -maybe some other preprocessor like GPP or m4, or some script (or your own other program), and generating C files is a common practice since the previous century (for examples, look into yacc or rpcgen, but you'll find many others). You then want to configure your build automation tool (perhaps make or ninja) to invoke such a C code generator appropriately.

You can obtain the preprocessed form, e.g. with gcc -C -E if using GCC. So you can understand what the compiler (its translation phases after preprocessing) is getting.

By using variadic macros, can I get what I want?

No you can't. Read documentation of variadic macros.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

Variadic macros won't solve anything here. You have two options, look-up tables or X macros. Look-up tables are preferable since they are most readable. But in case you need to minimize code repetition, X macros can be useful, although they are a bit hard to read.

Look-up table version:

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 macro version:

#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
}
Lundin
  • 195,001
  • 40
  • 254
  • 396