简介:本资源是面向嵌入式初学者与STM32开发入门者的标准库工程搭建实践包,聚焦STM32F103系列基于ARM Cortex-M3内核的单片机开发起点——Keil MDK环境下标准外设库(StdPeriph Library)工程的完整初始化配置。资源解决新手在创建可编译、可调试基础工程时常见的芯片选型错误、CMSIS与FWLIB路径配置混乱、启动文件匹配失当及目录结构不合理等典型问题。压缩包含160个文件,总计5.32MB,涵盖26个.c源文件(如stm32f10x_rcc.c、stm32f10x_usart.c等标准外设驱动)、27个.h头文件、28个.o编译目标及关键工程配置文件(uvprojx、sct、axf、map等),清晰呈现“User”与“Project”分层结构,便于理解代码组织逻辑与构建流程。已有2342人学习下载,提供开箱即用的可运行模板,包含system_stm32f10x.c系统初始化、中断向量表、Flash/RAM配置及典型外设驱动骨架,显著降低从零建工程的学习门槛。
1. 项目概述:为什么从“新建工程”开始
如果你刚拿到一块STM32F103的开发板,看着满屏的代码示例和教程,可能会觉得无从下手。很多教程一上来就讲GPIO点灯、讲串口通信,却忽略了一个最基础、也最容易出问题的环节——如何从零开始,正确地搭建一个属于自己的工程框架。我见过太多新手,包括当年的我自己,直接从网上下载一个现成的工程模板,编译通过就以为万事大吉,结果在添加新功能、移植代码时遇到各种诡异的编译错误和链接问题,最后不得不推倒重来。所以,今天我们不谈高深的应用,就扎扎实实地聊透“STM32F103标准库开发-新建工程”这件事。这不仅是写代码的第一步,更是为你后续所有开发工作打下坚实、可靠地基的关键一步。
所谓“新建工程”,远不止是在Keil或者IAR里点几下鼠标创建一个新项目那么简单。它涉及到开发环境的配置、标准库文件的组织、编译链接选项的设置,以及一个清晰、可维护的目录结构规划。对于STM32F103这款经典的Cortex-M3内核MCU,使用标准外设库(Standard Peripheral Library)进行开发,依然是许多项目,特别是对代码体积和运行效率有严格要求,或者需要维护历史代码的项目所采用的主流方式。尽管ST官方主推HAL/LL库,但标准库的直白、高效和对硬件底层的直接控制,使其在工程师群体中保有旺盛的生命力。一个构建良好的标准库工程,应该像一座结构清晰的房子,核心库文件、用户应用代码、启动文件、链接脚本等各居其位,互不干扰,并且易于扩展和复用。接下来,我就带你亲手搭建这座“房子”,并解释清楚每一个房间(目录)和梁柱(配置文件)的作用。
2. 工程整体设计与思路拆解
2.1 核心需求解析:我们需要一个怎样的工程?
在动手创建文件夹和文件之前,我们必须先想清楚目标。一个理想的标准库工程模板,应该满足以下几个核心需求:
- 环境隔离性:工程本身应该尽可能独立于特定的IDE(如Keil MDK、IAR EWARM)或安装路径。这意味着,工程中引用的头文件路径、库文件路径最好是相对路径,这样当我把整个工程文件夹拷贝到另一台电脑,或者分享给同事时,只需要重新配置一下IDE的器件型号和编译器版本,就能立即编译通过,而不需要手动修改一大堆绝对路径。
- 结构清晰性:代码和文件必须分门别类地存放。标准库的文件有成百上千个,我们不可能也不应该把它们和我们的应用代码混在一起。清晰的目录结构能让开发者快速定位文件,也便于团队协作和版本管理(如使用Git)。
- 可配置与可移植性:工程应该能方便地适配不同型号的STM32F103芯片(比如F103C8T6和F103ZET6),它们的内存大小、外设数量可能不同。同时,对于调试配置(如使用JTAG还是SWD)、优化等级等,也应该有统一的入口进行修改。
- 编译可靠性:必须正确配置预处理宏、头文件包含路径、链接脚本等,确保编译出来的代码能正确地在芯片上启动和运行,没有未定义的符号或内存区域冲突。
基于这些需求,我们的工程结构设计思路就明确了:采用分层与模块化的思想,将“芯片厂商提供的标准库”、“工程启动与系统文件”、“用户编写的应用程序”三者严格分离。
2.2 方案选型:为什么是标准库?文件从哪来?
首先回答一个前置问题:为什么选择标准库而非HAL库?对于STM32F103这类经典型号,标准库具有显著优势。它更贴近寄存器,代码效率高,生成的二进制文件体积小,对芯片资源的消耗低。其API风格直接,对于理解STM32外设的工作原理非常有帮助。而HAL库虽然抽象程度高、可移植性好,但有时显得臃肿,且对硬件异常的封装可能掩盖一些底层细节。在资源受限的F103上,标准库往往是更务实的选择。当然,如果项目未来需要迁移到STM32更现代的系列,HAL库的统一性优势会凸显,这就需要根据项目规划来权衡。
接下来是文件来源。你需要准备以下核心材料,它们通常可以从官方渠道获取:
- STM32F10x标准外设库:版本建议使用V3.5.0,这是最稳定、最经典的版本。你可以在ST官网搜索“STM32F10x Standard Peripheral Library”下载,或者从许多开发板配套资料中找到。
- CMSIS:Cortex Microcontroller Software Interface Standard,这是ARM公司为Cortex-M系列内核定义的软件接口标准。它包含了内核寄存器定义、系统初始化代码等。幸运的是,标准外设库的
Libraries\CMSIS目录下已经包含了针对STM32F10x系列的CMSIS文件,我们直接使用即可。 - 启动文件:这是芯片上电后运行的第一段汇编代码,负责设置堆栈指针、初始化.data段(已初始化全局变量)、.bss段(未初始化全局变量),最后跳转到C语言的
main函数。对于STM32F103,启动文件根据芯片Flash大小有所不同,例如startup_stm32f10x_hd.s(大容量)、startup_stm32f10x_md.s(中容量)、startup_stm32f10x_ld.s(小容量)等。这些文件也在标准外设库的Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm目录下。 - 链接脚本:告诉链接器如何将编译生成的代码(.o文件)分配到芯片的Flash和SRAM中。在Keil MDK中,链接脚本通常以
.sct文件形式存在,且IDE会根据你选择的芯片型号自动生成一个默认的。但理解其原理对于解决内存不足、变量定位等问题至关重要。
3. 工程目录结构创建与文件归位
理论说再多,不如动手做。让我们开始创建工程目录。我强烈建议你完全按照下面的结构来,这是经过多个项目检验的最佳实践。
假设我们的工程根目录名为Project_STM32F103,在其内部创建如下子目录:
Project_STM32F103/ ├── Docs/ # 存放项目文档、芯片手册、原理图等 ├── Libraries/ # 存放所有第三方库文件 │ ├── CMSIS/ # 核心:CMSIS文件 │ │ ├── CoreSupport/ # ARM CMSIS核心文件 (如 core_cm3.h, core_cm3.c) │ │ └── DeviceSupport/ST/STM32F10x/ # STM32F10x专用CMSIS文件 │ └── STM32F10x_StdPeriph_Driver/ # 核心:标准外设库驱动源码 │ ├── inc/ # 外设驱动头文件 (.h) │ └── src/ # 外设驱动源文件 (.c) ├── User/ # 用户应用程序代码 │ ├── main.c # 主函数文件 │ ├── stm32f10x_conf.h # 标准库配置文件(关键!) │ ├── stm32f10x_it.h # 中断服务函数头文件 │ ├── stm32f10x_it.c # 中断服务函数源文件 │ └── system_stm32f10x.c # 系统时钟初始化函数文件(来自CMSIS) ├── Project/ # IDE工程文件存放目录(如Keil的.uvprojx) │ └── (Keil project files, .uvprojx, .uvoptx等) ├── Output/ # 编译输出文件(.axf, .hex, .bin, .map等),临时文件不提交版本管理 └── Listings/ # 编译器生成的列表文件(可选)操作与解释:
- 创建
Libraries目录,并将从标准外设库包中解压出的Libraries文件夹下的CMSIS和STM32F10x_StdPeriph_Driver两个文件夹,完整拷贝到我们工程的Libraries目录下。这样就完成了库文件的“安家”。 - 创建
User目录,这是我们工作的主战场。你需要手动创建或从库包示例中拷贝以下文件:main.c: 一个空的main函数框架。stm32f10x_conf.h: 这是工程的“配置中枢”。它通过#define或#undef来决定编译时包含哪些外设驱动。例如,如果你只用到了GPIO和USART,那么就在这里#define USE_STDPERIPH_DRIVER并#include "stm32f10x_gpio.h"和#include "stm32f10x_usart.h",同时注释掉其他不用的外设头文件包含。这能显著加快编译速度并减少代码体积。stm32f10x_it.h/c: 集中管理所有中断服务程序(ISR)的声明和定义。保持中断处理的模块化。system_stm32f10x.c: 从标准库的CMSIS\DeviceSupport\ST\STM32F10x\目录下拷贝过来。它包含了SystemInit()函数,负责初始化系统时钟(HSE、HSI、PLL等),这个函数会在启动文件中被调用,早于main函数执行。
Project目录专门存放Keil的工程文件(.uvprojx等),这样工程文件就和源代码物理分离,管理起来更清爽。Output和Listings目录用于存放编译生成物,建议在版本控制(如.gitignore)中忽略它们。
注意:这种将库文件完整纳入工程目录的做法,保证了工程的完全自包含。无论ST官网的库文件未来是否更新、下载链接是否失效,你的这个工程永远都能独立编译。这是工程可移植性的基石。
4. 在Keil MDK中构建工程
现在,我们进入IDE实操环节。以Keil MDK-ARM(V5版本为例)进行说明。
4.1 创建新工程与选择器件
- 打开Keil,点击
Project -> New uVision Project...。 - 浏览到我们刚才创建的
Project/目录下,为工程命名(例如STM32F103_StdPeriph),点击保存。 - 在弹出的器件选择窗口中,搜索并选择你使用的具体型号。例如,对于最常见的STM32F103C8T6,你可以选择
STMicroelectronics -> STM32F103 Series -> STM32F103C8。务必准确选择,这决定了Keil为你匹配的启动文件、链接脚本和调试配置。 - 点击“OK”后,会弹出一个“Manage Run-Time Environment”对话框。对于标准库开发,我们不需要通过这个RTE来添加软件包,直接点击‘Cancel’取消即可。所有文件我们将手动添加。
4.2 手动添加文件组与源文件
Keil工程通过“文件组”(Group)来组织源文件。我们按照目录结构来创建对应的组。
- 在Keil的“Project”侧边栏,右键点击
Target 1,选择Manage Project Items...。 - 在
Project Items标签页,我们可以创建组和添加文件。- 首先,修改
Target名称为更有意义的,比如STM32F103C8T6。 - 在
Groups区域,点击新建按钮(或按Insert),创建以下组:Startup:存放启动文件。CMSIS:存放CMSIS核心文件。StdPeriph_Driver:存放标准外设驱动源文件。User:存放用户应用代码。Doc:可存放README等(非必须)。
- 首先,修改
- 为每个组添加文件:
Startup组:点击该组,然后点击右侧Add Files,导航到Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm,根据你的芯片Flash容量选择正确的启动文件。对于STM32F103C8T6(64KB Flash),属于“中容量”,选择startup_stm32f10x_md.s。文件类型筛选要选择All Files (*.*)才能看到.s文件。CMSIS组:添加以下两个核心文件(路径相对于工程):../Libraries/CMSIS/CM3/CoreSupport/core_cm3.c../User/system_stm32f10x.c(注意,这个文件我们放在了User目录)
StdPeriph_Driver组:这里我们不一次性添加所有.c文件,那样编译慢且臃肿。只添加你计划使用的外设驱动源文件。例如,初期可以只添加:../Libraries/STM32F10x_StdPeriph_Driver/src/misc.c(系统异常和NVIC相关函数)../Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c../Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_rcc.c(时钟控制,几乎必用) 后续需要USART、SPI、TIM等外设时,再来这里添加对应的.c文件。
User组:添加../User/main.c和../User/stm32f10x_it.c。
4.3 配置头文件包含路径与全局宏
这是最关键的一步,配置错误会导致编译时找不到头文件。
- 点击工具栏的魔术棒图标(Options for Target),打开配置对话框。
- 选择
C/C++标签页。Define::在这里输入全局的预处理器宏。对于STM32F10x标准库,至少需要:USE_STDPERIPH_DRIVER, STM32F10X_MDUSE_STDPERIPH_DRIVER:这个宏告诉编译器,我们要使用标准外设库。如果没有定义,stm32f10x.h这个主头文件就不会去包含stm32f10x_conf.h,从而导致所有外设驱动API无法使用。STM32F10X_MD:这个宏定义了芯片的密度(Density)。MD代表中容量(Medium Density)。对于C8T6,就是MD。如果是F103RCT6(256KB Flash,大容量),则需要定义为STM32F10X_HD。这个宏决定了芯片内部一些内存映射和寄存器定义。
Include Paths::点击末尾的...按钮,添加编译器需要搜索头文件的目录。必须添加以下路径(使用相对路径,以工程文件.uvprojx所在目录为基准):../Libraries/CMSIS/CM3/CoreSupport../Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x../Libraries/STM32F10x_StdPeriph_Driver/inc../User添加后,编译器就能在这些目录下找到core_cm3.h,stm32f10x.h,stm32f10x_xxx.h以及我们自己的stm32f10x_conf.h等头文件了。
4.4 配置调试与下载工具
在Debug标签页,选择你使用的调试器,例如 ST-Link。然后点击Settings。
- 在
Debug选项卡,确认Port设置为SW(如果你使用SWD接口,这是最常用的)。 - 在
Flash Download选项卡,点击Add,为你的STM32F10x系列芯片选择正确的Flash编程算法。对于STM32F103C8T6,选择STM32F10x Medium-density Flash。务必勾选Reset and Run,这样程序下载后会自动复位运行,无需手动复位。
4.5 配置输出文件
在Output标签页,点击Select Folder for Objects...,将输出目录指定到我们之前创建的../Output文件夹。这样所有的.o,.axf,.hex等文件都会生成在那里,工程目录保持整洁。同时,可以勾选Create HEX File,生成用于烧录的HEX文件。
在Listing标签页,同样将列表文件输出目录指定到../Listings。
完成以上所有步骤后,点击“OK”保存配置。一个基于标准库的STM32F103工程骨架就搭建完毕了。
5. 编写基础用户代码与验证
工程创建好了,我们需要写一点最简单的代码来验证它是否能正常工作。通常,我们使用点亮一个LED作为“Hello World”。
5.1 配置 stm32f10x_conf.h
打开User/stm32f10x_conf.h文件。这个文件通常包含了很多被注释掉的外设头文件包含。我们根据当前需要(点灯需要GPIO和RCC)进行配置:
/* 取消以下注释以使用对应外设驱动 */ #define _GPIO #define _RCC /* 包含你使用的外设头文件 */ #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" /* 其他不用的外设头文件保持注释状态 */ // #include "stm32f10x_adc.h" // #include "stm32f10x_can.h" // ... 等等实际上,更常见的做法是直接利用文件开头已有的#ifdef USE_STDPERIPH_DRIVER部分,取消对你所需外设头文件的注释。确保#include "stm32f10x_gpio.h"和#include "stm32f10x_rcc.h"这两行是有效的。
5.2 编写 main.c
打开User/main.c,编写一个简单的LED闪烁程序。假设LED连接在PC13(像Blue Pill开发板那样)。
#include "stm32f10x.h" // 这个头文件会自动包含 stm32f10x_conf.h void LED_GPIO_Config(void); int main(void) { // 系统时钟初始化已在启动阶段由 SystemInit() 完成,默认使用内部HSI 8MHz // 如果需要更高的系统时钟(如72MHz),需要在此之后重新配置RCC LED_GPIO_Config(); // 初始化GPIO while (1) { GPIO_SetBits(GPIOC, GPIO_Pin_13); // 置高,LED灭(假设低电平点亮) Delay_ms(500); // 简单延时函数,见下文说明 GPIO_ResetBits(GPIOC, GPIO_Pin_13); // 置低,LED亮 Delay_ms(500); } } void LED_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 定义GPIO初始化结构体 /* 开启GPIOC的时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); /* 配置PC13为推挽输出,最大速度50MHz */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度 GPIO_Init(GPIOC, &GPIO_InitStructure); /* 初始状态:LED灭(输出高电平) */ GPIO_SetBits(GPIOC, GPIO_Pin_13); } // 一个简单的毫秒级延时函数(基于SysTick实现更精准,此处为示例用循环延时) void Delay_ms(uint32_t nTime) { for(; nTime > 0; nTime--) for(uint32_t i = 0; i < 8000; i++); // 此循环次数需根据实际主频调整 }5.3 编译与下载
- 点击Keil的
Rebuild(F7)按钮编译整个工程。如果之前所有路径和配置都正确,你应该能看到0 Error(s), 0 Warning(s)的输出。 - 将开发板通过ST-Link(或其它调试器)连接电脑,并确保供电正常。
- 点击
Load(F8)按钮下载程序到芯片。如果配置了Reset and Run,下载完成后LED应该开始闪烁。
至此,你已经成功地从零创建、配置并验证了一个STM32F103标准库工程。这个工程框架是干净、标准且可扩展的。
6. 常见问题与排查技巧实录
即使按照步骤操作,新手也常会遇到一些问题。这里我总结几个高频问题及其解决方法。
6.1 编译错误:stm32f10x.h: error: #5: cannot open source input file...
- 问题现象:编译时提示找不到
stm32f10x.h或其他头文件。 - 排查思路:这是头文件包含路径(Include Paths)没有配置正确。
- 解决步骤:
- 双击Keil错误输出窗口的该错误信息,Keil会尝试定位到出错行(通常是
#include "stm32f10x.h")。 - 右键点击
main.c中的#include "stm32f10x.h",选择Open document “stm32f10x.h”。如果打不开,说明路径确实不对。 - 检查魔术棒
Options for Target -> C/C++ -> Include Paths。确保路径添加正确,并且是相对路径。一个常见的错误是路径层级不对,比如工程文件在Project/子目录,而添加的路径却是./Libraries/...,应该使用../Libraries/...。 - 检查路径中是否存在中文或特殊字符,最好使用全英文路径。
- 双击Keil错误输出窗口的该错误信息,Keil会尝试定位到出错行(通常是
6.2 链接错误:undefined symbol SystemInit (referred from startup_stm32f10x_md.o)
- 问题现象:链接阶段报错,提示
SystemInit函数未定义。 - 排查思路:启动文件
startup_*.s会调用一个名为SystemInit的C函数。如果这个函数没有被找到,就会报错。 - 解决步骤:
- 确认
User组下是否添加了system_stm32f10x.c文件。 - 打开
system_stm32f10x.c,查看里面是否有SystemInit函数的定义。标准库中该函数是弱定义(__weak)的,并且默认将系统时钟配置为使用内部HSI(8MHz)。如果你需要更高主频(如72MHz),需要在自己的代码(比如main.c开头)里重写这个函数,或者在其后调用RCC_Configuration()来重新配置时钟。 - 确保没有在其他地方错误地定义了同名的
SystemInit函数。
- 确认
6.3 程序下载后不运行,或运行异常
- 问题现象:程序编译下载成功,但LED不闪,或者行为异常。
- 排查思路:这通常是硬件连接、时钟配置或GPIO初始化问题。
- 解决步骤:
- 硬件检查:确认LED电路连接正确(PC13到LED阳极,LED阴极串电阻到地)。用万用表测量PC13引脚在程序运行时的电压是否在高/低电平间跳变。
- 时钟检查:我们的
main.c中直接使用了默认的HSI 8MHz时钟。如果你的延时循环Delay_ms是基于这个频率计算的,但实际系统时钟被错误地配置成了其他频率(比如你在别的地方改动了时钟),延时时间就会不准。可以在SystemInit函数末尾或main函数开头,添加代码将系统时钟切换到HSE并倍频至72MHz,这是F103的典型高速配置。注意:修改时钟后,Delay_ms函数中的循环次数需要重新校准。 - GPIO模式检查:确认
GPIO_InitStructure.GPIO_Mode设置正确。推挽输出(GPIO_Mode_Out_PP)是最常用的驱动LED的模式。 - 启动文件选择:再次确认启动文件是否与芯片容量匹配。给C8T6(中容量)用了
startup_stm32f10x_hd.s(大容量)一般也能运行,但反之则可能因栈空间设置不当而出问题。
6.4 如何添加新的外设驱动(如USART)
当你需要添加串口功能时,遵循以下步骤,这是工程扩展的标准流程:
- 修改配置文件:在
stm32f10x_conf.h中,取消对#include "stm32f10x_usart.h"的注释。 - 添加驱动源文件:在Keil工程中,右键
StdPeriph_Driver组,选择Add Existing Files to Group...,导航并添加../Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_usart.c。 - 编写应用代码:在
main.c或单独的模块文件中,编写USART的初始化函数(配置波特率、数据位、停止位等)和收发函数。 - 编译:点击Rebuild。如果之前路径和宏定义正确,应该能顺利编译。
这个过程体现了我们工程结构的优势:添加新外设,只需要在配置文件中声明,在工程组中添加对应的.c文件,然后编写应用层代码即可,干净利落。
7. 工程优化与进阶管理
一个基础的工程搭建完成后,还可以从以下几个方面进行优化,使其更专业、更高效。
7.1 使用SystemTick实现精准延时
上面示例中的Delay_ms函数是低效的循环阻塞延时,会浪费CPU资源。更专业的做法是使用Cortex-M内核的SysTick定时器。
- 在
stm32f10x_conf.h中确保#include "misc.h"被包含(因为SysTick函数在misc.c中)。 - 在
main.c中初始化SysTick,并实现一个基于中断的延时函数。通常,我们会配置SysTick每1ms中断一次,用一个全局变量uwTick累加。然后提供HAL_Delay()(类似HAL库)或自定义的Delay_ms()函数,该函数通过比较当前uwTick和目标 tick 值来实现非阻塞延时。这需要编写SysTick中断服务函数,并将其添加到stm32f10x_it.c中。
7.2 创建模块化的用户代码
不要把所有代码都堆在main.c里。在User目录下,可以创建子文件夹,例如BSP(板级支持包,放LED、按键、蜂鸣器等驱动)、Drivers(放传感器、屏幕等外部器件驱动)、App(放业务逻辑)、Utils(放工具函数)。然后在Keil工程中创建对应的文件组,将源文件添加进去。这样结构清晰,便于协作和维护。
7.3 版本控制集成
使用Git进行版本控制时,一个良好的.gitignore文件至关重要。它应该忽略所有编译生成文件和IDE临时文件,例如:
# Keil MDK Project/*.uvguix.* Project/*.uvoptx Project/*.uvprojx.user Output/ Listings/ *.crf *.d *.o *.axf *.hex *.bin *.map *.lst *.dep *.lnp *.tmp *.bak *.build_log.htm # IAR EWARM Debug/ Release/ *.eww *.ewp *.ewd *.dep *.log这样,你提交到仓库的只有纯净的源代码、库文件和工程配置文件,体积小且干净。
7.4 切换为更高效的编译优化
在项目开发后期,为了减小代码体积和提高运行速度,可以调整编译优化选项。在Options for Target -> C/C++中,将Optimization等级从默认的Level 0调整为Level 2 (-O2)或Level 3 (-O3)。注意:提高优化等级可能会暴露一些在低优化等级下隐藏的代码逻辑问题(比如未初始化的变量、 volatile 关键字使用不当),调试时如果遇到奇怪的问题,可以暂时调回Level 0进行排查。
从新建一个空文件夹开始,到构建出一个可以稳定运行、易于扩展的STM32F103标准库工程,整个过程就像搭积木,每一步都有其明确的目的。我强烈建议你不要满足于使用网上下载的“模板工程”,而是亲手走一遍这个流程。过程中遇到的每一个错误和解决它的过程,都会加深你对编译链、工程组织、芯片启动流程的理解。这个自己搭建的工程,将成为你日后所有STM32F103项目最可靠的起点。当你下次拿到一块新的F103开发板,或者需要为一个新项目搭建框架时,你完全可以自信地在10分钟内就搭建好一个干净、专业的工程环境,然后把精力集中在真正的应用开发上。
本文还有配套的精品资源,点击获取