STM32学习笔记【5】寄存器映射代码讲解

寄存器映射代码讲解

1.外设总线

查阅系统手册:
STM32学习笔记【5】寄存器映射代码讲解_第1张图片

由图可知,AHB(Advanced High performance Bus,高级高性能总线)下面挂载了RCC(Reset and clock control复位时钟控制器)和2个APB(Advanced Peripheral Bus,高级外设总线)。

其中,APB2为高速总线。


1.RCC总线

实际开发中,大部分的外设启用之前,都需要先启用RCC。APB1和APB2都有独立的RCC寄存器。而RCC寄存器是挂载在AHB上的。

查阅手册目录得知,RCC相关寄存器有如下种类:
STM32学习笔记【5】寄存器映射代码讲解_第2张图片

查阅手册里的寄存器地址得知,RCC总线的起始地址为0x40021000-0x400213FF

STM32学习笔记【5】寄存器映射代码讲解_第3张图片

1.外设时钟使能寄存器

一般我们使用RCC之前,首先需要对寄存器进行使能,这里以APB2进行举例。

我们查询到APB2外设时钟使能寄存器(RCC_APB2ENR)的偏移地址为:0x18
STM32学习笔记【5】寄存器映射代码讲解_第4张图片

2.外设时钟使能代码实现
//存储器映像从0x40000000开始。
#define PERIPH_BASE             (unsigned int)0x40000000

//APB1的范围为0x40000000到0x4000FFFF,所以基址和PERIPH_BASE相同。
#define APB1_PERIPH_BASE        PERIPH_BASE

//APB1的范围为0x40010000到0x4003FFF,所以基址为PERIPH_BASE+0x10000。
#define APB2_PERIPH_BASE        (PERIPH_BASE+0x10000)

//AHB的范围0x40018000到0x40023FFF,但由于16进制中进位较为容易混淆,出于计算方便的目的,我们将基址定为0x40020000。
#define AHB_PERIPH_BASE         (PERIPH_BASE+0x20000)

//上文查阅手册得知,RCC基址为0x40021000。
#define RCC_BASE                (AHB_PERIPH_BASE+0x1000)

//APB2外设时钟使能寄存器(RCC_APB2ENR)的偏移地址为:0x18,此处使用unsigned int*是为了连续4个字节取值。
#define RCC_APB2ENR              *(unsigned int*)(RCC_BASE+0x18)


2.GPIO总线

第四章中介绍了GPIO,链接在:

我们本次实验的目的是使用寄存器映射点亮LED灯,需要使用GPIOB端口,所以要先完成GPIOB总线的配置。

1.GPIO寄存器的地址

查阅《STM32F103中文参考手册》得知,GPIO端口的寄存器地址如下:
STM32学习笔记【5】寄存器映射代码讲解_第5张图片##### 2.GPIO寄存器地址的代码映射

//点亮LED灯只需要GPIBO,我们先定义GPIOB的基址
#define GPIOB_BASE            (APB2_PERIPH_BASE +0x0C00)

//端口配置低寄存器
#define GPIOB_CRL					  *(unsigned int*)(GPIOB_BASE +0x00)

//端口配置高寄存器
#define GPIOB_CRH					  *(unsigned int*)(GPIOB_BASE +0x04)

//端口输出寄存器
#define GPIOB_ODR					  *(unsigned int*)(GPIOB_BASE +0x0C)

//...其他部分如法炮制即可,本次实验只需要使用这么多

2.实验代码

这里我们将要用寄存器映射代码代替原先的寄存器编码的方式。

1.寄存器编码

int main(void)
{
    //配置时钟
    *(unsigned int *)0x40021018 |=(1<<3);
    
    //配置I/O口模式
    *(unsigned int *)0x40010C00 |=(1<<(4*0));
    
    //控制ODR寄存器
    *(unsigned int *)0x40010C0C &=~(1<<0);
}

2.寄存器映射

int main(void)
{
    //配置时钟
    RCC_APB2ENR |=(1<<3);
	
    //配置I/O口模式,GPIO 0~7使用CRL,8~15使用CRL
    //需要使用模拟输入/开漏输出模式,所以赋值为0001
    GPIOB_CRL |=(1<<(4*0));
	
    //控制ODR寄存器
    GPIOB_ODR &=~(1<<0);
}

3.代码优化

CRL寄存器写入之前,如果不清零可能会有错误出现。所以在这里我们需要多一步清零的操作。

我们知道,单独清零某个位使用&=一个1的操作就可以完成。那么清零16位的int型我们只需要&= 0x0f就可以完成。

实际代码如下:

int main(void)
{
    //配置时钟
    RCC_APB2ENR |=(1<<3);
	
    //配置I/O口模式,GPIO 0~7使用CRL,8~15使用CRL
    //清零操作
    GPIOB_CRL &=~(0x0f);
    
    //需要使用模拟输入/开漏输出模式,所以赋值为0001
    GPIOB_CRL |=(1<<(4*0));
	
    //控制ODR寄存器
    GPIOB_ODR &=~(1<<0);
}

你可能感兴趣的:(C语言,STM32,STM32F103)