目录
1.什么是存储器映射
存储器本身是没有地址之分的,就像一间间小仓库,由芯片厂家或者用户给它分配地址,如几号几号仓库之类的。给仓库分配地址的过程就叫存储器映射,如果再分配一个地址就叫重映射。
以STM32F103ZET6芯片数据手册里的存储器映射图为例子,如下图:
由图中可看出STM32F103ZET6共有4GB的储存器空间,平均分成了8块区域(可以理解为分成8个仓库),每个仓库的储存器空间为512MB。8个区域中,每一块区域都有它特殊的用途。
如block0主要用于设计芯片内的Flash(闪存),Flash掉电不遗失数据,所以经常作为单片机的程序储存器,我们编写的程序就存储在这里面;block1主要用于设计芯片内部的SRAM;block2用于设计片内外设(可以看到有ADC和IIC等)。
2.什么是寄存器映射
寄存器是有特定功能的内存单元,通常我们会给这个特殊的内存单元取一个名字,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
以block2为例子,刚刚说到block2这个小仓库是用来设计片上外设的,由于STM32的芯片内核是32位的,一次可以处理32位数据,所以我们以4个bit为一个单元,每个单元都有其功能,当我们控制这些单元的时候也就是在控制这些外设,由于stm32的内部存储空间大,外设繁多,每次操控一个外设时就要写一大串对应的储存单元地址。
举个例子,我们要操作0x4001 0C10这个单元地址,我们就要写是在block2区域的TIM2区域里的单元地址,十分繁琐。所以我们可以给它取个别名GPIOB_BSRR,这个GPIO_BSRR就是寄存器,这个寄存器的地址就是0x4001 0C10,这个给它取名的过程就叫寄存器映射。
例子:让GPIOB端口的16个引脚输出高电平
①首先要通过绝对地址访问内存单元,让GPIOB端口输出高电平,所以用到端口输出寄存器(8.2.4节),起始地址:中文参考手册的2.3存储器映像;偏移地址:中文参考手册的8.2 GPIO寄存器描述(8.2.4节)。
起始地址+偏移地址=绝对地址
0X4001 0C00+0C=0X4001 0C0C
②对物理地址进行强制类型转换,(unsigned int*)(0x4001 0C0C) 转换为指针
③对指针进行操作:*(unsigned int*)(0x4001 0C0C) 都赋值为高电平
// GPIOB 端口全部输出 高电平
*(unsigned int*)(0x4001 0C0C) = 0xFFFF;
或者,我们直接用“#define”宏定义,对绝对地址进行命名,这样操作更方便。
// GPIOB 端口全部输出 高电平
#define GPIOB_ODR *(unsignedint*)(0x4001 0C0C)
GPIOB_ODR = 0xFF;
3.C语言对寄存器的封装
就像在51里面加入的头文件“#include <reg52.h>”,在STM32中,需要我们自己写。最重要的就是找出寄存器的地址。
下面以GPIOB端口的寄存器为例介绍
(1)首先确定总线基地址(下表中的第二列)。
计算方法:总线最一开始的地址是0X4000 0000,看总线相对于最一开始地址偏移多少(下表第三列),之后二者相加:0X4000 0000+第三列的偏移=总线基地址(下表第二列) GPIOB属于APB2,基线地址为0X4001 0000
下图为中文参考手册的2.3存储器映像(起始地址查询处)
(2)确定外设基地址
外设基地址=总线基地址+该外设相对于所在总线地址的地址偏移。外设基地址在下图中可以直接读出:GPIOB的就是0X4001 0C00
下图为存储器映像的外设部分截图:
由此可得出GOIO外设的基地址:
(3)确定寄存器地址
寄存器地址=外设基地址+寄存器相对于外设基地址的偏移。这个在中文参考手册各自具体章节的介绍中有涉及。
这样经过层层叠加,寄存器地址得以确定。更改寄存器电平高低的时候,就更改一下地址的数据类型,用指针表示即可。
GPIOB的寄存器地址如下:
引用文章链接:http://t.csdn.cn/mBZA7