野火霸天虎 STM32F407 学习笔记_2 寄存器介绍

寄存器

虽然正式编程没有必要用寄存器编程,通常都是库函数或者 hal 库。但是还是有必要学一下原理的。

寄存器映射

芯片视图如下。

丝印:芯片上印的信息。型号,内核,生产批次等。

引脚:左上角是有小圆点的,从左上-左下-右下-右上逆时针看。或者如果没有小圆点,把丝印方向摆正,从左上角开始看。

芯片内部组成:

寄存器映射:32位,232=4GB,因此所有程序都需要通过内存 4GB 去映射访问。

block7:M4 芯片内外设,比如一些通信总线这些都算外设。

block1:内存。

block0:代码。不过实际上由于设计工艺的问题,block0 block1 都只用了很少的一部分来存代码或者作为内存。

外设寄存器放在 block2 中。根据不同块速度不一样,又具体分为不同速度的外设(AHB APB)。

总线速度:AHB>APB2>APB1. APB1 是较低速的外设,包括 I2C UART SPI 看门狗等。

我们想要操作特定的外设,其实就是控制他的寄存器。控制寄存器就要找到寄存器相应的地址往里面写入数据,寄存器地址就是内存中的地址映射。

比如 GPIOF 我们想让其端口全部输出高电平。我们查找 stm32f407 手册,发现 GPIOF 的地址是 0x40021400,GPIOF 的 ODR(output data register)相对起始地址的偏移地址是14,则我们需要给 0x40021414 的地址写入数据 0xFFFF.

51 单片机库函数中封装的 reg51.h 中,利用 sfr 定义寄存器地址;而 stm32 库函数中使用宏定义,这些就是寄存器映射操作。对芯片里一个特殊功能的内存单元起别名的过程就是寄存器映射。 给这个地址再分配一个地址交重映射,stm32 中不咋常用。

C语言对寄存器的封装

这样逐个地址,哪怕已经进行了寄存器映射,还是很复杂。

c 语言库函数实际进行的封装操作是使用结构体批量定义。

c 复制代码
/* GPIO 外设基地址 */
#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000)
#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400)
#define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800)
#define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00)
#define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000)
#define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400)
#define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800)
#define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00)

/* GPIO 寄存器列表 */
typedef struct {
    uint32_t MODER; /*GPIO 模式寄存器 地址偏移: 0x00 */
    uint32_t OTYPER; /*GPIO 输出类型寄存器 地址偏移: 0x04 */
    uint32_t OSPEEDR; /*GPIO 输出速度寄存器 地址偏移: 0x08 */
    uint32_t PUPDR; /*GPIO 上拉/下拉寄存器 地址偏移: 0x0C */
    uint32_t IDR; /*GPIO 输入数据寄存器 地址偏移: 0x10 */
    uint32_t ODR; /*GPIO 输出数据寄存器 地址偏移: 0x14 */
    uint16_t BSRRL; /*GPIO 置位/复位寄存器低 16 位部分 地址偏移: 0x18 */
    uint16_t BSRRH; /*GPIO 置位/复位寄存器高 16 位部分 地址偏移: 0x1A */
    uint32_t LCKR; /*GPIO 配置锁定寄存器 地址偏移: 0x1C */
	uint32_t AFR[2]; /*GPIO 复用功能配置寄存器 地址偏移: 0x20-0x24 */
} GPIO_TypeDef;

/* 使用 GPIO_TypeDef 把地址强制转换成指针 */
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)

所有外设都是如此,首先定义总线 APB AHB 地址,然后每个外设在其基础上进行偏移,每个外设的不同部分再在该外设基址上进行偏移。

相关推荐
习习.y17 分钟前
python笔记梳理以及一些题目整理
开发语言·笔记·python
Z***G47936 分钟前
网络爬虫学习:借助DeepSeek完善爬虫软件,实现模拟鼠标右键点击,将链接另存为本地文件
爬虫·学习·计算机外设
在逃热干面43 分钟前
(笔记)自定义 systemd 服务
笔记
我命由我123452 小时前
微信开发者工具 - 模拟器分离窗口与关闭分离窗口
前端·javascript·学习·微信小程序·前端框架·html·js
DKPT2 小时前
ZGC和G1收集器相比哪个更好?
java·jvm·笔记·学习·spring
Main. 243 小时前
从0到1学习Qt -- 常见控件之显示类控件
qt·学习
e***19353 小时前
爬虫学习 01 Web Scraper的使用
前端·爬虫·学习
QT 小鲜肉4 小时前
【孙子兵法之上篇】001. 孙子兵法·计篇
笔记·读书·孙子兵法
星轨初途5 小时前
数据结构排序算法详解(5)——非比较函数:计数排序(鸽巢原理)及排序算法复杂度和稳定性分析
c语言·开发语言·数据结构·经验分享·笔记·算法·排序算法
QT 小鲜肉5 小时前
【孙子兵法之上篇】001. 孙子兵法·计篇深度解析与现代应用
笔记·读书·孙子兵法