本帖最后由 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=
还有:因为定义了GPIOA_ODR_Addr就是(0x4001 0800+0C),哦,等一下,我先算出数值来吧,GPIOA_ODR_Addr就是0x4001 080C,得到:
*((volatile unsigned long *)((0x4001 080C & 0xF0000000)+0x2000000+((0x4001 080C &0xFFFFF)<<5)+(9<<2)))=1;
看着很长,其实有了具体数值,算出结果就短了:
解&运算符:得到*((volatile unsigned long *)(0x4000 0000 +0x200 0000+(0x0001 080C<<5)+(9<<2)))=1;
即:*((volatile unsigned long *)(0x4200 0000 +(0x0001 080C<<5)+(9<<2)))=1;
解移位运算符:9=1001 经过<<2得到 100100 即0x24;
1 080C=0001 0000 1000 0000 1100经过<<5得到0010 0001 0000 0001 1000 0000 即0x21 0180
所以语句变成:*((volatile unsigned long *)(0x4200 0000 + 0x21 0180 + 0x24)=1;
最后结果就是如下语句(以上这些过程都只是预编译器干的话,实际交付编译器的也就是下面这一句):
*((volatile unsigned long *)(0x4221 01A4)=1;
说成大白话,就是给0x4221 01A4这个地址中所存储的变量赋值为1.
(注意:这个变量是一个long型的,32位,占用从0x4221 01A4开始的连续4个存储单元)
但是ARM的设计师们并没有在物理上设计这些存储单元(也永远不允许这些存储单元实际存在!!!),取而代之的是设计了位映射机制:
凡是访问别名区域地址的操作,都被转换为访问其所映射对应的比特位,
*(0x4221 01A4)=1的执行结果就是:GPIOA的ODR寄存器第9位=1
一周热门 更多>