什么是寄存器
主要内容
- 如何辨别STM32芯片的正方向
- STM32芯片架构图
- 什么叫存储器映射
- 什么叫寄存器映射
一:如何辨别STM32芯片的正方向
- 看丝印左边逆时针为第一个引脚
- 在芯片表面有一个小圆点逆时针为第一引脚
二:STM32芯片架构图
(对于这两个图的理解可以参考STM32参考手册 驱动单元由ARM 粉色部分位外设由ST设计,主要学习APB1 APB2 两个总线(两个总线速度不同)中的外设)
三:什么叫存储器映射
存储器本身不具有地址信息,它的地址是由芯片厂商(ST)或用户分配,给存储器分配地址的过程就称为存储器映射。
给存储器分配地址的过程叫存储器映射,再分配一个地址叫重映射。
下图中的block0-7就相当于是存储器。
ARM的Cortex内核位32位,共有2^32=4GB的内存,ARM将4GB的内存分为8块,每块512Mb,分别位block0-7,如图
其中ARM规定block0中,规定ST等这类公司只能将flash(程序)在其中,虽然由很多剩余,但仍要这么放置,为以后着想。其他的block也规定。
下面我给出ARM规定block规定的block0-7放的相应外设图以及相应的地址(结合第二个图):
我们在学习的时候主要学习block中的外设。 我们编程的时候主要是对block2中的外设对应的地址进行编程,然后通过GPIO输出相应的高低电平
四:什么叫寄存器映射
给有特定功能的内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
例如我们在51单片机中为什么可以用 P0=0xFF 点亮小灯;这是因为在其头文件中reg52.h中利用sfr这个关键字定义了 sfr P0=0x80;这就意味这我们可以用P0代表80这个地址单元。但是在STM32中没有这个关键字。那它是如何实现的呢,在STM32参考手册中GPIOx-ODR的低十六位全位1即可点亮16个小灯,我们取x位B端口,GPIOB的起始地址位0x4001 0C00-0x4001 0FFF在这段地址中有很多的寄存器包括ODR(偏移地址位0Ch),这ODR这个寄存的地址为0x4001 0c0c(绝对地址)。
例如我们要实现GPIOB 16位全部输出高电平,则
*(unsigned int*)(0x40010C0C) = 0xFFFF;
但是这样有点麻烦可以这样(宏定义)
#define GPIOB_ODR (unsignedint*)(0x40010C0C) * GPIOB_ODR = 0xFF;
或
#define GPIOB_ODR *(unsignedint*)(0x40010C0C) GPIOB_ODR = 0xFF;
这就是寄存器映射。
下面我们尝试一下自己写TM32的寄存器映射以GPIOB为例(ST公司其实已经写好):
GPIOB挂载到APB2总线上
计算过程:
- 先找到外设所在总线的基地址0x4000 0000,然后在找到(APB2)偏移地址0x0001 0000 两者相加 0x4001 0000
- 然后找到(GIOPB)相对于APB2总线的偏移地址为0x0000 0C00,加上一个结果得 0x4001 0C00
- 然后我们找到ODR相对于GPIOB的偏移地址为0x0c 加上上一个结果得0x4001 0C0C 就得到我们想要找的ODR的地址。
代码:
第一种
总线和外设基址宏定义
- 上述我们想要实现的代码(上图的一部分)为
#define PERIPH_BASE ((unsigned int)0x40000000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) #define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) #define GPIOB_ODR *(unsignedint*)(GPIOB_BASE+0x0C) // PB0输出输出低电平 GPIOB_ODR &= ~(1<<0); // PB0输出输出高电平 GPIOB_ODR |= (1<<0);
2. &= ~ |= +移位操作 可以避免更改其它位。
第二种
1小方法(使用结构体指针访问寄存器)
我们发现各个寄存器的相对地址相差4个字节,那么我们可以将这些寄存器定义位一个结构体,这些寄存器定义为无符号int型,将结构体的地址定义为GPIOB的地址0x4001 0C00 仍可实现上面的功能。
如图(官方结构体封装)
使用结构体指针访问寄存器
2小方法(定义GPIO端口基地址指针)
其实这些官方都已经为我们写好固件库,我们只需要理解过程,这样在以后运用的时候能够加深印象。