论坛元老
 
- 积分
- 4462
- 金钱
- 4462
- 注册时间
- 2018-5-11
- 在线时间
- 932 小时
|

楼主 |
发表于 2019-5-31 16:39:18
|
显示全部楼层
本帖最后由 warship 于 2019-6-3 12:30 编辑
简化宏定义、便于代码移植
为减少宏定义的工作量,对于多个同类的外设,尤其是两个以上,如定时器、通信串口等,避免大量类似的宏定义
使用带参数的宏,形如bCR_CEN(bTIM1),其中bTIM1为基址宏
以b开头的基址宏定义(如bTIM1)的值,其原始本质就是一个u32的数值,所以
当有需要,想将它也作为一个可变参数时,可以定义形参的类型为u32
比如:想写一个设置任意SPI接口速率的函数
可编写如下函数:
void SET_SPIx_SPEED(u32 MySPIx_Base, u8 SPI_SPEED)
{
SET_SPI_CR_BR(MySPIx_Base,SPI_SPEED);//设置SPI速率
}
调用时,入口参数MySPIx_Base分别使用bSPI1、bSPI2或bSPI3就可作用于不同的SPI口
另外,在编程需要时,可用
((SPI_TypeDef *)MySPIx_Base)->DR; 取代SPIx->DR;
((SPI_TypeDef *)bSPI1)->DR; 取代SPI1->DR;
在进一步地增加了宏定义 #define pSPI(bSPIx) ((SPI_TypeDef *)bSPIx)
之后,使得上两句可简写为:pSPI(bSPI1)->DR; //前缀“p”表示这是一个指向结构体的指针。
接近了寄存器编程的风格,也就是说,对于寄存器整体的访问,
除了仍可沿用原有的SPI1->DR外,也可以使用带参的宏定义方式:pSPI(bSPI1)->DR
使用者可以视情任意选择其一,但使用后者的好处是使得bSPIx成了与单BIT、多BIT访问时统一的参数,便于移植
比如:下列函数即向串口发送一个字符,如果移植时,只须替换bURT1为bURT2就可以从串口1改成串口2
void USART_SendData(u8 ch)
{
pURT(bURT1)->DR = ch ;
while ( bURT_SR_TXE(bURT1) ==0 );
}
对比一下,如果第一句仍沿用传统的寄存器访问风格,则移植的时候就需要修改两种符号:
void USART_SendData(u8 ch)
{
USART1->DR = ch ;
while ( bURT_SR_TXE(bURT1) ==0 );
}
后者比前者需要增加的工作量:还须将USART1改成USART2
而且,前者还可以很容易地写成向任意串口发送字符的通用函数:
void USART_SendData(u32 bURTx, u8 ch)
{
pURT(bURTx)->DR = ch ;
while ( bURT_SR_TXE(bURTx) ==0 );
}
|
|