存储器和寄存器

  • 存储器映射:给存储器分配地址的过程
  • 寄存器映射:给(已经分配好地址的)(有特定功能的)内存单元取别名的过程
  • 封装寄存器:补充

存储器映射:

  1. STM32的存储空间

①存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射,如果给存储器再分配一个地址就叫存储器重映射。

②程序存储器、数据存储器、寄存器和输入输出端口被组织在同一个4GB的线性地址空间内。数据字节以小端格式存放在存储器中。一个字里的最低地址字节被认为是该字的最低有效字节,而最高地址字节是最高有效字节。

③存储空间的大小是由芯片内CPU内的地址总线的数量来决定,而stm32芯片内部的总线为32。内存被划分为一个个的内存单元,每个内存单元的大小是一个字节,为了能有效的访问到内存的每个单元就给内存单元进行编号,编号就被称为该内存单元的地址。

存储器和寄存器_第1张图片

存储器和寄存器_第2张图片
存储器和寄存器_第3张图片
  1. 存储器的区域功能划分

①4GB 的地址空间中,ARM 将其平均分成了 8 个块,每块 512MB,每个块也都规定了用途每个块的大小都有512MB,显然这是非常大的。

存储器和寄存器_第4张图片

②三个重要块:Block0 用来设计成内部 FLASH,Block1 用来设计成内部 RAM,Block2 用来设计成片上的外设。

存储器和寄存器_第5张图片

寄存器映射:

  1. 在存储器 Block2 这块区域,设计的是片上外设,它们以四个字节为一个单元,共32bit,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。
  2. 我们可以找到每个单元的起始地址,然后通过 C 语言指针的操作方式 (既然一个单元是四个字节那我们就用一次取四个字节的指针(int * )来操作这些功能单元) 来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个给(已经分配好地址的)(有特定功能的)内存单元取别名的过程就叫寄存器映射
  3. 寄存器:寄存器只是特定功能的的单元的名字而已
  4. 比如,GPIOB 端口的输出数据寄存器 ODR 的地址是 0x4001 0C0C。通过 C 语言指针的操作方式,让 GPIOB 的 16 个 IO 都输出高电平。

存储器和寄存器_第6张图片

  1.  如何给功能单元取个别名(寄存器)

存储器和寄存器_第7张图片

  1. STM32F10xxx中内置外设的起始地址:

存储器和寄存器_第8张图片

存储器和寄存器_第9张图片

存储器和寄存器_第10张图片

总线基地址:

外线基地址:

存储器和寄存器_第11张图片

       外设寄存器:一般是指一些某一特殊功能的物理地址,外设寄存器的物理地址都在0x4800_0000~0x5FFF_FFFF,比如STM32中,GPIO、I²C、SPI、CAN都叫做外设寄存器。嵌入式通过编程来控制外设寄存器从而控制芯片外部的外设。

   内部寄存器:指的是CPU内核里的寄存器,如r0,r1等。

       内存:内存(Memory)也被称为内存储器,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。如RAM,SDRAM,Flash等。

       物理地址:操作系统会给每一个内存单元编上一个绝对的号,计算机系统就通过这个编号来定为每一个内存单元的物理位置,这个编号称为内存的物理地址。

  • 区别
  1. 外设寄存器

       在 XX 外设的地址范围内,分布着的就是该外设的寄存器。以 GPIO 外设为例, - GPIO(general purpose input output)是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚 ,基本功能是控制引脚输出高电平或者低电平。

       最简单的应用就是把 GPIO 的引脚连接到 LED 灯的阴极,LED 灯的阳极接电源,然后通过 STM32 控制该引脚的电平,从而实现控制 LED 灯的亮灭。

存储器和寄存器_第12张图片

  1. GPIO 的寄存器:

存储器和寄存器_第13张图片

GPIO 有很多个寄存器,每一个都有特定的功能。每个寄存器32bit,占四个字节,在该外设的基地址上按照顺序排列,寄存器的位置都以相对该外设基地址的偏移地址来描述。

各个寄存器的地址=外设基地址+寄存器相对于外设基地址的偏移

存储器和寄存器_第14张图片

存储器和寄存器_第15张图片

存储器和寄存器_第16张图片

  • 寄存器的封装:

上面方式还不够方便,接下来经过层层套娃,找到各个外设寄存器的地址再用C语言的结构体进行封装。

 

  1. 封装总线和外设基地址

在编程上为了方便理解和记忆,我们把总线基地址和外设基地址都以相应的宏定义起,总线或者外设都以他们的名字作为宏名。

存储器和寄存器_第17张图片

  1. 封装寄存器列表:

存储器和寄存器_第18张图片

到这里大家有没有发现一个特点寄存器的地址每次偏移4,如果定义一个寄存器的类型为(unsigned int)是不是正好在内存中占4个字节,而一个内存单元就是1个字节,分配一个地址,那4个字节不正好每次偏移4个地址,而且有符合结构体的内存对齐,关于结构体的内存对齐这里不细讲,以后会出有关结构体的文章详细阐述。

存储器和寄存器_第19张图片

把寄存器封装成结构体后,接下来就是取出寄存器对寄存器进行操作。以GPIOA为例,我们将GPIOA外设的基地址强制类型转化为该结构体的首地址。不就完美解决了嘛。

我们定义的这个 GPIO_TypeDef ,这个结构体的首地址就为 0x4001 0800(这也是第一个成员变量 CRL 的地址), 那么结构体中第二个成员变量 CRH 的地址即为 0x4001 0800 +0x04 ,加上的这个 0x04 ,正是代表 CRL 所占用的 4 个字节地址的偏移量,其它成员变量相对于结构体首地址的偏移。

  1. 操作寄存器

最后我们就可以直接使用宏定义好 GPIO_TypeDef 类型的指针,而且指针指向各个 GPIO 端口的首地址,使用时我们直接用GPIOA这个指针对结构体成员寄存器进行访问。

存储器和寄存器_第20张图片

单片机的本质其实就是在操作寄存器。stm32的库函数开发也不例外,它只不过是将操作寄存器封装成一个个函数,我们只要配置指定函数的参数,再调用该函数自动把对应的寄存器配置好。(先看库函数,再看寄存器,方便理解)

你可能感兴趣的:(STM32学习笔记,单片机,stm32,嵌入式硬件)