手撕STM32F103寄存器映射

先看代码

stm32f10x.h

//用来存放STM32寄存器映射的代码

//外设 perirhral
#define PERIPH_BASE            	         ((unsigned int)0x40000000)		
#define APB1PERIPH_BASE                  PERIPH_BASE										
#define APB2PERIPH_BASE                 (PERIPH_BASE+0x10000)		
#define AHBPERIPH_BASE					(PERIPH_BASE+0x20000)		
																						
#define RCC_BASE						(AHBPERIPH_BASE+0x1000)
#define GPIOB_BASE						(APB2PERIPH_BASE+0x0C00)

#define RCC_APB2ENR						*(unsigned int*)(RCC_BASE+0x18)

#define GPIOB_CRL						*(unsigned int*)(GPIOB_BASE+0x00)
#define GPIOB_CRH						*(unsigned int*)(GPIOB_BASE+0x04)
#define GPIOB_ODR						*(unsigned int*)(GPIOB_BASE+0x0C)
#define GPIOB_BSRR						*(unsigned int*)(GPIOB_BASE+0x10)

以下是STM32F103的存储器映像(存储器在产家制作完成后是一片没有任何信息的物理存储器,而CPU要进行访存就涉及到内存地址的概念,因此存储器映射就是为物理内存按一定编码规则分配地址的行为。值得注意,存储器映射一般是由产家规定,用户不能随意更改。)

寄存器映射
寄存器映射是在存储器映射的基础上进行的。

以STM32为例,操作硬件本质上就是操作寄存器。在存储器片上外设区域,四字节为一个单元,每个单元对应不同的功能。当我们控制这些单元时就可以驱动外设工作,我们可以找到每个单元的起始地址,然后通过C 语言指针的操作方式来访问这些单元。但若每次都是通过这种方式访问地址,不好记忆且易出错。这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名实质上就是寄存器名字。给已分配好地址(通过存储器映射实现)的有特定功能的内存单元取别名的过程就叫寄存器映射。

首先取TIM2定时器的地址,作为起始地址,也是所有外设的基地址0x4000 0000让我们逐一分析

#define PERIPH_BASE            	((unsigned int)0x40000000)		//这是一个外设基地址

这段代码 #define PERIPH_BASE ((unsigned int)0x40000000) 是C语言中的一个宏定义。我们来分解一下这段代码,理解其作用:

  1. #define 这是C语言中的一个预处理指令,用于定义宏。它允许给定一个符号名称,将其定义为一个常量值或代码片段。预处理器在编译代码之前会用宏的值替换所有相应的出现。

  2. PERIPH_BASE 这是正在定义的宏的名称。它充当一个符号常量,表示内存中某个外设的基地址。使用宏来表示这样的地址可以使代码更易读、易维护。

  3. ((unsigned int)0x40000000) 这是分配给PERIPH_BASE宏的值。它代表外设映射的具体内存地址。在这里,数值 0x40000000 被强制转换为 unsigned int 类型。将地址强制转换为 unsigned int 类型通常是为了避免意外的符号扩展。

在实际应用中,这个宏可能被用在嵌入式系统或底层编程中,其中硬件外设(比如GPIO、UART等)被映射到特定的内存地址。使用宏可以让程序员使用符号名称 PERIPH_BASE 而不是原始的十六进制值,从而提高代码的可读性和可维护性。

#define APB1PERIPH_BASE          PERIPH_BASE

这里 PERIPH_BASE 已经定义为硬件寄存器的基地址(比如 0x40000000),而 APB1PERIPH_BASE 是属于第一个高性能总线 (APB1) 的寄存器的基地址,那么通过这样的宏定义,你可以在代码中使用 APB1PERIPH_BASE,而不必关心具体的硬件寄存器基地址。

#define APB2PERIPH_BASE         (PERIPH_BASE+0x10000)

这里APB2PERIPH_BASE为第二个高性能总线(APB2)的寄存器基地址,它在STM32F103的存储器映射表中,在基地址的基础上(PERIPH_BASE)偏移了0x10000(AFIO开始当作APB2总线基地址)这样可以在代码中使用APB2PERIPH_BASE,而不必关心具体的硬件寄存器基地址。

