我想让我的头文件很容易改变与宏。我正在调试我的代码,似乎这些宏没有做他们应该做的事情。有人能告诉我怎样才能达到以下效果吗?LED_ID_AMS等。
#define LED_NUMBER (2)
#define LED_ID_X (0)
#define LED_ID_Y (1)
#define LED_PIN_X (0)
#define LED_PIN_Y (3)
#define LED_PORT_X (PORTE)
#define LED_PORT_Y (PORTG)
#define LED_DD_X (DDRE)
#define LED_DD_Y (DDRG)
#define LED_PORT(LED_ID_X) (LED_PORT_X)
#define LED_PORT(LED_ID_Y) (LED_PORT_Y)
#define LED_PIN(LED_ID_X) (LED_PIN_X)
#define LED_PIN(LED_ID_Y) (LED_PIN_Y)
#define LED_DD(LED_ID_X) (LED_DD_X)
#define LED_DD(LED_ID_Y) (LED_DD_Y)
我想要实现什么?
我试着这样做,这样我就可以像这样循环通过端口init:
for(i=0;i<LED_NUMBER;i++){
/* set data direction to output*/
LED_DD(i)|=((0x01)<<LED_PIN(i));
/* turn on led */
LED_PORT(i)|=((0x01)<<LED_PIN(i));
}
您以后会后悔使用了太多宏。实际上,你已经后悔了,因为它们不能工作,而且作为宏,它们很难调试。
还有几点:
- 您的
LED_PIN(i)
表达式总是扩展到0
- 你的
LED_PORT(i)
表达式总是扩展到PORTE
,无论可能是
例如LED_PIN(LED_ID_X)
展开为LED_PIN_X
。注意,根本没有使用宏参数LED_ID_X
。相反,LED_PIN_X
只是展开为0
。
这应该会向您发出警告,例如LED_PORT(SOME_ARG)
有几个定义。在LED_PORT(LED_ID_X)
中,LED_ID_X
只是一个虚拟参数,与常量LED_ID_X
完全没有关系。
你可以通过使用常量数组使你的代码具有同样的可读性,也许就像你在这里尝试做的那样,从宏中使用。
除非有大量的 LED_ID_<foo>
,否则这充其量只是一个小的简化。不要那样做。如果有很多代码以相同的方式绕过它们,那么定义一个宏来迭代每个操作可能是有意义的,例如:
#define FROB_LEDS \
action(LED_ID_X); \
action(LED_ID_Y); \
action(LED_ID_Z);
并将action(X)
本地定义为宏,以对LED X
, FROB
进行操作,并再次取消定义action
。很丑,真的。
您必须添加至少一个:
- 数组
- 内联函数
- 更复杂的宏
在我看来,还需要对硬件地址进行解引用。
例如,您可以使用宏定义:
#define LED_PORT(i) *(uint16_t *)(
(i) == LED_ID_X ? LED_PORT_X :
(i) == LED_ID_Y ? LED_PORT_Y :
etc)
地点:
#define LED_ID_X (0)
#define LED_ID_Y (1)
#define LED_PORT_X (PORTE)
#define LED_PORT_Y (PORTG)
#define PORTE (0x11112222U) // example only
#define PORTG (0x33334444U) // example only
这里uint16_t
只是一个猜测:我假设16位端口在32位地址空间。
或者,使用数组和C99的指定初始化式:
const uint32_t LED_PORT[] = {
[LED_ID_X] = LED_PORT_X,
[LED_ID_Y] = LED_PORT_Y
};
#define LED_PORT(i) (*(uint16_t *)LED_PORT[i])
当然,如果没有C99,你可以直接使用:
const uint32_t LED_PORT[] = {LED_PORT_X, LED_PORT_Y};
其中假设 LED_ID_X
为0
,等等