原创 宏的妙用(1)

2010-11-22 12:06 2444 7 4 分类: MCU/ 嵌入式

 在V-USB中(也就是以前的AVRUSB)中,我们可以看到有新的一些宏使用方法,非常独特。例如在文件hardware.h中,定义端口的方式是:

#define HWPIN_ISP_RESET     B, 0
#define HWPIN_ISP_MOSI      B, 3
#define HWPIN_ISP_MISO      B, 4
#define HWPIN_ISP_SCK       B, 5

这样做有什么好处呢?在前面的一篇Blog中,我们可以看到每种MCU的IO都是由几个寄存器进行控制的。在程序移植时,如果修改一个端口,就需要同时将对应的几个寄存器都进行修改,这样就比较麻烦,特别在需要修改的IO比较多,或者程序直接引用的地方比较多的时候,比较容易出错。使用宏就可以比较好的解决这个问题。在V-USB的文件utils.h中,我们可以看到下面的宏定义:




#define UTIL_CONCAT(a, b)           a ## b
#define UTIL_CONCAT_EXPANDED(a, b)  UTIL_CONCAT(a, b)

#define UTIL_INTERRUPT(signame)                         \
    void signame (void) __attribute__ ((interrupt));    \
    void signame (void)


/* PORT bit macros */

#define UTIL_ARG1(a, b) a
#define UTIL_ARG2(a, b) b

#define UTIL_PBIT_SET(varbase, pinspec)  UTIL_CONCAT_EXPANDED(varbase, UTIL_ARG1(pinspec)) |= (1 << (UTIL_ARG2(pinspec)))
#define UTIL_PBIT_CLR(varbase, pinspec)  UTIL_CONCAT_EXPANDED(varbase, UTIL_ARG1(pinspec)) &= ~(1 << (UTIL_ARG2(pinspec)))

#define PORT_OUT(pinspec)       UTIL_CONCAT_EXPANDED(PORT, UTIL_ARG1(pinspec))
#define PORT_IN(pinspec)        UTIL_CONCAT_EXPANDED(PIN, UTIL_ARG1(pinspec))
#define PORT_DDR(pinspec)       UTIL_CONCAT_EXPANDED(DDR, UTIL_ARG1(pinspec))
#define PORT_BIT(pinspec)       UTIL_ARG2(pinspec)

#define PORT_PIN_SET(pinspec)   UTIL_CONCAT_EXPANDED(PORT, UTIL_ARG1(pinspec)) |= (1 << (UTIL_ARG2(pinspec)))
#define PORT_PIN_CLR(pinspec)   UTIL_CONCAT_EXPANDED(PORT, UTIL_ARG1(pinspec)) &= ~(1 << (UTIL_ARG2(pinspec)))
#define PORT_PIN_VALUE(pinspec) (UTIL_CONCAT_EXPANDED(PIN, UTIL_ARG1(pinspec)) & (1 << (UTIL_ARG2(pinspec))))

#define PORT_DDR_SET(pinspec)   UTIL_CONCAT_EXPANDED(DDR, UTIL_ARG1(pinspec)) |= (1 << (UTIL_ARG2(pinspec)))
#define PORT_DDR_CLR(pinspec)   UTIL_CONCAT_EXPANDED(DDR, UTIL_ARG1(pinspec)) &= ~(1 << (UTIL_ARG2(pinspec)))
#define PORT_DDR_VALUE(pinspec) (UTIL_CONCAT_EXPANDED(DDR, UTIL_ARG1(pinspec)) & (1 << (UTIL_ARG2(pinspec))))





调用时方式如下:

    PORT_DDR_SET(HWPIN_ISP_SCK);    /* enable programming I/O pins */
    PORT_DDR_SET(HWPIN_ISP_MOSI);

    PORT_DDR_SET(HWPIN_ISP_RESET);
    timerTicksDelay(ispClockDelay); /* stabDelay may have been 0 */
    PORT_PIN_SET(HWPIN_ISP_RESET);  /* give positive RESET pulse */


如果把宏替换,上面的语句就是

    DDRB |= (1 << 5);
    DDRB |= (1 << 3);
    DDRB |= (1 << 0);
    PORTB |= (1 << 0);


其实和以前的写法没有什么区别。但是
这样的好处也很明显,在移植程序时,只需要修改IO的定义,不需要手工修改相关寄存器了,减少了移植时的难度,降低了代码维护量。缺点是代码看起来有些复杂,类似伪代码。



在其他MCU中,我们也可以使用类似的方法。下面是我将这种方法移植到MSP430的代码,基于IAR5.10开发环境。


#define LEDRED      P1, 0
#define LEDGREEN    P1, 6


#define PIN_INPUT             0
#define PIN_OUTPUT            1

#define MC_ARG1(a, b)         a
#define MC_ARG2(a, b)         b
#define MC_CON_CAT(a, b)      a##b
#define MC_CONCAT(a, b)       MC_CON_CAT(a, b)

#define MSP_PINDIR(PIN)       MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), DIR_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), DIR_), MC_ARG2(PIN)))
#define MSP_PININ(PIN)        MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IN_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IN_), MC_ARG2(PIN)))
#define MSP_PINOUT(PIN)       MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), OUT_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), OUT_), MC_ARG2(PIN)))
#define MSP_PINREN(PIN)       MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), REN_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), REN_), MC_ARG2(PIN)))
#define MSP_PINSEL(PIN)       MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), SEL_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), SEL_), MC_ARG2(PIN)))

#define MSP_PINIE(PIN)        MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IE_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IE_), MC_ARG2(PIN)))
#define MSP_PINIES(PIN)       MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IES_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IES_), MC_ARG2(PIN)))
#define MSP_PINIFG(PIN)       MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IFG_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IFG_), MC_ARG2(PIN)))
#define MSP_PINIFGSET(PIN)    MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IFG_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IFG_), MC_ARG2(PIN))) = 1
#define MSP_PINIFGCLR(PIN)    MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IFG_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), IFG_), MC_ARG2(PIN))) = 0

#define LEDON(PIN)   MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), OUT_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), OUT_), MC_ARG2(PIN))) = 1
#define LEDOFF(PIN)  MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), OUT_bit.), MC_CONCAT(MC_CONCAT(MC_ARG1(PIN), OUT_), MC_ARG2(PIN))) = 0

 


  MSP_PINDIR(LEDRED) = 1;
  MSP_PINDIR(LEDGREEN) = 1;
 
  LEDON(LEDRED);
  LEDOFF(LEDGREEN);


附件中是完整的例子,基于TI的LaunchPad开发板和MPS430G2231:



 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /3 下一条