存储器和寄存器

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

存储器映射:

  1. STM32的存储空间

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

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

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

  1. 存储器的区域功能划分

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

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

寄存器映射:

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

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

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

总线基地址:

外线基地址:

       外设寄存器:一般是指一些某一特殊功能的物理地址,外设寄存器的物理地址都在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 灯的亮灭。

  1. GPIO 的寄存器:

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

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

  • 寄存器的封装:

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

 

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

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

  1. 封装寄存器列表:

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

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

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

  1. 操作寄存器

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

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

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码字神经元

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值