【stm32】物理内存地址如何与指针对应上

本文详细介绍了C语言中&取地址运算符和*寻址运算符的用法,涉及指针的概念、类型转换,以及如何在STM32中通过指针操作寄存器。讲解了内存地址、指针与不同类型数据的关系,并强调了无符号int指针在硬件控制中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

.

.

1 C语言基础----- * 与 & 运算符以及强制类型转换

1 &是取地址符号

我们的变量都是存放在物理内存上的,每一个变量定义的时候就被分配了地址,要想知道变量的地址可以用取地址运算符 & ,如取变量 a 的地址 &a 。

&a 的运算结果是a的地址,即&a执行完之后返回一个地址,这个地址的数据类型是指针,即返回的数值并不是一个简单的整数,而是一个unsigned int*类型的,对于这个类型的理解在下面有讲。

2 *是寻址运算符

当我们知道了一个变量的地址之后,即知道了变量的指针之后,想要找到变量对应存放的内存单元,就需要运用 * 来寻址,如*(变量a的地址)

*(变量a的地址)的结果是直接连通物理内存与软件

即你可以读取变量a的值,b=*(变量a的地址),读取a变量内存单元的数据,即读取a的值,然后赋值给b

你也可以将b的值写入a的内存单元,*(变量a的地址)=b;将b的数据赋值到a的内存单元中,即将b的值赋值给a。

3 强制类型转换

将一个数据的类型强制转换成另一种类型

语法:(需要转换的类型)(被转换的数据)

如,将小数转换成int类型的数:(int)(3.14)

2 内存与指针对应

1 操作寄存器 

我们知道想要用软件控制硬件外设,中间必须通过寄存器,软件控制寄存器,寄存器再控制硬件外设。

在stm32中外设的寄存器是专门放在一个特定的内存块当中的,块的起始地址是0x4000 0000

如果想要控制某个外设,就必须操作对应的寄存器,查看参考手册可以知道寄存器的地址,比如为0x4000 0000,那么如何通过软件去写入数据呢?

我们用到*(unsiged int*)(0x40000000)

2 *(unsiged int*)(0x40000000)解读

1 0x40000000是整形

首先,我们要明确的是,0x4000 0000是一个十六进制的整形数据,并不是一个指针,不可以用*进行寻址。

2 unsiged int* 是一个指向unsiged int数据类型的指针

*代表这是一个指针类型,unsiged int代表该指针指向的物理内存中存放的数据是unsiged int类型的。

为什么要有unsiged int呢

假设有一系列连续的房子,每一间房子都有一个编号,并且编号的连续的

当你们家只有一间房子的时候,房号就是你们家的地址

但是当你们家有好几间房子的时候,如果把所有房号都记下来就很麻烦了,所以我们采用第一间房子房号与房间数的方法记,即只要知道你们家第一间房的房号和你们有多少间房就可以知道哪些房子是你们的了(假设你们的房子的房间号连续)。

指针也一样,指针代表的是变量的首地址,但是变量都占有很多个内存单元,因此在首地址的信息的基础上加上变量占用内存单元的大小的信息就可以准确知道变量的所有内存单元了,而这个占用内存单元大小的信息就用unsiged int等等的数据类型标识符来标记。

3 (unsiged int*)(0x40000000)是强制类型转换

我们知道0x40000000是一个十六进制的整形,整形是不可以寻址的,即虽然你知道寄存器的地址的数值,但是你无法通过寻址操作来找到对应的内存。

因此我们需要将整形强制转换成指针。

4 unsiged int是多长

在不同的单片机中,unsiged int的长度是不同的,他的长度是由单片机的位数来决定的,在stm32中,unsiged int的长度是32位,即4个字节。

5 为什么是转换成 unsiged int

首先我们明确为什么是unsigned(无符号),unsigned是无符号的意思,就是说没有负数。

unsigned int 的类型是指针指向的内存单元存放的数据的类型,我们知道这里寄存器操作指向的内存单元就是寄存器,而寄存器的数据是每一位的数值都是有特定的意义的,实际上这里的数据类型你可以定义成任何数据类型,只要长度是32位进行了,即int也行,但是定义成int的话,假设寄存器是8位的,如果你要往寄存器中写1000 0001的二进制数据,那么由于int是有符号的,内存中最高位代表符号位,写入的是正数,因此最高位是0,最后写入的是0000 0001,因为数据位只有7位,写入8位的数据会溢出,导致丢失最高位。所以为了方便准确控制和写入寄存器数据,将寄存器的数据定义成无符号的,即写入什么就是什么。

为什么长度是int

指针指向的数据类型的长度代表着一个地址代表多长的内存单元,由于这里的内存单元代表这外设的寄存器,因此所定义的数据类型的长度必须等于一个寄存器占用的内存单元的长度。在stm32中,外设的寄存器的长度都是32位的,因此指针的类型也是32位的。

6  *(unsiged int*)(0x40000000)是寻址

*(unsiged int*)(0x40000000)是找到对应的内存单元,用于写入数据或者读出数据。

3 总结

软件与硬件内存之间是通过指针操作来实现的,在单片机中指针具有更清晰的物理意义,了解指针的物理意义(对应内存的什么),掌握指针的运算是操作内存/.寄存器的基本要求。

