『7x24小时有问必答』

代码逐行详解

cCopy Code

#define  SETV(GP,PINNUM,Val) \

      do{ \

            GPIO##GP->BSRR = (!(Val) << (16+PINNUM)) | ((Val) << PINNUM); \

      } while(0)

GPIO##GP:通过令牌拼接生成如GPIOAGPIOB等实际寄存器名
!(Val) << (16+PINNUM):若Val=0,则在复位段(高16位)置1
(Val) << PINNUM:若Val=1,则在置位段(低16位)置1
|运算:同时处理置位和复位,硬件自动忽略冲突位
cCopy Code

#define  SPI_CS(x) \

      do{ \

            SETV(C, 9, (x)&0x01); \

      } while(0)

固定GPIOC9:典型SPI硬件连接方案(如STM32的SPI1_NSS)
(x)&0x01:强制参数合法化,等效于x ? 1 : 0

---

效率分析(最优级)

单指令周期操作
直接操作BSRR寄存器,STM32的GPIO置位/复位只需1个时钟周期
对比传统GPIOx->ODR操作(需读-改-写,3周期以上)
原子性保证
BSRR
的置位和复位位是独立硬件电路,无竞争条件
GPIOx->ODR = value(需关中断保护)更高效安全
编译器优化
do{...}while(0)
会被优化为纯内联代码,无函数调用开销
(x)&0x01
和位操作会被编译为单条AND指令
零内存占用
宏展开后仅为寄存器操作指令,无栈帧消耗

对比传统实现

方法
周期数
原子性
代码体积
本宏(BSRR)
1
极小
ODR直接赋值
≥3
库函数(HAL_GPIO)
≥10

---

典型应用场景

SPI片选控制
cCopy Code

SPI_CS(0);  // 拉低片选

SPI_Send(data);

SPI_CS(1);  // 释放片选

需纳秒级响应(如W25Q128 Flash)
精密时序控制
用于WS2812B等LED驱动,需50ns级精度
中断安全操作
在中断和主循环共享GPIO时无需额外锁

---

注意事项

硬件依赖性
仅适用于STM32等有BSRR寄存器的ARM芯片
调试限制
宏展开后难以单步调试,建议配合逻辑分析仪验证
可读性妥协
对新手不友好,但性能敏感场景必用
这种实现是寄存器级编程的典范,在RTOS、高频SPI、硬件协议栈等场景中广泛使用。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码