【STM32】MDK中寄存器地址名称映射分析

摘要:
STM32访问地址寄存器地址名称映射STM32也必须能够以这种方式设置寄存器。然而,由于STM32的寄存器数量太多,如果以这种方式列出,则需要大量空间,不便于开发。因此,MDK使用结构将寄存器组织在一起。也就是说,STM32和51 MCU之间的最大区别在于,由于STM32中的寄存器太多,控制同一外围设备的寄存器被设置为一个结构,而特定的寄存器由结构的地址和寄存器相对于结构的偏移地址决定。

对于MCU,一切底层配置,最终都是在配置寄存器

51单片机访问地址

51单片机经常会引用一个reg51.h的头文件。下面看看它是怎么把名字和寄存器联系在一起的:

1 sfr p0=0x80;
2 p0=0x00;

sfr是一种扩充数据类型,使用一个内存单位,值域为0-255.利用它可以访问51单片机内部所有的特殊功能寄存器。前一句“sfr p0=0x80”就是将P0映射到地址0x80。以后对P0的读写操作即使对0x80地址对应的单元进行读写操作;注意:单独的地址是不能进行操作的,必须对地址所对应的变量操作

后一句“p0=0x00”就是往p0地址(0x80)代表的寄存器写值。

STM32访问地址
寄存器地址名称映射
STM32肯定也是可以这样来设置寄存器的。但是由于STM32的寄存器数目太多了,如果以这样的方式列出来,需要很大的篇幅,而且也不方便开发。所以,MDK采用的方式是通过结构体来将寄存器组织在一起。

下面就介绍MDK如何把结构体和地址对应起来的,为什么修改结构体成员变量的值就可以达到操作寄存器的值?这些事情都是在stm32f10x.h文件中完成的。

注:stm32f10x.h文件在STM32固件库下的目录是:

STM32F10x_StdPeriph_Lib_V3.5.0LibrariesCMSISCM3DeviceSupportSTSTM32F10x文件夹下。

GPIOA的寄存器地址名称映射

我们通过GPIOA的寄存器为例来进行介绍。

 1 GPIOA->ODR=0x00000000; 

首先,我们需要看一下GPIOA是个什么东西?通过宏定义我们可以看到:

1 #define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
2 #define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)
3 #define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
4 #define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
5 #define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)
6 #define GPIOF               ((GPIO_TypeDef *) GPIOF_BASE)
7 #define GPIOG               ((GPIO_TypeDef *) GPIOG_BASE)

GPIOA是一个将GPIOA_BASE强制转换成GPIO_TypeDef的指针。这句话的意思就是,GPIOA指向地址GPIOA_BASE,而GPIOA_BASE存放的数据类型是GPIO_TypeDef。

再看一下结构体GPIO_TypeDef的定义:

 1 typedef struct
 2 {
 3   __IO uint32_t CRL;
 4   __IO uint32_t CRH;
 5   __IO uint32_t IDR;
 6   __IO uint32_t ODR;
 7   __IO uint32_t BSRR;
 8   __IO uint32_t BRR;
 9   __IO uint32_t LCKR;
10 } GPIO_TypeDef;

结构体里面声明了7个变量,这个时候就明白了“GPIOA->ODR”就是指:GPIOA结构体下的ODR变量。

其实结构体的7个变量就是GPIOA的7个寄存器。我们需要知道GPIOA下的ODR寄存器的地址,首先需要知道的是GPIOA的基地址是怎么计算的呢?

1 #define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)
2 #define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)
3 #define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)
4 #define GPIOD_BASE            (APB2PERIPH_BASE + 0x1400)
5 #define GPIOE_BASE            (APB2PERIPH_BASE + 0x1800)
6 #define GPIOF_BASE            (APB2PERIPH_BASE + 0x1C00)
7 #define GPIOG_BASE            (APB2PERIPH_BASE + 0x2000)

因为GPIO都是挂载在APB2总线之上的,所以它的基地址是由APB2总线的基地址+GPIO在APB2总线上的偏移地址决定的。

那么APB2总线的基地址是怎么计算的呢?

1 #define PERIPH_BASE       ((uint32_t)0x40000000) 
2 #define APB2PERIPH_BASE   (PERIPH_BASE + 0x10000)

原理都是一样的,APB2总线的基地址也是从其他地址进行地址偏移得到的。

所以到这个时候,就可以算出GPIOA的基地址位了:

GPIOA_BASE=0x40000000+0x10000+0x0800=0x40010800

这上面就已经知道了GPIOA的基地址,那么那些GPIOA的7个寄存器的地址又是怎么计算出来的呢?

【STM32】MDK中寄存器地址名称映射分析第1张

 

GPIOA的寄存器的地址=GPIOA基地址+寄存器相对GPIOA基地址的偏移值

