【问题标题】:C macro for defining symbols用于定义符号的 C 宏
【发布时间】:2012-02-05 01:40:40
【问题描述】:

我正在使用带有 ANSI C(gcc;不是 C++)的微控制器,并且有很多硬件引脚要定义。我正在寻找一种使引脚定义更具可读性的方法。

我想我想要一个可以让我在一行中定义每个引脚的宏,如下所示:

PIN(LED_RED, E, 2);  
PIN(LED_YELLOW, B, 3);  
PIN(LED_GREEN, A, 4);  

(这只是一个简单的例子——我有几十个引脚要定义)。 现在我有这样丑陋的代码:

#define LED_RED           (LATEbits.LATE2)  
#define LED_RED_TRIS      (TRISEbits.TRISE2)  

#define LED_YELLOW        (LATBbits.LATB3)   
#define LED_YELLOW_TRIS   (TRISBbits.TRISB3)    

#define LED_GREEN         (LATAbits.LATA4)    
#define LED_GREEN_TRIS    (TRISAbits.TRISA4)   

每个图钉有 2 个符号;一个用于读/写引脚,另一个用于设置 I/O 方向(_TRIS 定义)。锁存器和 TRIS 定义来自 MCU 供应商提供的头库;避免使用它们并不实际。

我很确定可以用 C 语言编写一个定义这两个符号的宏,但我不太擅长使用 # 和 ## 的东西。这是我半生不熟的尝试(不起作用):

#define _PIN( id,port,pos) #define ##id (LAT ##port ##bits.LAT ##port ##pos )  
#define _TRIS(id,port,pos) #define ##id _TRIS (TRIS ##port ##bits .TRIS ##port ##pos )  
#define PIN(  id,port,pos) _PIN(id,port,pos)  _TRIS(id,port,pos)

有没有办法做到这一点?

或者,还有其他方法可以简化我的引脚定义吗?我想把它归结为一根线/针,并摆脱我拥有的端口 ID(A、B、C 等)和位数(2、3、4 等)的重复现在;将它们放入两次只是自找麻烦。

干杯,

--戴夫

【问题讨论】:

  • 你能澄清一下你的宏的所有参数会做什么吗?现在我不明白预期的行为应该是什么。
  • 一个宏不能定义其他宏。但也许您的问题可以在不同的层面上得到简化?
  • 当然。第一个参数(例如:“LED_RED”)用于定义两个符号;一个称为“LED_RED”,另一个称为“LED_RED_TRIS”(通过附加“_TRIS”)。第二个和第三个参数被替换到宏替换字符串中以形成“LATEbits.LATE2”(其中 E 和 2 来自参数)。
  • 丑陋的代码?它很漂亮,它遵循所有标准,发表一两条评论,这将是完美的。如果你必须像这样制作 5000 亿行,只需编写一个小程序将 em 打印到 .h 文件中即可:)

标签: c macros


【解决方案1】:

你不能在宏中定义宏,但是你可以做一些其他的技巧。

这是在“相当丑陋的宏”领域。

#define MY_CAT(x, y) x ## y
#define MY_CAT2(x, y) MY_CAT(x, y)
#define LED(x) (MY_CAT2(MY_CAT2(LAT, PORT_ ## x), bits) \
                .MY_CAT2(LAT, MY_CAT2(PORT_ ## x, POS_ ## x)))

#define PORT_RED E
#define POS_RED 2
#define PORT_YELLOW B
#define POS_YELLOW 3
#define PORT_GREEN A
#define POS_GREEN 4

LED(RED)
LED(YELLOW)
LED(GREEN)

扩展(检查gcc -E)是:

(LATEbits .LATE2)
(LATBbits .LATB3)
(LATAbits .LATA4)

仅仅因为宏是你的锤子并不意味着这是一个钉子。尝试使用 Python 或其他工具生成源代码,效果会更好。

LEDS = [
    ('RED', 'E2'),
    ('YELLOW', 'B3'),
    ('GREEN', 'A4'),
]
for name, pos in LEDS:
    print '#define LED_%s (LAT%sbits.LAT%s)' % (name, pos[0], pos)
    print '#define LED_%s_TRIS (TRIS%sbits.TRIS%s)' % (name, pos[0], pos)

输出是:

#define LED_RED (LATEbits.LATE2)
#define LED_RED_TRIS (TRISEbits.TRISE2)
#define LED_YELLOW (LATBbits.LATB3)
#define LED_YELLOW_TRIS (TRISBbits.TRISB3)
#define LED_GREEN (LATAbits.LATA4)
#define LED_GREEN_TRIS (TRISAbits.TRISA4)

然后您只需继续检查脚本及其输出到您的修订控制系统。

附录:我不打算解释宏技巧是如何工作的,因为我不想学得足够好来解释它。

【讨论】:

  • 感谢您的回复。不幸的是,该解决方案只是将复杂性从“LED(RED)”系列转移到#defines。 (并且大多数引脚不是 LED - 它们是开关、输入和输出等。)如果有的话,我认为这个结果比我开始时的可读性差。但是如何使用## 的例子很有价值——谢谢。我想我会为此研究一个外部预处理器。
猜你喜欢
  • 2018-11-11
  • 1970-01-01
  • 2012-03-13
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多