1、字节地址和位地址
1字节(byte) = 4比特(bit), 1字 = 4字节
内存单元为1字节,一个地址所指向的内存为8位
字节地址:每个内存单元的编号
位地址:一个内存单元里每一位的编号
2、51单片机的字节地址和位地址
8位的51单片机有0~255共256个地址,可分为:
1、片内数据存储器(RAM)共128个单元,字节地址00H~7FH。
2、特殊功能寄存器映射在片内RAM 80H~FFH 区域中,共26个。
其中,共211个可寻址位,构成了位地址空间。它们位于内部 RAM(共128位)和特殊功能寄存器区(共83位)中
(1)在数据存储区,20H~2FH中的每一位可位寻址
疑问:为什么字节地址00H~7FH 和 位地址00H~7FH不会冲突?
答:使用位寻址区时,需定义变量的存储类型为bdata即可指向位寻址区
unsigned char bdata status_byte; //定义位寻址区的变量status_byte
可获取status_byte的每一位
sbit stat_flag=status_byte^4; //将status_byte第4位传给stat_flag
(2)特殊功能寄存器区的位操作是对寄存器的具体某一位操作
例如:对P0端口的某一位操作
P0端口字节地址 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0x80 | 0x87 | 0x86 | 0x85 | 0x84 | 0x83 | 0x82 | 0x81 | 0x80 |
P0 = 0x80; P0端口的字节地址
P0^0 = 0x80 P0端口的第1位(0x80按位异或0)
P0^1 = 0x81 P0端口的第0位(0x80按位异或1)
......
C51中对位操作两种形式
1、自己定义:sbit LED0 = P0^1;
2、使用已有的定义:P0_1 (sbit P0_1 = 0x81;)
3、STM32寄存器
STM32的寄存器为32位(4字节),即每个寄存器占用4个地址
STM32中无法直接操作具体的某一位,只能对寄存器整体写入值。因此需使用位带操作实现对内存单元的位进行操作。
4、位带操作
在位带区中,每个比特都映射到别名地址区的一个字——这是个只有 LSB 才有效的字。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到 LSB,并把 LSB 返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读-改-写”过程。
支持位带操作的两个内存区的范围是:
0x2000_0000-0x200F_FFFF(SRAM 区中的最低 1MB)
0x4000_0000-0x400F_FFFF(片上外设区中的最低 1MB)
简单讲就是对指定寄存器的某一位的操作转化为对指定内存单元的操作
存储器的片上外设和SRAM各含有1MB的位带区和位带别名区
片上外设的1MB位带区,包含STM32各种外设的寄存器。
5、位带操作地址映射
位带区1MB | 位带别名区32M |
位带区1bit | 位带别名区32bit |
因此需要求位带区一个地址对应内存的某一位映射到位带别名区所对应的地址
对于片上外设位带区的某个比特,记它所在字节的地址为 A,位序号为 n(0<=n<=7),则该比特在别名区的地址为:
AliasAddr=0x42000000+((A-0x40000000)*8+n)*4=0x42000000+ (A-0x40000000)*32 + n*4
思路:位带别名区地址=位带别名区基地址+(位带区偏移bit数*32/8)
AliasAddr=0x42000000+((A-0x40000000)*8+n)*32 /8
- (A-0x40000000)*8:在位带区相对基地址偏移了多少bit
- n:在内存单元中的偏移量(bit)
- ((A-0x40000000)*8+n):在位带区总的偏移的bit数
- *32:1bit映射为32bit,位带区总的偏移的bit数*32 = 位带别名区偏移的bit数
- /8 :得该比特在位带别名区偏移的内存单元数,也就是位带别名区地址的偏移量