寄存器相对于GPIOA基地址的偏移值可以在上面的寄存器地址映射表中查到。稍微解释一下:GPIO的每个寄存器都是32位的,所以每个寄存器是占用4个地址,也就是说一共占用28个地址。地址偏移范围为(000h-01Bh)。这个地址偏移是相对于GPIOA的基地址而言的。

那么你可能又有一个疑问:结构体里面的寄存器又是怎么与地址一一对应的呢?这就涉及到结构体的一个特征,那就是结构体存储的成员的地址是连续的。上面讲到GPIOA是指向GPIO_TypeDef类型的指针,又由于GPIO_TypeDef是结构体,所以自然而然我们就可以算出GPIOA指向的结构体成员变量对应地址了。

 

总结与分析
对于STM32而言,使用“GPIOA->ODR=0x00000000;”来对寄存器赋值的原理,也就是将GPIO下的所有寄存器放在一个结构体内,通过基地址和在基地址上的偏移地址不断转化,最终找到准确的寄存器实际地址来进行赋值。也就是说,和51单片机最大的不同就是:由于STM32的寄存器数目太多,就将其中控制同一外设的寄存器设置成一个结构体(如GPIO、DMA等),通过对结构体的地址和寄存器相对于结构体的偏移地址,来确定某个特定的寄存器。


原文链接:https://blog.csdn.net/qq_38410730/article/details/79816270

  可以结合博客中《stm32 中库函数、结构体、地址的强制类型转换、相应特殊功能寄存器之间的关系》这篇文章看更能体会到地址映射、为什么使用结构体、库函数中各种赋值是怎么一会事,就像这篇文章开头所说一切的配置就是对于相应的寄存器配置,应为不同的外设中有各种各样的寄存器,我们想要使用这个外设的相应功能,就需要对于这个外设中相应的寄存器进行配置,才能使这个外设进行正常的运行。

  举一个不是很恰当的例子:就像电脑一样你要使用电脑中的word这个软件,对于电脑这个外设就需要配置操作系统,以及显示器、键盘、鼠标这些驱动、安装word后才能正常使用word;而操作系统和安装驱动就是对于能够正常使用word所做的配置;就像对于stm32中外设寄存器配置一样。

免责声明:文章转载自《【STM32】MDK中寄存器地址名称映射分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Verilog 模块参数重定义(转)H5与企业微信jssdk集成下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

STM32F1库函数初始化系列:DMA—ADC采集

1 void ADC_Configure(void) 2 { 3 ADC_InitTypeDef ADC_InitStructure; 4   GPIO_InitTypeDef GPIO_InitStructure; 5 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); 6   RCC_AHBPer...

MODBUS串行通信协议详细说明

第一章  简介 本文详细地描述了装置在MODBUS 通讯模式下的输入和输出命令、信息和数据,以便第三方使用和开发。 1.1 串行通讯协议的目的 通信协议的作用是使信息和数据在上位机主站和装置之间有效地传递,它包括: (1)   允许主站访问和设定所接装置的全部设置参数; (2) 允许访问装置的所有测量数据。     第二章  装置 MODBUS串行通信协议...

(stm32f103学习总结)—RTC独立定时器—实时时钟实验

一、STM32F1 RTC介绍 1.1 RTC简介   STM32 的实时时钟( RTC)是一个独立的定时器。 STM32 的 RTC 模 块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的 功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC模块和时钟配置是在后备区域,无论器件状态如何(运行模式、 低功耗模式或处于复位状态),只要...

Linux安装Elasticsearch-head插件

首先需要下载以下内容:   我试验的对应版本:ES:elasticsearch-6.6.1.tar.gz  Node:node-v10.15.3-linux-x64.tar  JDK:jdk-8u201-linux-x64.tar.gz   1. node-v10.15.3-linux-x64.tar 下载地址:https://nodejs.org/en/...

Redis 下载与安装(Windows版)

1、Github下载地址:https://github.com/MicrosoftArchive/redis/releases 2、百度网盘下载地址:Redis-x64-3.2.100.zip   密码:kdfq 1、打开一个命令窗口,通过 cd 命令进入到你解压的目录 2、输入命令:redis-server redis.windows.conf ,启动...

如何在Ubuntu 20.04 / 18.04或更老版本中安装ifconfig

Ubuntu Linux是最流行的操作系统之一,因此,如果你正在使用它,并希望使用Ifconfig命令查看系统的Ip地址,那么有办法安装它。就像在Windows中的ipconfig一样,我们有ifconfig for Linux操作系统来获取和使用命令行查看所有可用的网络适配器的Ip地址。然而,默认情况下,它不会出现在你的Ubuntu系统中,这需要手动安装...