#define AHBPERIPH_BASE		   (PERIPH_BASE+0x20000)

通过这种方式你可以得到 AHBPERIPH_BASE,其值为 0x40000000 + 0x20000,表示 AHB 总线上的寄存器基地址。(DMA1开始当作AHB总线基地址)

由于之前已经宏定义过#define PERIPH_BASE                ((unsigned int*)0x40000000)

所以这里可以不写0x40000000而是使用PERIPH_BASE来替换,提高代码可读性

#define RCC_BASE								(AHBPERIPH_BASE+0x1000)

复位和时钟控制(RCC)在AHBPERIPH_BASE的基础上偏移了0x1000

#define GPIOB_BASE							(APB2PERIPH_BASE+0x0C00)

GPIOB端口的基地址在APB2PERIPH_BASE的基础上偏移了0x0C00

#define RCC_APB2ENR							*(unsigned int*)(RCC_BASE+0x18)

*(unsigned int*)(RCC_BASE + 0x18) 是一个将地址 RCC_BASE + 0x18 转换为无符号整数指针,然后通过指针解引用访问该地址的值的表达式。这通常用于访问嵌入式系统中的硬件寄存器,特别是在使用寄存器映射的方式时。

让我们逐步解释这个表达式:

  • RCC_BASE:是一个基地址,通常表示某个寄存器或寄存器组的基地址。在这里, RCC_BASE 是时钟控制寄存器(RCC)的基地址。

  • RCC_BASE + 0x18:表示基地址偏移了 0x18 字节,即指向了寄存器组中的某个具体寄存器。在这是 RCC_APB2ENR 寄存器,用于控制和配置微控制器上的某些外设的时钟。

  • (unsigned int*):将地址转换为指向无符号整数 (unsigned int) 的指针类型。

  • *(unsigned int*)(RCC_BASE + 0x18):通过指针解引用操作,访问 RCC_BASE + 0x18 地址上的值。

这种操作通常用于读取或写入硬件寄存器的值。在嵌入式系统中,这样的寄存器用于配置和控制设备的各种功能,例如时钟频率、外设使能等。

需要注意的是,直接访问硬件寄存器需要小心,确保了解硬件规格,避免不正确的配置,以及确保不会导致系统不稳定。在实际使用中,通常会使用芯片厂商提供的头文件或文档,以确保对寄存器的正确访问。

最后通过#define宏定义成RCC_APB2ENR,通过RCC_APB2ENR来读取或写入硬件寄存器的值

#define GPIOB_CRL					*(unsigned int*)(GPIOB_BASE+0x00)

将地址(GPIOB_BASE+0x00)强制类型转换为指针使用 * 过指针解引用操作,访问 GPIOB_BASE+0x00地址上的值。

最后通过#define宏定义成GPIOB_CRL,通过GPIOB_CRL来读取或写入硬件寄存器的值

#define GPIOB_CRH								*(unsigned int*)(GPIOB_BASE+0x04)

将地址(GPIOB_BASE+0x04)强制类型转换为指针使用 * 过指针解引用操作,访问 GPIOB_BASE+0x04地址上的值。

最后通过#define宏定义成GPIOB_CRH,通过GPIOB_CRH来读取或写入硬件寄存器的值

#define GPIOB_ODR								*(unsigned int*)(GPIOB_BASE+0x0C)

将地址(GPIOB_BASE+0x0C)强制类型转换为指针使用 * 过指针解引用操作,访问 GPIOB_BASE+0x0C地址上的值。

最后通过#define宏定义成GPIOB_ODR,通过GPIOB_ODR来读取或写入硬件寄存器的值

#define GPIOB_BSRR							*(unsigned int*)(GPIOB_BASE+0x10)

将地址(GPIOB_BASE+0x10)强制类型转换为指针使用 * 过指针解引用操作,访问 GPIOB_BASE+0x10地址上的值。

最后通过#define宏定义成GPIOB_BSRR,通过GPIOB_BSRR来读取或写入硬件寄存器的值

  • 47
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值