
STM32F103的开发板到手了接下来该怎么走板子刚拿到手的那一刻心情大概都是一样的——包装拆开一块蓝色的PCB躺在防静电袋里USB线、杜邦线、可能还有几个传感器模块散在旁边然后就是一阵短暂的茫然接下来该干嘛我当年第一次拿到STM32F103C8T6最小系统板的时候盯着上面那颗LQFP48封装的芯片看了半天心里想的全是“这玩意儿怎么连个屏幕都没有代码写进去我怎么知道它在跑”。如果你现在正处于这个阶段那这篇内容就是写给你的。我会把从零开始折腾STM32F103的完整路径拆开讲清楚包括工具链怎么选、第一个工程怎么建、点灯之后该练什么、哪些坑几乎每个人都会踩一遍。不管你是电子专业的学生、想转嵌入式的软件工程师还是纯粹想用单片机做点小玩意儿的爱好者下面这些内容都能直接拿去用。1. 先搞清楚你手里这块板子到底有什么1.1 F103系列芯片的定位与常见型号差异STM32F103属于意法半导体ST的ARM Cortex-M3内核微控制器主频最高72MHz这个系列在嵌入式圈子里被用得极广原因很简单性能够用、外设丰富、资料多、价格便宜。但“STM32F103”这个说法其实涵盖了一大票型号不同型号之间的差异比你想象的大。最常见的几种封装和型号型号封装FlashRAM典型开发板STM32F103C8T6LQFP4864KB20KB蓝色最小系统板俗称“蓝板”STM32F103RCT6LQFP64256KB48KB正点原子Mini板等STM32F103ZET6LQFP144512KB64KB正点原子战舰板、野火指南者等STM32F103VET6LQFP100512KB64KB一些工业评估板你买到的开发板如果是那种十几块钱的蓝色小板大概率是C8T6。这块板子的特点是引脚全部引出、带一个8MHz晶振和一个32.768kHz晶振、有复位按键和BOOT跳线、板载一个Micro USB口只供电不带USB转串口芯片。注意最后这一点很多新手拿到蓝板后插上USB发现电脑没反应以为板子坏了其实它只是取了5V供电数据线根本没连到芯片的USB引脚上。如果你买的是正点原子、野火、普中这类品牌的开发板通常会板载USB转串口芯片CH340或CP2102、多个按键、LED、OLED接口、传感器接口等价格从几十到两三百不等。板载资源越多上手越方便但核心学习路径是一样的。1.2 开发板上哪些东西你第一周就会用到拿到板子后先别急着写代码花十分钟把板子上的关键部件认一遍电源部分确认供电方式。蓝板通过Micro USB取5V板上有AMS1117-3.3稳压到3.3V。如果你用的是ST-Link下载器供电注意ST-Link的3.3V输出电流有限带不动太多外设。晶振8MHz主晶振给系统提供时钟源经过PLL倍频到72MHz。32.768kHz晶振给RTC用。如果板子上没有焊接晶振有些廉价板会省你就只能用内部RC振荡器精度差很多。BOOT跳线BOOT0和BOOT1的组合决定芯片从哪启动。正常运行时BOOT0接GND从Flash启动。串口下载时需要把BOOT0接VCC下载完再拨回去。这个跳线帽丢了会很麻烦建议多备几个。复位按键别小看它调试的时候按一下比拔插USB快得多。LED通常PC13接了一个LED蓝板上是PC13有些板子是PA5或PB0。点灯实验就是拿它开刀。下载接口蓝板引出SWD接口SWDIO、SWCLK、GND、3.3V需要配合ST-Link或DAP-Link使用。品牌开发板通常板载了下载器电路一根USB线就能下载。注意如果你买的是蓝板且没有ST-Link先别急着买。有些商家会把ST-Link和板子打包卖价格差不了几块钱但省事很多。单独买ST-Link的话认准带SWD接口的版本别买成只支持JTAG的老款。2. 工具链的选择Keil、CubeIDE还是VS Code2.1 Keil MDK资料最多但需要处理授权Keil MDK是STM32开发里资料最丰富的工具链国内绝大多数教程、例程、视频都是基于Keil的。它的优势在于编译器成熟、调试器集成度高、器件支持包Device Family Pack安装方便、网上遇到问题一搜就有答案。但Keil有两个让人头疼的地方。第一是授权问题MDK-Lite版本限制32KB代码F103C8T6的64KB Flash刚好卡在边界上稍微加点功能就超了。第二是Keil5默认不包含ARM编译器需要单独安装ARM Compiler 5或6而且Keil5和Keil4的工程不兼容网上很多老例程是Keil4的直接打开会报错。安装Keil5的正确顺序下载MDK-ARM安装包安装到默认路径不要有中文和空格。安装器件支持包到Keil官网下载STM32F1系列的DFP包或者用Pack Installer在线安装。安装ARM CompilerKeil5.37之后不再自带AC5需要单独下载ARM Compiler 5并手动添加到Keil的安装目录下。处理授权如果你有正版License就正常激活没有的话……嗯自己想办法。实操心得Keil的工程路径千万不要有中文和空格否则编译时会出现各种莫名其妙的错误。我见过有人把工程放在“D:\我的项目\STM32学习\”下面然后编译报错找不到文件折腾了一下午才发现是路径问题。2.2 STM32CubeIDE官方免费但生态稍弱STM32CubeIDE是ST官方推出的免费IDE基于Eclipse和GCC编译器集成了CubeMX配置工具。它的最大优势是免费、跨平台、自带CubeMX新建工程时可以直接图形化配置引脚和外设自动生成初始化代码。缺点是编译速度比Keil慢GCC优化不如ARMCC调试体验也稍逊一筹而且网上基于CubeIDE的教程相对少一些。如果你不想折腾授权问题CubeIDE是个很省心的选择。2.3 VS Code 插件适合有经验的开发者用VS Code开发STM32需要自己搭建工具链安装ARM GCC、OpenOCD或PyOCD、配置tasks.json和launch.json。这套方案灵活度最高适合已经熟悉命令行的开发者。但新手不建议一上来就搞这套光是配置编译和调试环境就能耗掉你两三天而且出了问题不好排查。我个人的建议是第一周用Keil或CubeIDE把流程跑通等对编译、下载、调试的流程有感觉了再考虑迁移到VS Code。工具是为你服务的不是用来折磨你的。3. 第一个工程从新建到点亮LED3.1 用标准库还是HAL库这是每个STM32新手都会遇到的问题。标准库Standard Peripheral Library是ST早期推出的库直接操作寄存器代码效率高、逻辑清晰国内大量教程基于标准库。HAL库Hardware Abstraction Layer是ST现在主推的库配合CubeMX使用跨系列移植方便但代码臃肿、执行效率低。对于F103来说我的建议是先学标准库再了解HAL库。原因很简单标准库能让你更清楚地看到寄存器的操作逻辑理解时钟树、GPIO模式、中断向量这些底层概念。等你把F103玩明白了再去看HAL库会发现很多东西都是相通的。3.2 新建标准库工程的完整步骤以Keil5为例新建一个标准库工程的流程创建工程目录结构。建议这样组织Project/ ├── CMSIS/ # 内核相关文件 ├── Library/ # 标准库文件 ├── User/ # 用户代码 ├── Start/ # 启动文件 ├── Obj/ # 编译输出 └── Project.uvprojx # Keil工程文件复制必要文件。从ST官网下载标准库压缩包解压后把以下文件复制到对应目录stm32f10x.h、system_stm32f10x.c/h、core_cm3.c/h→ CMSIS目录stm32f10x_gpio.c/h、stm32f10x_rcc.c/h等 → Library目录startup_stm32f10x_md.s→ Start目录C8T6属于中容量用md后缀的启动文件在Keil中添加文件分组。打开Keil新建工程选择芯片型号STM32F103C8然后在Project窗口中建立CMSIS、Library、User、Start四个分组把对应文件添加进去。配置头文件路径。在Options for Target → C/C → Include Paths中添加所有包含.h文件的目录。添加宏定义。在C/C → Define中添加USE_STDPERIPH_DRIVER, STM32F10X_MD。这两个宏缺一不可前者启用标准库后者告诉编译器芯片是中容量型号。编写main.c。一个最简单的点灯程序#include stm32f10x.h void Delay(__IO uint32_t nCount) { for(; nCount ! 0; nCount--); } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); 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); while(1) { GPIO_SetBits(GPIOC, GPIO_Pin_13); Delay(5000000); GPIO_ResetBits(GPIOC, GPIO_Pin_13); Delay(5000000); } }配置下载器。在Options for Target → Debug中选择ST-Link Debugger然后在Settings → Flash Download中勾选Reset and Run这样下载完程序自动运行。3.3 编译通过但下载失败最常见的三个原因“编译成功却烧录不进去”是新手遇到最多的问题没有之一。根据我的经验90%的情况是以下三个原因之一原因一BOOT跳线不对。如果你用串口下载BOOT0必须接VCC下载完再拨回GND。如果用SWD下载BOOT0接GND即可。很多人拨了跳线帽忘记拨回来结果程序下载进去了但不运行。原因二ST-Link驱动或固件问题。ST-Link在Keil中需要正确识别。如果Debug Settings里显示“No ST-Link detected”先检查USB线是否支持数据传输有些线只能充电再检查驱动是否安装。ST-Link的固件也可能需要升级用ST-Link Utility或STM32CubeProgrammer可以升级固件。原因三芯片被读保护或写保护。如果你买的是二手板或者之前烧过程序芯片可能被设置了读保护。用STM32CubeProgrammer连接后在Option Bytes里把Read Out Protection设为Disabled然后执行Full Chip Erase。实操心得遇到下载失败先别急着换板子。按这个顺序排查换USB线 → 检查BOOT跳线 → 换一个USB口 → 用STM32CubeProgrammer测试连接 → 检查芯片是否被保护。我遇到过最离谱的情况是USB线内部断了外观完全看不出来换线就好了。4. 点灯之后该练什么一条清晰的进阶路线4.1 外设学习的推荐顺序点灯只是让你确认工具链没问题接下来才是真正的学习。我建议按这个顺序推进GPIO输入按键检测、按键消抖。学会用轮询和中断两种方式读按键。串口通信USART的配置、发送和接收、printf重定向。串口是调试利器越早掌握越好。定时器定时中断、PWM输出、输入捕获。定时器是STM32最强大的外设之一值得花时间深入。中断系统NVIC的配置、中断优先级、外部中断EXTI。ADC模拟量采集、DMA传输。I2C和SPI驱动OLED、EEPROM、传感器等外设。DMA解放CPU提高数据传输效率。RTC实时时钟、闹钟、备份寄存器。看门狗独立看门狗和窗口看门狗提高系统可靠性。每个外设的学习方法都差不多先看参考手册里对应章节的框图理解工作原理然后看标准库的例程理解配置流程最后自己动手改代码做一个小项目验证。4.2 用串口打印调试信息比点灯更重要的技能很多新手学完点灯就卡住了因为除了LED亮灭他们不知道程序到底在干什么。串口打印是解决这个问题的关键。把printf重定向到USART1之后你可以在代码任何位置打印变量值、函数执行状态、错误信息调试效率提升十倍不止。printf重定向的代码int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) RESET); return ch; }然后在Keil的Options for Target → Target中勾选Use MicroLIB。注意如果不勾选MicroLIB需要自己实现_sys_exit等底层函数否则会报错。注意重定向printf之后串口助手的波特率要和代码中USART_InitStructure.USART_BaudRate设置的一致。我见过有人代码里写9600串口助手开115200然后说“串口输出乱码”这属于自己坑自己。4.3 从例程到项目做一个超声波测距小车学完基础外设后最好的巩固方式是做一个小项目。超声波测距是个不错的选择涉及定时器输入捕获、串口输出、GPIO控制难度适中。HC-SR04超声波模块的工作原理Trig引脚给至少10微秒的高电平触发测距模块自动发送8个40kHz方波然后Echo引脚变高高电平持续时间就是声波往返时间。距离 高电平时间 × 340m/s ÷ 2。用STM32F103实现时可以用定时器的输入捕获功能测量Echo高电平时间。具体做法配置TIM2的通道1为输入捕获模式上升沿触发捕获到上升沿后记录当前计数值然后切换为下降沿触发捕获到下降沿后再记录计数值两次差值乘以计数周期就是高电平时间。这个项目能让你把GPIO、定时器、中断、串口这几个外设串起来用做完之后对STM32的理解会上一个台阶。5. 那些年我们一起踩过的坑5.1 时钟配置错误导致串口乱码STM32F103的时钟树是新手最容易搞错的地方。系统时钟默认是内部8MHz RC振荡器经过PLL倍频后可以到72MHz。但如果你在SystemInit()之后又手动改了时钟配置或者外部晶振没有起振系统时钟就会跑偏导致串口波特率不对输出全是乱码。排查方法用示波器测MCO引脚PA8输出的时钟频率或者在代码里读取RCC_GetClocksFreq()的返回值通过串口打印出来确认。如果外部晶振不起振检查晶振是否焊接、负载电容是否匹配通常22pF、晶振频率是否设置正确。5.2 中断优先级配置不当导致程序卡死STM32F103的中断优先级分为抢占优先级和响应优先级NVIC_PriorityGroupConfig()决定了如何分配这两者的位数。如果配置不当可能出现中断嵌套死锁、中断无法触发等问题。常见错误在中断服务函数里调用了Delay函数。Delay通常基于SysTick而SysTick的中断优先级如果低于当前中断就会导致死循环。正确的做法是在中断里只做标记主循环里处理具体逻辑。5.3 变量被优化导致调试时看不到值Keil的编译器优化等级默认是Level 3会把一些“看起来没用”的变量优化掉。调试时你会发现某个变量在Watch窗口里显示“not in scope”或者值不对。解决方法把优化等级调到Level 0或者给变量加volatile关键字。5.4 栈溢出导致程序跑飞STM32F103C8T6只有20KB RAM如果定义了大数组或者递归调用太深很容易栈溢出。表现是程序运行一段时间后莫名其妙复位或者进入HardFault。排查方法在启动文件里把Stack_Size改大一些比如从0x400改成0x800或者在Keil的Target设置里调整。6. 关于学习节奏和心态的一些实话嵌入式开发的学习曲线是前陡后缓。刚开始接触寄存器、时钟树、中断向量这些东西会觉得非常抽象但一旦跨过某个门槛后面学新外设就是查手册、看例程、改代码的重复过程。我见过太多人买了开发板点了个灯然后就没有然后了。板子在抽屉里吃灰偶尔翻出来看一眼又放回去。问题不在于难度而在于没有明确的目标。如果你只是“想学STM32”这个目标太模糊了很容易放弃。但如果你给自己定一个具体的目标比如“做一个能显示温湿度的桌面时钟”或者“做一个能循迹的小车”学习过程就会完全不一样。另外不要试图把参考手册从头读到尾。STM32F103的参考手册有1000多页没有人能全部记住。正确的做法是用到哪个外设就查哪个章节先看框图理解原理再看寄存器描述了解配置方法最后对照标准库的例程写代码。还有一点很重要学会看英文资料。ST的官方文档、数据手册、参考手册、应用笔记都是英文的虽然国内有很多翻译版但翻译质量参差不齐而且更新不及时。直接看英文原版虽然一开始慢但准确度最高长期来看效率更高。最后说一个我自己的习惯每次调试成功一个功能我都会把关键配置和踩过的坑记在一个Markdown文件里。比如“串口重定向printf需要勾选MicroLIB”、“TIM2输入捕获需要先配置滤波器和分频器”之类的。这些笔记后来成了我自己的速查手册比翻例程快得多。你也可以试试这个方法坚持几个月你会发现自己对STM32的理解比只看教程的人深得多。