<think>好的,用户想了解STM32的内存地址架构,我需要详细解释这个问题。首先,我得回忆一下STM32的内存结构,结合之前看到的引用内容。 记得引用[1]提到,STM32的存储器结构Cortex-M3相似,但加入了Flash和SRAM等实际组件。所以应该从Cortex-M3的架构说起,然后过渡到STM32的具体实现。 首先,Cortex-M3的地址空间是4GB,分为不同的区域,比如代码区、SRAM区、外设等。STM32在此基础上划分了Flash、SRAM、外设寄存器等部分。需要详细说明每个区域的地址范围,比如Flash通常从0x08000000开始,SRAM从0x20000000开始。 然后,启动配置也很重要。STM32的启动模式选择不同会影响初始地址,比如从主Flash启动时,0x08000000会被映射到0x00000000。这一点在启动文件里可能有设置,引用[2]提到启动文件.s中设置了堆栈,堆栈是在RAM分配给RW和ZI数据之后分配的。需要解释堆栈的位置如何影响内存布局。 内存分配方面,用户可能想知道编译后的程序如何占用内存。代码段放在Flash,已初始化的全局变量在RW-data,未初始化的在ZI-data,堆栈在RAM末尾。需要结合引用[2]的内容,说明堆栈的分配位置以及如何调整。 外设寄存器部分,地址固定,比如APB和AHB总线对应的外设地址范围。引用[3]虽然主要讲ADC,但提到外设集成,可以举例说明外设寄存器的访问方式。 内存映射方面,可能需要提到别名区域,比如通过不同地址访问同一物理内存,用于位带操作,这在Cortex-M3中支持,STM32是否也有?需要确认并解释其作用。 最后,实际应用中的注意事项,如地址越界、堆栈溢出,以及如何通过分散加载文件调整内存分配。这部分可以引用启动文件的内容,如引用[2]提到的堆栈设置。 用户可能还想知道如何查看内存映射,或者如何优化内存使用,但根据问题,重点在架构详解,所以需要覆盖结构、启动配置、分配、外设和映射等内容,确保每个部分都有引用支持,并自然添加引用标识。</think>### STM32内存地址架构详解 STM32的内存地址架构基于**Cortex-M系列处理器的统一存储器映射**,其设计遵循ARM架构规范,同时结合了芯片实际硬件资源(如Flash、SRAM、外设寄存器等)。以下是具体分析: --- #### 1. **内存地址空间划分** STM32的4GB地址空间(32位系统)分为以下主要区域: - **代码区(Code Area)** 地址范围:$0x00000000$ - $0x1FFFFFFF$ 用途:存放程序代码(Flash),例如主Flash通常从$0x08000000$开始[^1]。 - **SRAM区(SRAM Area)** 地址范围:$0x20000000$ - $0x3FFFFFFF$ 用途:运行时数据存储,例如STM32F4的SRAM起始地址为$0x20000000$,大小因型号而异(如192KB或更多)。 - **外设寄存器区(Peripheral Registers)** 地址范围:$0x40000000$ - $0x5FFFFFFF$ 用途:映射所有片上外设(如GPIO、ADC、USART)的控制寄存器[^3]。 - **其他区域** 包括位带别名区($0x42000000$)、系统控制区($0xE0000000$)等,用于特殊操作(如位操作、调试)。 --- #### 2. **启动配置地址映射** STM32支持多种启动模式,通过BOOT引脚配置: - **主Flash启动**(默认):Flash起始地址$0x08000000$映射到$0x00000000$,CPU从此读取初始堆栈指针和复位向量[^2]。 - **系统存储器启动**:用于内置Bootloader,地址由芯片厂商定义。 - **SRAM启动**:调试时临时使用,直接运行RAM中的代码。 --- #### 3. **内存分配堆栈管理** - **编译后的内存占用**: 代码段(`.text`)存储在Flash中; 已初始化全局变量(`.data`)加载到RAM; 未初始化变量(`.bss`)占用RAM的ZI-data区域。 - **堆栈分配**: 堆(Heap)和栈(Stack)位于RAM末尾,由启动文件(`.s`)定义大小。例如: ```c Stack_Size EQU 0x00000400 // 1KB栈 Heap_Size EQU 0x00000200 // 512B堆 ``` --- #### 4. **外设寄存器的地址固定性** 每个外设的寄存器地址在芯片设计时已固定。例如: - **GPIOA**的寄存器基址为$0x40020000$; - **ADC1**的寄存器基址为$0x40012000$(不同型号可能不同)[^3]。 --- #### 5. **内存映射的灵活性** STM32支持**别名区(Bit-Band)**操作,允许通过位带别名地址直接操作单个比特。例如: - 原始地址:$0x20000000$的某比特; - 别名地址:$0x22000000 + (0x20000000 - 基址) \times 32 + 比特序号 \times 4$。 --- #### 6. **实际应用注意事项** - **地址越界**:访问未分配区域会触发硬件错误(HardFault)。 - **堆栈溢出**:需合理设置栈大小,避免覆盖其他数据。 - **分散加载文件(Scatter File)**:可自定义代码和数据的存储位置。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@枭白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值