STM32F103C8T6单片机内部执行原理及启动流程详解

引言:为什么深入理解STM32启动流程很重要?

STM32F103C8T6作为嵌入式开发中最常用的单片机之一,其内部执行原理启动流程是理解嵌入式系统底层运行机制的核心。无论是开发Bootloader、调试HardFault异常,还是优化系统启动速度,都需要对这两部分有深入掌握。本文将从硬件架构到软件执行,全方位解析STM32F103C8T6的工作原理,配合代码示例和实战技巧,帮助你彻底搞懂单片机从"上电"到"运行main函数"的全过程。

一、STM32F103C8T6内部执行原理

1.1 核心架构:Cortex-M3内核与哈佛结构

STM32F103C8T6基于ARM Cortex-M3内核,采用哈佛架构Harvard Architecture ),将指令存储和 数据存储分离为两条独立总线:

I-Code总线:专门用于取指(32位宽),可一次读取两条16位Thumb指令

D-Code总线:专门用于数据访问(32位宽),支持字节/半字/字操作

这种架构的优势在于指令读取和数据访问可并行执行,大幅提升运行效率。相比传统51单片机的冯·诺依 曼结构(指令和数据共享总线),哈佛结构在高主频下的性能优势尤为明显。

1.2 三级流水线: 指令执行的"工厂流水线"

Cortex-M3内核采用三级流水线设计,将指令执行分为三个阶段并行处理:

