
快递拆开那一刻蓝色板子从静电袋里滑出来板面上印着“STM32F103C8T6”这排字母。如果你也正好把这样一块开发板买回来了又不知道接下来该干嘛这篇东西就是给你写的。我前后折腾过不下十块 STM32 开发板从最小系统板到正点原子、野火的全功能板都摸过可以负责任地说这块 F103 的板子只要你按顺序走完下面这些步骤从“点个灯”到“跑一个带中断、定时器、串口打印的小系统”大概就是两个周末的事。文章里我会把硬件认识、开发环境搭建、时钟、GPIO、中断、串口这些核心东西掰开揉碎讲清楚还有新手最容易踩的下载失败、芯片锁死、串口乱码这些坑我都会把排查思路写出来。目标是让零基础的读者也能照着把板子跑起来并且知道每一步背后的原因。1. 为什么第一块板子选STM32F1031.1 这块芯片的江湖地位STM32F103 是意法半导体 STM32 系列里被讨论最多的一颗芯片Cortex-M3 内核最高主频 72MHz板上这颗 C8T6 的型号是 64KB Flash、20KB RAM封装是 LQFP48。听起来参数平平无奇和现在动辄几百兆主频的芯片比完全不够看但它的价值恰恰在于“经典”和“资料够多”。我刚学单片机那会儿选的不是它而是 51 单片机那时候觉得 51 简单、教材多。但学了两个月就发现 51 的生态真的太老了IO 翻转速度慢、没有硬件调试接口、定时器资源少做个稍微复杂点的项目就捉襟见肘。后来一狠心换了 F103情况马上不一样ARM 内核、SWD 调试、硬件定时器、多路串口、ADC、PWM这些东西在整个嵌入式行业里是最通用的能力模型。学会了 F103你后面去摸 F4、H7、甚至其它厂商的 ARM 芯片迁移成本都不高因为内核和外设框架是相通的。换句话讲F103 不是性能最强的选择但它是“投入产出比”最高的学习平台。几十块钱的成本资料、教程、开源项目可以堆满一个硬盘遇到问题一搜就能找到答案。作为入门的踏板它太合适了。1.2 选板子时我在对比什么市面上的 F103 开发板主要有三类最小系统板、基础学习板比如正点原子 Mini 板、野火指南者、以及带丰富外设的全功能板。我给自己的选择标准是三点价格、资料完整度、外设扩展性。最小系统板最便宜十几块到二十几块板子上只有芯片、晶振、LDO、排针和一颗 USB 转串口芯片适合喜欢自己搭电路的玩家。但它的缺点也很明显没有板载下载器你得另外买 ST-Link而且没有按键、LED、屏幕接口这些基础外设新手到最后还是要买模块总体省不了几个钱。全功能板则相反板上把按键、LED、OLED/液晶接口、SD 卡座、CAN 收发器、音频、温湿度传感器这些都集成了跟着教程走很方便但价格贵有些功能可能你用不上。我实际更推荐中间那类“基础学习板”比如一块带 ST-Link、几个 LED、几个按键、一个 USB 串口、引出全部引脚的 F103 板子价格在一百以内足够覆盖入门到进阶的所有常见实验。拿我现在的推荐配置来说一块 C8T6 或者 RCT6 的板子配一个 ST-Link V2 下载器再加几根杜邦线总成本一百出头。如果你已经买了全功能板那更好资源只多不少。2. 开箱之后先别急着写代码2.1 板子上的硬件得认全很多新手拿到板子的第一反应是“插上USB就开始敲代码”结果发现电脑毫无反应。原因往往是连硬件都没认全更别提驱动了。一块标准 F103 开发板上通常有这些东西电源接口、USB 转串口芯片、BOOT0/BOOT1 跳线、SWD/JTAG 下载接口、外部晶振、复位按键、用户按键、LED以及若干排针。先记住两个关键角色。第一个是 USB 转串口芯片常见的有 CH340、CP2102、FT232 这几种。它的作用是把电脑 USB 信号转成板子能识别的串口信号让你的 STM32 能和电脑“对话”用来打印调试信息。第二个是 BOOT0 跳线这玩意儿新手极其容易忽略。它决定芯片从哪里启动BOOT0 拉低接 GND是从用户 Flash 启动这是正常运行模式BOOT0 拉高且 BOOT1 拉低是从系统存储器启动也就是进入“串口 ISP 下载模式”后面讲到芯片锁死救砖时会用到。还要注意芯片的第一脚怎么找。LQFP48 封装的小圆点旁边就是 1 脚然后逆时针数。你要是确定不了就看丝印上有一个角标或者对照数据手册的引脚图。这问题看着弱智但我见过有人把芯片装反导致烧录器无法识别排查了半天才发现是接线接错。2.2 装驱动、确认串口把板子跑起来让板子“通电”的第一步是装驱动。如果你是 CH340去官网下载 CH340 驱动装上如果是 CP2102装 CP210x 的 VCP 驱动。装完之后把板子通过 USB 线连上电脑打开设备管理器在“端口 (COM 和 LPT)”下面应该能看到一个 COM 口名字里通常带着你那个芯片的型号。我见过很多新手在这里卡住现象是设备管理器里压根没有新设备或者出现一个带感叹号的“未知设备”。这种问题十有八九是 USB 线的问题——注意不是所有 USB 线都能传数据有些线只能充电。我以前手头有一抽屉的线随便拿一根插上去就是没反应最后换了一根带数据功能的线才解决。这件事非常值得先排摸线材不对下面所有步骤全白搭。还有一种情况是驱动装上了、COM 口也出现了但一打开串口助手就报“无法打开串口”。这通常是串口被别的软件占用了关掉占用的软件再试就行。这一步做好之后板子就算是“通”了接下来才轮到开发环境登场。3. 搭建开发环境Keil、芯片支持包与第一个工程3.1 安装Keil MDK和F1的DFP包STM32 的开发环境选择很多我推荐从 Keil MDK 入手。IAR 也很好但 Keil 在中文资料、例程、视频教程的数量上碾压其他选择遇到问题容易找到参考。自己去官网下载 MDK 安装包版本 5.36 左右就行不用追求最新。安装路径千万别带中文和空格这是老生常谈但每次都会有人遭殃宁可安装在 D:\Keil_v5 这种干净路径下。装完 MDK 之后打开 Pack Installer找到 STMicroelectronics 目录把 STM32F1xx 的 Device Family Pack 下载安装好。没有这个包你新建工程的时候连 F103C8 的芯片型号都选不到。我遇到过一种情况是装了 pack 但工程里显示芯片型号是灰的那是因为 pack 没装全重启 Keil 或者重新安装 pack 即可。这里多说一句Keil 的 debug 功能窗口看起来简陋但实际用起来很稳。对于新手阶段你不需要上 VS Code CMake arm-none-eabi-gcc 那套复杂组合学起来容易劝退。等你会写工程了想迁移到 VS Code 也来得及其实核心还是那些编译链接命令。3.2 标准外设库还是HAL库我建议这样选这是一个争论了很久的问题。STM32 的开发方式有三套路线寄存器直接操作、标准外设库STM32 Standard Peripheral Library、HAL 库 CubeMX。我的观点可能和很多人不一样我不建议新手一上来就用 CubeMX。原因不是 CubeMX 不好而是它太“好”了。图形化配置、代码自动生成、时钟树自动算好新手确实能很快把灯点起来但这种“快”会让你跳过很多必要的理解。比如 RCC 时钟在哪里使能、GPIO 模式如何设置、重映射是什么这些在 CubeMX 里都是鼠标点几下的事你根本不会去思考为什么。当后面项目复杂起来、出了问题你会完全不知道从哪里排查。标准外设库的代码虽然啰嗦一点但它是“看得懂、追踪得到”的每一步初始化都有迹可循。你对照着寄存器手册去看库函数就特别容易建立“寄存器地址”和“外设配置”之间的映射关系。等你用标准库把 GPIO、UART、定时器这几个核心外设都亲手配置过一遍再回来用 CubeMX你会觉得它只有提效作用不再是掩藏原理的黑箱。3.3 建立工程、下载点灯程序我以标准外设库的方式为例讲一遍建工程的完整流程这也是我第一次把板子点亮时走过的路。先准备一份标准外设库推荐 V3.5 版本网上很容易下到。新建一个工程文件夹里面建好这几个子目录User放 main.c、stm32f10x_it.c、Core放启动文件 startup_stm32f10x_hd.s、系统文件 system_stm32f10x.c、Periph放标准库的 inc 和 src只添加你用到的外设即可、ProjectKeil 工程文件目录。然后在 Keil 里新建工程选择芯片型号 STM32F103C8接着添加启动文件和系统文件。关键的全局宏定义要在 Options - C/C 里加上 USE_STDPERIPH_DRIVER 和 STM32F10X_MD前者告诉编译器你要用标准外设库后者告诉它你的芯片是中容量型号。这两个宏不加或者加错编译大概率报一堆“undefined identifier”。接下来写第一个点灯程序核心代码就几行#include stm32f10x.h void delay(void) { volatile unsigned int i; for (i 0; i 500000; i); } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); while (1) { GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_SET); delay(); GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_RESET); delay(); } }这段代码里有两处我当初理解错了很久的地方。一个是RCC_APB2PeriphClockCmd你使用任何外设之前必须先把对应的时钟打开。GPIO 挂在 APB2 总线上所以要使能 RCC_APB2Periph_GPIOB。忘了这句寄存器写再多也没用外设压根没通电。另一个是GPIO_Mode_Out_PP这个推挽输出模式它和开漏输出的差别在驱动 LED 这种负载时体现不出来但后面接 I2C 总线、控制电机驱动芯片的时候就要注意了推挽输出能主动输出高低电平开漏只能拉低、要靠外部上拉才能拉高。编译通过后连接 ST-Link 下载器。注意接线四根3.3V、GND、SWDIO、SWCLK。在 Keil 的 Options - Debug 里选择 ST-Link Debugger点 Settings 确认能识别到设备然后点 Load 下载。下载成功后按一下复位键如果看到板载 LED 在闪恭喜你的 STM32 入门第一关已经过了。4. 核心知识拆解把这几个模块吃透才算入门4.1 时钟树先搞懂芯片的“心跳”点完灯之后如果直接开始复制粘贴各种外设代码你会发现经常出现“这段程序在别人板子上跑得好好的在我这就不行”的情况。根子在于你不理解时钟系统。STM32 的时钟树对所有型号来说都是同一种套路芯片上电后默认使用内部高速时钟 HSI8MHz但这只是备用时钟精度差、稳定性一般。真正的“主时钟”一般选择外部晶振 HSE常见的是 8MHz 外部晶振再通过 PLL 锁相环倍频到 72MHz也就是系统时钟 SYSCLK。很多同学学到这里就晕了“为什么 M3 要搞这么多层时钟”你可以把芯片想象成一座城市外设想象成各个工厂而时钟就是输电线。不同工厂对电压等级要求不同所以供电系统要先假设一个主干网再分压到各个片区。STM32 的 AHB、APB1、APB2 总线就是这个分级电网APB1 最高 36MHz主要给低速外设用APB2 最高 72MHz给高速外设用GPIO 就在 APB2 上。这也是为什么串口、定时器要想达到特定波特率或频率必须先弄清楚自己挂在哪条总线上然后用分频系数算出最终频率。标准的时钟初始化流程可以用SystemInit()完成它会读启动文件里定义的宏SYSCLK_FREQ_72MHz自动配好 PLL 分频倍频系数。如果你想手写核心动作就是先打开 HSE等待稳定后配置 PLL 为 9 倍频8MHz * 9 72MHz然后切换系统时钟源到 PLL。这套动作值得亲手写一遍因为它在开启任何外设之前都必须准备就绪。你还会遇到 SysTick 滴答定时器它挂在内核上和普通的定时器不同常用来做延时比如 HAL_Delay 就是基于它的。4.2 GPIO点灯背后的寄存器逻辑GPIO 算是 STM32 里最容易上手、也最需要细抠的外设。一个 GPIO 端口有多个配置寄存器MODER 管输入/输出模式、OTYPER 管推挽/开漏、OSPEEDR 管输出速度、PUPDR 管上下拉再加上输出数据寄存器 ODR 和输入数据寄存器 IDR。标准外设库的 GPIO_Init 函数本质上就是往这些寄存器里填值。新手最容易搞混的是“输出速度”这个概念。GPIO_Speed_50MHz不是指引脚“必须”输出 50MHz 的信号而是指 IO 驱动电路的翻转能力上限。如果你用的是低频信号设为 2MHz 反而功耗更低、电磁干扰更小如果做高速 SPI 或者 DHT11 这种对波形时序敏感的场景速度设太低可能边沿过缓导致采样失败。我建议平时点灯、接按键直接选 50MHz稳妥一点。还有一个经常翻车的地方是推挽和开漏的选择。推挽输出强弱高低电平都行适合驱动 LED、蜂鸣器开漏输出只能在低电平的时候主动驱动高电平要靠外部上拉电阻适合 I2C 这种“线与”总线场景。如果你在 I2C 上用了推挽模式虽然初始工作可能正常但一旦两个器件同时拉低总线就可能烧芯片这个坑越早理解越好。GPIO 还有一组很有用的复用功能配置也就是把引脚重新映射给串口、SPI 或定时器 PWM。比如 UART1 的 TX/RX 默认在 PA9/PA10但通过 AFIO 重映射可以挪到 PB6/PB7这在画 PCB、布线不方便时特别好用。用标准库时记得两件事需要重映射的外设要打开 AFIO 时钟还要查数据手册确认重映射后的引脚确实复用功能存在不然配置了也没信号。4.3 中断与定时器让程序学会自己干活一直用 while 循环轮询的方式写代码程序跑不到别的功能。从学会用定时器和中断开始你的程序才算真正“活”起来。STM32F103 的定时器资源很丰富TIM1 和 TIM8 是高级定时器带互补输出、死区控制可以用来驱动直流无刷电机TIM2~TIM5 是通用定时器能做定时、输入捕获、输出比较、PWM 生成TIM6/TIM7 是基本定时器只能做定时功能。入门阶段掌握一个通用定时器产生定时中断就够了。配置定时器的过程可以这样理解给一个计数器设定一个“重装值”然后给它一个“计数时钟”每当计数器从零加到重装值就触发一次中断或者输出翻转信号。假设你 APB1 的时钟是 36MHz定时器的时钟倍频之后可能是 72MHz如果你设置预分频器为 71即 72 分频、重装载值为 10000那么定时周期就是 72MHz / 72 1MHz 计数频率再数 10000 次正好 10ms 触发一次。这个计算过程我第一次学的时候觉得绕但其实你只要抓住“计数频率 时钟源频率 /预分频系数 1”这一个公式其它都能推出来。配置中断时还要注意 NVIC 这个概念它像个“中断路由器”决定哪些中断源能进入 CPU以及多个中断同时发生时谁优先。每个中断源要在 NVIC 里使能否则外设的中断标志置位了CPU 也不会响应。我见过不少新手写完定时器中断函数发现永远不进去就是漏配了 NVIC或者中断服务函数的名字和启动文件里的名字不一致。标准库里中断服务函数必须严格用启动文件定义的名字比如 TIM2 的中断函数叫TIM2_IRQHandler你在 main.c 里写错一个字母链接时也发现不了问题但中断就是不会进。4.4 串口与电脑对话调试效率翻倍串口UART是嵌入式开发里最通用的调试手段。你用 ST-Link 下载器打印不了数据只有串口才能看到变量值、状态标志、调试日志所以这块建议早学早用。配置 USART1 的流程说起来不算复杂使能 GPIOA 时钟和 USART1 时钟把 PA9 配置为复用推挽输出、PA10 配置为浮动输入然后初始化波特率、字长、停止位、校验位。这里我提一个非常容易忽略的点串口的 TX 引脚必须配置为复用推挽输出而不是普通推挽输出。普通推挽输出时引脚由 ODR 寄存器控制而复用推挽输出才把引脚的控制权交给外设。用错了配置串口发出来的全是乱码或者根本发不出来。波特率怎么理解就是每秒传多少个位。9600、115200 在串口助手里下拉菜单能选但要知道计算公式其实是波特率 外设时钟 /16 * 分频系数。重点来了如果你外部晶振不是标准的 8MHz比如用了 12MHz 晶振而启动文件和库又按 8MHz 算好了SystemInit那 UART 的波特率就会偏差一点点。短期看不出问题连接久了、数据量大帧错误就会频繁出现。这也是我遇到过串口“偶尔乱码”的一个重要来源。如果你想把标准库的printf直接重定向到串口只需要实现一个函数int fputc(int ch, FILE *f) { while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, (uint8_t)ch); return ch; }然后在 Keil 的 Options 里勾选 Use MicroLIBprintf就能直接往串口输出。注意 MicroLIB 是精简版 C 运行库体积小但不支持完整的浮点printf。如果你打印浮点数发现全是 0 或者异常就是这个原因建议把 float 拆成整数和小数分别打印。5. 新手最容易踩的坑我的排查实录5.1 下载失败“No target connected”这个报错基本每个玩 STM32 的人都会遇到先不用慌。遇到No target connected或Cannot connect to target按顺序排查五件事。第一检查下载器接线。ST-Link 的 SWDIO、SWCLK、GND 三根线必须可靠连接特别是 GND最好和板子的 GND 相连否则地电位不一致会导致识别失败。第二检查目标板供电。板子如果没有独立供电只靠下载器供电有些电路可能还是能跑但有的板载芯片功耗大就不稳定建议用 USB 给板子供电下载器只接信号。第三确认 Keil 里选择的下载器类型和实际一致你在 Debug 里选了 J-Link插的却是 ST-Link那自然连不上。第四检查 Reset 引脚。有些下载器需要给目标板提供复位信号如果你手动把复位键按住或复位电路有问题也会连不上。第五也是最容易被忽略的一步——确认 BOOT0 引脚状态。如果 BOOT0 被拉高芯片进入 ISP 模式此时内核不运行 Flash 里的程序SWD 仍然可以连接但某些情况会表现成连接不稳定。我自己的经验是80% 的情况是线没接稳或板子没供电剩下 20% 才是芯片本身的问题。所以排查的时候别一上来就怀疑板子坏了先把线拔掉重插一遍把 USB 重新插拔一遍。5.2 芯片锁死如何救回来“芯片锁死”这个词听起来吓人但 F103 很少真正烧坏。最常见的情况是你启用了 SWD 禁用功能比如误把调试引脚当普通 GPIO 重映射了下一次下载时 Keil 就报“Flash Download failed - Cortex-M3”之类的错。芯片本身没坏只是调试接口被关了。救砖的办法是强制进入 ISP 模式重新擦除 Flash。做法是把 BOOT0 跳线拨到高电平BOOT1 保持低电平手动复位一次这样芯片从内置 ROM 的 bootloader 启动SWD 引脚就恢复默认状态。此时再用 ST-Link 连接一般就能连上连上之后把 BOOT0 拨回低电平重新复位再烧录新程序恢复成功。如果没有 ST-Link也可以用 USB 转 TTL 的串口线接好 USART1 的 TX/RX注意交叉在电脑上用STM32CubeProgrammer连接串口同样可以烧录和擦除。我的经验是平时在代码里尽量不要重新映射调试引脚尤其是GPIO_PinRemapConfig那类操作要改注意点非常多。另外如果你用标准库在初始化代码前面临时加一段GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)之类的配置时更要小心它会影响 SWD 可用性除非你确认自己知道在干什么。5.3 串口乱码、屏读ID异常、CAN掉线这类奇怪问题串口打印乱码大部分是波特率对不上但还有两类隐蔽问题一是前面说的晶振频率不匹配库函数里默认按 8MHz 算实际晶振是 12MHz就会差 30% 以上二是供电电压不够稳定板载 LDO 输出 3.3V 偏低芯片内部 PLL 工作不稳定也会导致串口数据错乱。我排查问题的顺序一般是先量电压、再查晶振、最后改波特率。还有“ILI9341 屏幕读 ID 读到 A1A1”这种情况。我当初第一次驱动 TFT 屏幕时也读到了这种看起来完全不对的值。通常来说ILI9341 的 ID 是 0x9341读寄存器地址 0xD3 会依次返回几个字节其中包含 ID。如果你在任何地址读都是 0xA1A1原因大多是三个方向一是并行数据线接反或错位DB0-DB7 的顺序不对读出来的数据自然完全变样二是你手里的屏幕实际用的不是 ILI9341而是 ST7789 这类兼容屏驱读 ID 的指令和返回格式不一样三是片选或者 DC 引脚时序不对导致单片机读到的是一堆浮空值。遇到这种问题不要靠猜先把逻辑分析仪或者示波器挂上看数据线上的波形或者直接换一个已知 ID 的屏幕测试很快就能定位是屏的问题还是时序的问题。“CAN 通信突然连不上”也是热门搜索词。CAN 连不上、时通时断最常见的原因是终端电阻没有配对。CAN 总线两端各需要一颗 120 欧姆电阻如果只有一端有、或者两端都没有信号反射会导致波形失真就会出现“之前还好好的换了一根线就报错误”的诡异现象。此外还有一个新手坑CAN 波特率配置依赖时钟频率如果你把系统时钟倍频改了CAN 波特率也会跟着变通讯双方不一致就直接不进中断。排查 CAN 问题时我习惯先用示波器看 CAN_H 和 CAN_L 之间的差值是否在显隐性电平范围内再考虑软件配置。6. 这块板子接下来还能陪你走多远6.1 传感器、显示与运动控制方向入门过后你可能会觉得点灯、串口打印已经不够刺激了。这时候可以往三个方向自然延伸传感器采集、显示交互、运动控制。比如热词里的“stm32超声波测距”你就可以给板子接一个 HC-SR04用定时器输入捕获或者 GPIO 脉冲宽度测量来测距离。关键点是超声波模块的回波脉宽与距离成正比用定时器捕获两次上升沿之间的时间再换算成厘米。这个实验对理解定时器、中断和实时性很有帮助。显示方向最常见的是用 ILI9341 屏幕。新手要注意先搞清楚你手里的屏幕是 8080 并口还是 SPI因为 8080 并口的引脚控制比较复杂如果直接照搬别人的 SPI 例程就是前面说的读 ID 异常问题。而且注意 STM32F103 的 GPIO 翻转速度有限刷全屏会明显看到刷新过程这是正常的不是坏了你用 DMA 优化之后会好一些。运动控制方向热词里也有“五线四相步进电机stm32”“两轮差速小车stm32控制”。驱动步进电机需要额外的驱动芯片比如 ULN2003直接用 GPIO 控制电机绕组的通电顺序每次切换一个相位就能让电机转一个步距角。两轮差速小车稍微复杂一些要用定时器产生 PWM 控制电机速度再用编码器测速做闭环控制这就自然引出了 PID 调参。PID 不是玄学你先搭一个串口打印速度值的通道边调边看响应曲线再去找资料里的系数参考值会比对着公式凭空调参数高效得多。6.2 网络通信与物联网网关方向如果你走完上面这些还想玩点更“大”的东西通信方向是很好的进阶路径。F103 本身不带 WiFi但你可以通过串口挂 ESP8266/ESP32 模块、或者用 SPI 挂以太网芯片比如 ENC28J60走“MCU 通信模块”的模式。热词里的“巴法云”就是一个例子STM32 通过 MQTT 协议连接云平台把传感器数据上报、接收手机指令。这个方向会逼着你去学 AT 指令、MQTT 协议、JSON 格式但每一步都有回报。更高阶一点的玩法是“freertos stm32物联网网关”“stm32网关lwip协议栈”。F103 跑 FreeRTOS 完全没问题20KB RAM 虽然不算宽裕但精简配置下跑几个任务还是绰绰有余。我在一个基于 F103 的网关项目里用过 LwIP 协议栈通过 SPI 接口驱动 DM9000 网卡再配合 FreeRTOS 做 TCP 服务器性能虽然比不了工业网关但作为学习和验证原型足够。如果你想做 USB 设备方向F103 也有一个 USB Device 外设支持虚拟串口CDC、HID 等热词里“stm32 如何做usb设备”就是这个方向做一个小小的 USB 键盘或虚拟串口是个很有意思的项目。6.3 给新手的阶段路线建议最后分享一个我认为对新手最有用的阶段规划。第一阶段只做 GPIO 和点灯目标是把开发环境跑通理解编译、下载、调试的完整链路。第二阶段学串口和定时器把调试能力建起来能打印出变量的值程序逻辑出了问题可以快速定位。第三阶段做一个小综合项目比如“按键控制 LED 亮灭的速度”“串口输入一个数字控制 PWM 占空比”。第四阶段才去碰中断、DMA、外设总线这些进阶内容。第五阶段再根据自己的兴趣选方向屏幕驱动、电机控制、网络通信、嵌入式操作系统。我自己当初犯的最大错误就是太贪买到板子当天就想直接跑一个带系统、带协议栈的完整项目结果啥也看不懂反而浪费了更多时间。STM32 的学习曲线不是陡峭的那种而是“平台期很长”的那种——你一开始可能两三天没感觉但只要代码跑通一个实验后面的东西就开始加速串联起来了。你现在手上这块 F103就是带你入行的一块好跳板把它吃透后面什么板子都不慌了。