在编程的过程中,使用带参数的宏有时会使得程序看起来更加直观、操作也更加方便。
如果我要点亮一个LED灯,我可以这样写
LED2_ON;
这样就可以点亮LED2,当然,LED2_ON是一个宏定义,那么它是一个怎样的宏呢?
#define LED2_ON digitalLo(GPIOF,GPIO_Pin_7)
如上,它由 digitalLo(GPIOF,GPIO_Pin_7) 来替换,而 digitalLo() 为一个带有参数的宏,我们来看它的定义
#define digitalLo(p,i) {p->BRR = i;} // 输出低电平
因为预处理器不进行计算,而只进行字符串替换,所以我们调用LED2_ON的结果为
GPIOF->BRR = GPIO_Pin_7;
我们来看下GPIOF定义
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
而GPIOF_BASE定义为
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
而APB2PERIPH_BASE定义为
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
而PERIPH_BASE定义为
#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
所以 APB2PERIPH_BASE = (PERIPH_BASE + 0x10000) = 0x40000000 + 0x10000 = 0x4001 0000
所以 GPIOF_BASE = (APB2PERIPH_BASE + 0x1C00) = 0x4001 0000 + 0x1C00 = 0x4001 1C00
所以 GPIOF = ((GPIO_TypeDef *)GPIOF_BASE) = (GPIO_TypeDef *)0x4001 1C00
如上图,由《STM32 Reference Manual》可知,0x4001 1C00为GPIO端口F的起始地址,所以GPIOF为一个结构体指针,并指向GPIO端口F的首地址,而GPIO_TypeDef 结构体的定义在上一篇文章中已经介绍过了,这里不再赘述。
现在我们回到 GPIOF->BRR = GPIO_Pin_7; 这一条代码,再来看下GPIO_Pin_7的定义
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
即 GPIOF->BRR = 0x0080
如上图,再参考手册可知,代码执行结果为配置GPIOF的引脚 7 为 0,而硬件原理图里面我们的LED2一端接VCC,一端接PF7脚,把GPIOF引脚7拉低,即使得LED2点亮。
使用带参宏点亮LED2(也可以是其他操作)使得代码很直观,易于操作,当然宏的参数要参照硬件原理图来设定。
原创作品