我正在尝试使用宏轻松更改我的头文件。我正在调试我的代码,似乎这些MACROS没有做他们应该做的事情。谁能告诉我如何实现以下效果? 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));
}
答案 0 :(得分:1)
您将后悔使用过多的宏。实际上,你已经后悔了,因为它们不起作用,并且作为宏,它们很难调试。
只需几点:
LED_PIN(i)
表达式始终扩展为0
LED_PORT(i)
表达式始终会扩展为PORTE
例如LED_PIN(LED_ID_X)
扩展为LED_PIN_X
。注意,根本不使用宏参数LED_ID_X
。相反,LED_PIN_X
只会扩展为0
。
答案 1 :(得分:0)
您必须至少添加以下内容之一:
在我看来,还需要取消引用硬件地址。
例如,使用宏,您可以定义:
#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
只是猜测:我假设32位地址空间中有16位端口。
或者,使用数组和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
等。
答案 2 :(得分: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
再次执行操作。非常丑陋,真实。