1. 取指(Fetch从Flash或指令缓存读取指令,由预取单元(Prefetch Unit)完成,支持指令预取缓冲

2. 解码(Decode解析指令操作码和操作数,生成控制信号

3. 执行(Execute由ALU(算术逻辑单元)、乘法器等执行运算,访问寄存器或存储器

流水线工作时序

• 时钟周期1:指令1取指

• 时钟周期2:指令1解码,指令2取指

• 时钟周期3:指令1执行,指令2解码,指令3取指

这种并行处理使Cortex-M372MHz主频下可实现1.25 DMIPS/MHz的性能(约90 DMIPS )。

1.3 存储器系统: Flash RAM与地址映射

STM32F103C8T6的存储器资源如下:

Flash:64KB(地址范围:0x08000000~0x0800FFFF),用于存储程序代码和常量

SRAM:20KB(地址范围:0x20000000~0x20004FFF),用于存储变量和堆栈

存储器映射规则

Cortex-M3支持4GB地址空间,STM32将其划分为多个区域:

• 0x00000000~0x1FFFFFFF:代码区(Flash/系统存储器/SRAM,通过启动模式映射)

• 0x20000000~0x3FFFFFFF:SRAM区

• 0x40000000~0x5FFFFFFF:外设寄存器区(APB1/APB2/AHB外设)

• 0xE0000000~0xE00FFFFF: 内核外设区(NVIC、SysTick等)

1.4 总线架构:AHBAPB总线矩阵

STM32采用多级总线架构,通过总线矩阵( Bus Matrix )协调各主设备( CPU DMA)对从设备 Flash SRAM、外设)的访问:

 AHB总线(Advanced High-performance Bus最高72MHz,连接高性能外设(Flash、SRAM、 DMA、LCD控制器等)

 APB1总线:最高36MHz,连接低速外设(USART2/3、I2C、SPI2等)

 APB2总线:最高72MHz,连接高速外设(GPIO、USART1、SPI1、ADC等)

1.5 时钟系统: 从晶振到外设的" 时间管理者"

STM32的时钟系统是最复杂也最核心的部分之一,支持5种时钟源:

HSI:内部高速RC振荡器(8MHz,精度±1%)

HSE:外部高速晶振(4~16MHz,通常接8MHz)

LSI:内部低速RC振荡器(40kHz,用于独立看门狗)

LSE:外部低速晶振(32.768kHz,用于RTC)

PLL:锁相环倍频器(输入可接HSI/2、HSE或HSE/2,倍频2~16倍,最高输出72MHz)

典型时钟树配置HSE=8MHz ):

HSE → PLL输入(不分频) PLL倍频9  PLL输出72MHz → 作为SYSCLK(系统时钟)

• AHB分频1 → HCLK=72MHz(CPU主频)

• APB1分频2 → PCLK1=36MHz

• APB2分频1 → PCLK2=72MHz

二、 STM32F103C8T6启动流程详解

2.1 启动模式: BOOT引脚如何决定程序从哪里启动?

STM32的启动模式由BOOT0BOOT1引脚的电平决定,共三种模式:

BOOT1

BOOT0

启动模式

映射地址

用途

X

0

主Flash启动

0x08000000

正常运行用户程 序(默认模式)

0

1

系统存储器启动

0x1FFFF000

通过串口下载程 序(ISP模式)

1

1

SRAM启动

0x20000000

调试临时程序

(掉电不保存)

关键细节

• 复位时BOOT引脚电平被锁存,修改后需复位生效

• 主Flash启动时,0x00000000地址被映射到0x08000000(Flash首地址)

• 系统存储器启动时,执行ST出厂预置的Bootloader(支持USART1下载)

2.2 复位序列: 上电后CPU首先做什么?

STM32上电或复位( NRST引脚拉低)后,硬件自动执行以下步骤:

1. 初始化状态寄存器:清除中断标志,设置默认优先级

2. 读取向量表前两项

从0x00000000读取MSP初始值(栈顶指针)

从0x00000004读取复位向量(Reset_Handler函数地址)

3. 跳转执行Reset_Handler:CPU将PC指针设置为复位向量地址,开始执行启动代码

2.3 启动文件解析: startup_stm32f10x_md.s的秘密

启动文件(汇编编写)是连接硬件复位和C语言环境的桥梁,以  startup_stm32f10x_md .s 

(中等容量 设备)为例,主要完成以下工作:

2.3.1 堆栈定义

Stack_Size      EQU     0x00000400  ; 栈大小1KBAREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size  ; 分配栈空间
__initial_sp    ; 栈顶地址(栈从高地址向低地址生长)Heap_Size       EQU     0x00000200   ; 堆大小512BAREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base     ; 堆起始地址
Heap_Mem        SPACE   Heap_Size   ; 分配堆空间
__heap_limit    ; 堆结束地址

 

2.3.2 中断向量表

AREA    RESET, DATA, READONLYEXPORT  __VectorsEXPORT  __Vectors_EndEXPORT  __Vectors_Size__Vectors       DCD     __initial_sp               ; 0: 栈顶指针DCD     Reset_Handler              ; 1: 复位中断DCD     NMI_Handler                ; 2: NMI中断DCD     HardFault_Handler          ; 3: 硬件错误中断; ... 其他中断向量(共68个)
__Vectors_End__Vectors_Size  EQU     __Vectors_End - __Vectors  ; 向量表大小

2.3.3 复位处理函数( Reset_Handler

复位后执行的第一个函数,负责初始化硬件和C环境:

Reset_Handler   PROCEXPORT  Reset_Handler             [WEAK]IMPORT  SystemInit                ; 引入系统初始化函数IMPORT  __main                    ; 引入C库初始化函数; 1. 设置栈指针(已由硬件读取__initial_sp完成); 2. 初始化数据段(.data)ldr     r0, =_sdata               ; 数据段目标地址(RAM)ldr     r1, =_edata               ; 数据段结束地址ldr     r2, =_sidata              ; 数据段源地址(Flash)movs    r3, #0
LoopCopyDataInit:cmp     r0, r1                    ; 复制未完成?ittt    ltldrlt   r4, [r2], #4              ; 从Flash读取数据strlt   r4, [r0], #4              ; 写入RAMblt     LoopCopyDataInit          ; 循环复制; 3. 初始化BSS段(清零)ldr     r2, =_sbss                ; BSS段起始地址ldr     r4, =_ebss                ; BSS段结束地址movs    r3, #0
LoopFillZerobss:cmp     r2, r4                    ; 清零未完成?itt     ltstrlt   r3, [r2], #4              ; 写入0blt     LoopFillZerobss           ; 循环清零; 4. 调用SystemInit配置系统时钟bl      SystemInit; 5. 调用__main初始化C库,最终跳转到main函数bl      __mainENDP

关键步骤解析

数据段(.data)复制:将Flash中存储的已初始化全局变量复制到RAM

BSS段清零:将未初始化全局变量在RAM中清零

SystemInit:配置系统时钟(默认使用HSI,可修改为HSE+PLL=72MHz)

 __main:C库函数,初始化堆和栈,调用全局构造函数(C++),最终跳转到用户

2.4 SystemInit函数: 时钟配置的核心

SystemInit函数(位于system_stm32f10x.c)负责系统时钟初始化,默认配置如下:

void SystemInit(void) {/* 复位RCC寄存器到默认状态 */RCC->CR |= 0x00000001U;                  // 使能HSIRCC->CFGR &= 0xF8FF0000U;                // 复位时钟配置寄存器RCC->CR &= 0xFEF6FFFFU;                  // 关闭HSE、CSS、PLLRCC->CR &= 0xFFFBFFFFU;                  // 关闭HSE旁路RCC->CFGR &= 0xFF80FFFFU;                // 复位PLL配置/* 配置向量表偏移(默认在Flash) */
#ifdef VECT_TAB_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; // 向量表在SRAM
#elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;// 向量表在Flash(0x08000000)
#endif
}

默认时钟:HSI(8MHz)作为系统时钟,未启用PLL,如需72MHz需修改SetSysClock函数:

static void SetSysClockTo72(void) {RCC->CR |= RCC_CR_HSEON;                 // 使能HSEwhile((RCC->CR & RCC_CR_HSERDY) == 0);   // 等待HSE就绪RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;        // PLL输入=HSERCC->CFGR |= RCC_CFGR_PLLMULL9;          // PLL倍频9倍(8MHz*9=72MHz)RCC->CR |= RCC_CR_PLLON;                 // 使能PLLwhile((RCC->CR & RCC_CR_PLLRDY) == 0);   // 等待PLL就绪FLASH->ACR |= FLASH_ACR_PRFTBE;          // 使能Flash预取FLASH->ACR &= ~FLASH_ACR_LATENCY;FLASH->ACR |= FLASH_ACR_LATENCY_2;       // Flash等待周期=2(72MHz时)RCC->CFGR |= RCC_CFGR_SW_PLL;            // 系统时钟=PLL输出while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // 等待切换完成
}

三、代码示例与实战解析

3.1 启动流程验证: 通过LED观察启动阶段

硬件连接 LEDPC13(低电平点亮)

代码实现

// main.c
#include "stm32f10x.h"// 延时函数
void Delay(__IO uint32_t nCount) {while(nCount--) {}
}int main(void) {// 使能GPIOC时钟(APB2外设)RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;// 配置PC13为推挽输出GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);GPIOC->CRH |= GPIO_CRH_MODE13_0;  // 输出模式,最大速度10MHzwhile (1) {GPIOC->ODR ^= GPIO_ODR_ODR13;   // 翻转PC13电平Delay(0xFFFFF);                 // 延时}
}

启动阶段分析

1. 上电后LED不亮(系统初始化阶段)

2. SystemInit执行完毕后,LED开始闪烁(main函数执行)

3. 若LED不闪烁,可能是时钟配置错误或启动文件选择不当(需使用  startup_stm32f10x_md .s

3.2 中断向量表重映射: RAM启动时的配置

当使用SRAM启动或IAP升级时,需将向量表重映射到RAM

// 在SystemInit或main中配置
void VectorTableRemap(void) {// 将Flash中的向量表复制到RAM(0x20000000)uint32_t *pSrc = (uint32_t*)0x08000000;    // Flash向量表起始地址uint32_t *pDest = (uint32_t*)0x20000000;   // RAM向量表起始地址uint32_t i;for(i = 0; i < 68; i++) {                  // 复制68个中断向量pDest[i] = pSrc[i];}// 配置VTOR寄存器(向量表偏移)SCB->VTOR = 0x20000000;                    // 向量表基地址=RAM起始地址
}

3.3 启动时间优化: 72ms15ms的实战技巧

默认启动时间:约72ms(含Flash擦写、C库初始化等)

优化方法

1. 关闭不必要的外设时钟

在SystemInit中仅使能必要外设时钟(如GPIO、USART)

2. 优化Flash访问

使能预取缓冲区(FLASH_ACR_PRFTBE=1),设置正确等待周期(72MHz时=2)

3. 跳过C库初始化

若不使用全局构造函数,可在启动文件中直接跳转到main:

; 在Reset_Handler中替换bl __main为bl main
bl SystemInit
bl main        ; 直接调用main,跳过__libc_init_array

4. 使用HSI快速启动

若对时钟精度要求不高,使用HSI(8MHz)可避免HSE晶振启动延时

四、常见问题与调试技巧

4.1 启动失败排查清单

现象

可能原因

解决方案

程序无反应

BOOT0引脚接高电平(进入 ISP模式)

将BOOT0接地,复位芯片

HardFault异常

栈溢出或非法内存访问

增大栈大小(Stack_Size), 查指针操作

现象

可能原因

解决方案

时钟配置后死机

PLL倍频过高(超过72MHz)

重新计算PLL参数,确保输出 ≤72MHz

全局变量初始化失败

.data或.bss段地址配置错误

检查链接脚本( .ld)中的RAM 地址和大小

4.2 使用ST-Link调试启动过程

1. 查看寄存器状态

复位后暂停,查看  SP 是否等于 ___initial_sp,  PC 是否指向  Reset_Handler 

2. 设置断点

在  Reset_Handler SystemInitmain 函数设置断点,观察执行流程

3. 查看内存

检查  0x20000000(RAM起始地址)是否已复制.data段数据,.bss段是否清零

总结与扩展

本文详细解析了STM32F103C8T6的内部执行原理(哈佛架构、三级流水线、存储器映射、时钟系统)和启动流程(复位序列、启动模式、启动文件、SystemInit),并通过代码示例展示了实战应用。掌握这些知识后,你可以:

  1. 开发自定义Bootloader,实现IAP固件升级
  2. 优化系统启动速度,满足实时性要求
  3. 快速定位HardFault等底层异常

推荐扩展阅读:

  1. 《STM32F103参考手册(RM0008)》:深入了解寄存器配置
  2. 《Cortex-M3权威指南》:理解内核架构和异常处理
  3. STM32CubeMX:图形化配置时钟和外设,自动生成初始化代码

如果觉得本文对你有帮助,欢迎点赞+关注,后续将带来更多STM32底层开发实战内容!如有疑问,可在评论区留言讨论~ 

附录:关键地址速查表

名称

地址范围

用途

Flash

0x08000000~0x0800FFFF

程序代码存储

SRAM

0x20000000~0x20004FFF

变量和堆栈

向量表(默认)

0x08000000~0x08000107

中断服务函数地址数组

RCC寄存器

0x40021000~0x400213FF

时钟控制寄存器

GPIO寄存器

           0x40010800~0x40010BFF (GPIOC)

GPIO控制寄存器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88401.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88401.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【python 常用的数学科学/计算机视觉等工具】

当然有&#xff01;在科学计算、机器学习、图像处理等领域&#xff0c;scikit-learn、scikit-image&#xff08;skimage&#xff09;、SciPy、OpenCV 是非常重要的库&#xff0c;但它们不是唯一的。以下是一些与它们类似或互补的项目&#xff0c;按照用途分类列出&#xff1a; …

LUMP+NFS架构的Discuz论坛部署

一、配置准备 每台主机都安装mysql、nfs、php、mysql 对每台主机都进行关闭防火墙、上下文等&#xff0c;减少阻碍[rooteveryone ~]# systemctl stop firewalld [rooteveryone ~]# setenforce 0安装插件等[rootlocalhost mysql]# yum install -y nfs-utils nginx [rootlocalho…

C++STL-deque

一.基础概念deque和vector一样都是对元素的操作&#xff0c;不同点&#xff1a;vector对元素增删后元素会往前或往后移&#xff0c;如果数据不大没有太多影响&#xff0c;如果数据很大效率会变低&#xff1b;deque对元素增删不会使元素位置改变&#xff0c;所有效率会变高。二.…

字节跳动高质量声音克龙文字转语音合成软件MegaTTS3整合包

MegaTTS3是抖音团队联合国内其他大学研发的一款语音合成及声音克龙应用&#xff0c;可实现零样本语音克龙及富有情感的自然语音合成。我基于当前最新版制作了免安装一键启动整合包。 MegaTTS3介绍 MegaTTS 3 是字节跳动&#xff08;ByteDance&#xff09;与浙江大学联合开发的…

RPC:远程过程调用机制

目录 1、概念 2、RPC架构 2.1 RPC的四个核心组件 2.2 访问流程 3、关键概念 3.1 接口定义语言 (IDL - Interface Definition Language) 3.2 序列化与反序列化 (Serialization & Deserialization - Marshalling/Unmarshalling) 3.3 网络传输 (Transport) 3.4 服务发…

EPLAN 电气制图(六):电机正反转副勾主电路绘制

一、项目背景&#xff1a;为什么绘制电机正反转主电路&#xff1f; 在多功能天车系统中&#xff0c;电机正反转控制是核心功能之一。通过 EPLAN 绘制主电路&#xff0c;不仅能清晰展示电源分配、换相逻辑和线缆连接&#xff0c;还能为后续 PLC 控制设计奠定基础。本次以西门子设…

JAVA JVM对象的实现

jvm分配内存给对象的方式1. 内存分配的总体流程对象内存分配的主要步骤&#xff1a;类加载检查&#xff1a;确认类已加载、解析和初始化。内存分配&#xff1a;根据对象大小&#xff0c;从堆中划分内存空间。内存初始化&#xff1a;将分配的内存空间初始化为零值&#xff08;不…

CVE-2023-41990/CVE-2023-32434/CVE-2023-38606/CVE-2023-32435

CVE-2023-41990&#xff08;GitLab 命令注入漏洞&#xff09;漏洞原理CVE-2023-41990是GitLab CE/EE&#xff08;社区版/企业版&#xff09;中项目导出功能的一个命令注入漏洞。具体原理如下&#xff1a;①GitLab在导出项目时&#xff0c;会调用git命令生成项目存档&#xff08…

RAG实战指南 Day 8:PDF、Word和HTML文档解析实战

【RAG实战指南 Day 8】PDF、Word和HTML文档解析实战 开篇 欢迎来到"RAG实战指南"系列的第8天&#xff01;今天我们将深入探讨PDF、Word和HTML文档解析技术&#xff0c;这是构建企业级RAG系统的关键基础。在实际业务场景中&#xff0c;80%以上的知识都以这些文档格式…

【AXI】读重排序深度

我们以DDR4存储控制器为例&#xff0c;设计一个读重排序深度为3的具体场景&#xff0c;展示从设备如何利用3级队列优化访问效率&#xff1a;基础设定从设备类型&#xff1a;DDR4存储控制器&#xff08;支持4个存储体Bank0-Bank3&#xff09;读重排序深度&#xff1a;3&#xff…

牛马逃离北京(回归草原计划)

丰宁坝上草原自驾游攻略&#xff08;半虎线深度版&#xff09; &#x1f697; 路线&#xff1a;北京/承德 → 丰宁县城 → 半虎线 → 大滩镇&#xff08;2天1夜&#xff09; &#x1f3af; 核心玩法&#xff1a;免费草原、高山牧场、日落晚霞、牧群互动、星空烟花&#x1f33f;…

【前端】【Echarts】ECharts 词云图(WordCloud)教学详解

效果ECharts 词云图&#xff08;WordCloud&#xff09;教学详解 词云图是一种通过关键词的大小、颜色等视觉差异来展示文本数据中词频或权重的图表。它直观、形象&#xff0c;是数据分析和内容展示中的利器。 本文将带你从零开始&#xff0c;学习如何用 ECharts 的 WordCloud 插…

【arXiv 2025】新颖方法:基于快速傅里叶变换的高效自注意力,即插即用!

一、整体介绍 The FFT Strikes Again: An Efficient Alternative to Self-AttentionFFT再次出击&#xff1a;一种高效的自注意力替代方案图1&#xff1a;FFTNet整体流程&#xff0c;包括局部窗口处理&#xff08;STFT或小波变换&#xff0c;可选&#xff09;和全局FFT&#xff…

通过vue如何利用 Three 绘制 简单3D模型(源码案例)

目录 Three 介绍 创建基础3D场景 创建不同类型的3D模型 1. 球体 2. 圆柱体​​​​​​​ 3. 平面​​​​​​​ 加载外部3D模型 添加交互控制 创建可交互的3D场景 Three 介绍 Three.js是一个强大的JavaScript 3D库&#xff0c;可以轻松地在网页中创建3D图形。下面我…

云蝠智能 Voice Agent 落地展会邀约场景:重构会展行业的智能交互范式

一、行业痛点与 AI 破局在会展行业数字化转型的浪潮中&#xff0c;传统展会邀约模式面临多重挑战&#xff1a;人工外呼日均仅能处理 300-500 通电话&#xff0c;且无效号码占比高达 40% 以上&#xff0c;导致邀约效率低下。同时&#xff0c;个性化邀约话术设计依赖经验&#xf…

idea如何打开extract surround

在 IntelliJ IDEA 中&#xff0c;"Extract Surrounding"&#xff08;提取周围代码&#xff09;通常指 ​将一段代码提取到新的方法、变量或类中&#xff0c;但更常见的操作是 ​​"Surround With"&#xff08;用代码结构包围&#xff09;​。以下是两种场景…

window显示驱动开发—XR_BIAS 和 BltDXGI

Direct3D 运行时调用驱动程序的 BltDXGI 函数&#xff0c;以仅对XR_BIAS源资源执行以下操作&#xff1a;复制到也XR_BIAS的目标未修改的源数据的副本可接受点样本的拉伸旋转由于 XR_BIAS 不支持 MSAA) (多个示例抗锯齿&#xff0c;因此驱动程序不需要解析XR_BIAS资源。核心规则…

web网页开发,在线%ctf管理%系统,基于html,css,webform,asp.net mvc, sqlserver, mysql

webform,asp.net mvc。数据库支持mysql,sqlserver经验心得 每次我们写crud没啥技术含量&#xff0c;这没法让咱们进入大厂&#xff0c;刚好这次与客户沟通优化方案建议&#xff0c;咱们就把能加的帮他都加上去。一个ctf管理系统基本crud&#xff0c;并进行不同分层开发&#xf…

面试技术问题总结一

MySQL的几种锁机制一、从锁的粒度角度划分表级锁机制&#xff1a;它是对整张表进行锁定的一种锁。当一个事务对表执行写操作时&#xff0c;会获取写锁&#xff0c;在写锁持有期间&#xff0c;其他事务无法对该表进行读写操作&#xff1b;而当事务执行读操作时&#xff0c;会获取…

π0.5的KI改进版——知识隔离:让VLM在不受动作专家负反馈的同时,继续输出离散动作token,并根据反馈做微调(而非冻结VLM)

前言 过去的一个月(25年6.4-7.4)&#xff0c;我司「七月在线」具身长沙分部为冲刺一些为客户来现场看的演示项目&#xff0c;基本都用lerobot的那套框架 比如上周五(7.4日)晚上&#xff0c;通过上周五下午新采的第五波数据做『耳机线插入耳机孔』的任务&#xff0c;推理十次之…