本帖最后由 warship 于 2018-7-16 19:56 编辑
在原子例程的sys.h中,使用宏定义建立了位带操作的基础,
使得操作IO端口可以像51一样实现位操作。
其实深入了解了位带操作的原理,几乎就可以实现对STM32所有外设寄存器的访问,
极端情况下,什么库函数版本,什么寄存器版本都可以不用,直接精准地操控所有寄存器的每一位的读写!!!
知道了STM32将所有外设寄存器的每一位都建立了位带别名区,
你只要再花一点点时间,彻底搞明白下面的三句宏定义,位带操作就都不在话下了:
#define
BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define
MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define
BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
************************************************************************************************
注:本文后文所探索的寄存器位段操作宏定义包含在另文所附范例(外部中断试验的工程包)中,并随时更新。
有需要研究探讨的网友,可移步下载http://www.openedv.com/forum.php ... d=274724&extra=
怎么是这样的呢?因为有前面这些宏定义为基础,
反正闲着没事儿,我就当一回编译器,把这句PAout(9)=1一步步地编译出来,宏的展开就是一个替换的过程:
PAout(9)=1;因为定义了PAout(n) 要替换成 BIT_ADDR(GPIOA_ODR_Addr,n),所以展开成:
BIT_ADDR(GPIOA_ODR_Addr,9)=1;因为定义了BIT_ADDR(addr, bitnum) 要替换成 MEM_ADDR(BITBAND(addr, bitnum)),所以展开成:
MEM_ADDR(BITBAND(GPIOA_ODR_Addr, 9))=1;因为定义了BIT_ADDR(addr, bitnum) 要替换成 MEM_ADDR(BITBAND(addr, bitnum)),所以展开成:
MEM_ADDR((GPIOA_ODR_Addr & 0xF0000000)+0x2000000+((GPIOA_ODR_Addr &0xFFFFF)<<5)+(9<<2))=1;
最后一步,因为定义了MEM_ADDR(addr)要替换成 *((volatile unsigned long *)(addr))
所以展开成为如下的语句,不要晕倒哦,*((volatile unsigned long *)((GPIOA_ODR_Addr & 0xF0000000)+0x2000000+((GPIOA_ODR_Addr &0xFFFFF)<<5)+(9<<2)))=1;
神奇吧?
一句 PAout(9)=1;
与 *((volatile unsigned long *)((GPIOA_ODR_Addr & 0xF0000000)+0x2000000+((GPIOA_ODR_Addr &0xFFFFF)<<5)+(9<<2)))=1;
是完全等效的。
而这,就是宏定义的效能和魅力!
一周热门 更多>