STM32内部寄存器、储存器、C对寄存器的封装
STM32的地址空间可以分为8个,分别是Block0~Block7,其中Block2是应用于外设的存储器,也是主要学习的内容。
存储器映射
存储器的地址由厂商或者用户分配,给存储器分配地址就叫做存储器映射。 Block0 主要用于设计片内的 FLASH。 Block1 用于设计片内的 SRAM。 Block2 用于设计片内的外设,根据外设的总线速度不同,Block 被分成了 APB 和 AHB 两部分,其中 APB 又被分为 APB1 和 APB2。
寄存器映射
通过单片机来控制外设时,其实就是对相应的寄存器进行控制,或者是说,对相应的地址对应的单元进行控制,然而,想要记住每个单元的地址是很难的,不如给每个地址起个名字,就叫“寄存器”吧。
- 首先来看一下,怎么直接操作地址来控制内存单元。GPIO是外设中的一种,并且在
STM32F103ZET6芯片中共GPIOA~GPIBG共七组,以GPIOB为例,控制GPIOB输出高电平,GPIOB输出寄存器ODR的地址为0x40010C0C。
*(unsigned int*)(0x4001 0C0C) = 0xFFFF;
unsigned int *p;
p = 0x4001 0C0C;
*p = 0xFFFF ;
可以看到,以上过程较为繁琐,我们不可能每次都这么操作,所以通过C语言对这一些列地址进行封装,称之为寄存器。
- 寄存器封装
#define GPIOB_ODR *(unsigned int*)(0x4001 0C0C)GPIOB_ODR
GPIOB_ODR = 0xFFFF;
GPIOB_ODR |= (1<<2);
GPIOB_ODR &= ~(1<<2);
- 寄存器结构体封装
GPIOA-GPIOE 都各有一组功能相同的寄存器,如GPIOA_ODR/GPIOB_ODR/GPIOC_ODR 等等,它们只是地址不一样,但却要为每个寄存器都定义它的地址。为了更方便地访问寄存器,我们引入 C 语言中的结构体语法对寄存器进行封装。
typedef unsigned int uint32_t;
typedef unsigned short int uint16_t;
typedef struct {
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint16_t LCKR;
} GPIO_TypeDef;
GPIO_TypeDef * GPIOx;
GPIOx = GPIOB_BASE;
GPIOx->IDR = 0xFFFF;
GPIOx->ODR = 0xFFFF;
uint32_t temp;
temp = GPIOx->IDR;
用 typedef 关键字声明了名为 GPIO_TypeDef 的结构体类型,结构体内有 7 个成员变量, 变量名正好对应寄存器的名字。并且如果使用GPIO_TypeDef类型的指针的时候,将IO的首地址赋予指针地址,指针在调用时,内部定义的变量储存的地址恰好与GPIO对应的各个寄存器的地址对应,只需要调用,GPIO的成员变量即可对对应的寄存器操作。
|