本帖最后由 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=
继续研究,对21楼的测试例程进行反汇编如下:
143: MyFlag=2; //赋值为2,即最低四位(下同,共32位这里只关注低四位的变化)为0010
0x0800019A 2002 MOVS r0,#0x02
0x0800019C 49FE LDR r1,[pc,#1016] ; @0x08000598处所存的内容(MyFlag分配的地址值)赋值给R1
0x0800019E 6008 STR r0,[r1,#0x00] ;寻址这一MyFlag地址,将R0的值存入
144: if(Myflg1) Myflg1=0; //如果BIT1为1,则清为0,此时MyFlag变为0000
145:
0x080001A0 48FE LDR r0,[pc,#1016] ; @0x0800059C,标志位Myflg0的地址(2203 0000),指向别名区
0x080001A2 6840 LDR r0,[r0,#0x04] ; 加#4后为标志位Myflg1的地址,指向别名区
0x080001A4 B110 CBZ r0,0x080001AC
0x080001A6 2000 MOVS r0,#0x00
0x080001A8 49FC LDR r1,[pc,#1008] ; @0x0800059C,(此处存地址值2203 0000)
0x080001AA 6048 STR r0,[r1,#0x04]
146: Myflg3=1; //置位BIT3
0x080001AC 2001 MOVS r0,#0x01
0x080001AE 49FB LDR r1,[pc,#1004] ; @0x0800059C(此处存地址值2203 0000)
0x080001B0 60C8 STR r0,[r1,#0x0C] ; 加#12后为标志位Myflg3的地址,指向别名区
......
......
0x08000598 1800 DCW 0x1800 ; 这里存放了我们手工指定的地址值:2000 1800
0x0800059A 2000 DCW 0x2000
0x0800059C 0000 DCW 0x0000 ; 这里存放了计算出来的别名区基址:2203 0000
0x0800059E 2203 DCW 0x2203
一周热门 更多>