STM32中寄存器编程

一、存储器映射:给存储器分配地址。

存储器重映射:给存储器再分配一个地址

存储器的地址空间有4G,被平均分为8块。

 

 

block0设计成FLASH

block1设计成内部SRAM

block2设计成片上外设(根据外设的总线速度不同,block被分成了APB和AHB,APB被分为APB1和APB2)

二、寄存器映射

在block2中,设计成片上外设,四个字节为一个单元,共32bit(4*8),每个单元对应不同功能,通过控制这些单元来控制外设工作。找到每个单元的起始地址然后利用c语言的指针操作来进行访问。如果利用地址来进行操作的话,很麻烦。

因此我们根据每个单元功能的不同以此对内存单元取别名方便操作。这个别名就叫寄存器。

利用绝对地址对内存单元进行访问:
// GPIOB 端口全部输出 高电平
*(unsigned int*)(0x4001 0C0C) = 0xFFFF; 

 此处0x4001 0C0C就是GPIOB端口ODR的地址,类似变量名。

先转换成指针,c语言就知道是这是个地址,就可以通过*操作来对这个地址存储的值进行间接访问。

 上述方法过于麻烦,可以把强制类型转换和*操作放在宏定义里,然后直接打英文字符就行了。

// GPIOB 端口全部输出 高电平
#define GPIOB_ODR
*(unsigned int*)(GPIOB_BASE+0x0C)
GPIOB_ODR = 0xFF;

 三、STM32外设地址映射

APB1挂载低速外设,APB2,AHB挂载高速外设

相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外设的地址。APB1总线的地址最低,片上外设从此开始。

总线基地址+相对外设基地址的偏移(该总线地址与片上外设基地址的差值)。

总线上挂载这各种外设也有自己的地址范围,特定外设的首个地址称为XX外设基地址=XX外设的边界地址。

XX外设的地址范围内分布着的就是该外设的寄存器。

例如GPIO 有很多寄存器,每一个都有相应的特定功能。每个寄存器32bit,占4个字节。

寄存器位置=外设基地址+相对该外设基地址的偏移。

四、一个一个定义太麻烦

因此采取对寄存器封装的方式,全部用宏定义起来,总线和外设以他们的名字作为宏名

*(unsigned int *)GPIOB_BSRR = (0x01<<(16+0));

我们对于总线基地址,外设基地址,寄存器基地址进行宏定义。通过查阅手册来进行宏定义。

此时这些地址是一些无符号整型的值。

c语言中,对于一些普通的变量来讲,程序被编译和链接之后,变量名被替换成相应的地址,然后获取数据。

C语言中,允许用一个变量来存放指针,这种变量称为指针变量。指针变量的值就是某份数据的地址,这样的一份数据可以是数组、字符串、函数,也可以是另外的一个普通变量或指针变量。

而指针不同:

假设变量 a、p 的地址分别为 0X1000、0XF0A0,它们的指向关系如下图所示:

 

程序被编译和链接后,a、p 被替换成相应的地址。使用 *p 的话,要先通过地址 0XF0A0 取得变量 p 本身的值,这个值是变量 a 的地址,然后再通过这个值取得变量 a 的数据,前后共有两次运算;而使用 a 的话,可以通过地址 0X1000 直接取得它的数据,只需要一步运算。

我们要用 C 语言控制读写外设寄存器

这里采用了指针的方式

(unsigned int *)GPIOB_BSRR的意思是强制类型转换,将原先定义的一个无符号整型变量变成一个指针变量,这个指针变量指向的数据类型是无符号整型,然后这个指针变量存放的是一个地址,这个地址是(0x01<<(16+0)).

前面又加了一个*号,这个意思赋予GPIOB_BSRR的值,也就是把这个地址赋予给这个指针。

 

posted on 2021-04-10 11:54  -yuanyuan-  阅读(1251)  评论(0编辑  收藏  举报