
STM32 开发板到手之后真正让人卡住的往往不是写代码而是从拆快递到点亮第一颗 LED 之间那段“没人细说”的路。我前后带过不少刚入行的朋友入门 STM32发现大家买的板子大同小异卡点却惊人地一致驱动装不上、Keil 里找不到芯片、下载器连不上、例程编译一堆报错。这篇就把 STM32F103 这块经典开发板从开箱到跑通第一个工程的全过程拆开讲顺带把后面做 USB 设备、串口调试、定时器捕获、CAN 通信这些常见需求的前置准备也一并说清楚。不管你是电子专业的学生、想转嵌入式的软件工程师还是准备拿 STM32 做毕业设计的同学跟着走一遍基本能少走两三个晚上的弯路。1. 为什么 STM32F103 至今仍是入门首选1.1 这块芯片的定位与生态优势STM32F103 属于 ST 的 Cortex-M3 系列主频常见为 72MHz片上 Flash 从 64KB 到 512KB 不等SRAM 一般 20KB 起步。放到今天看这个参数并不亮眼但它胜在资料密度极高。你随便搜一个外设问题比如“STM32 定时器捕获测频率”能翻出十几篇不同角度的教程、开源工程和论坛讨论。这种“遇到问题一定有人踩过”的生态对新手来说比性能重要得多。从选型逻辑上讲入门阶段最怕的不是芯片弱而是遇到问题搜不到答案。F103 因为出货量大、教学使用广标准外设库、HAL 库、LL 库三种开发方式都有成熟范例。你甚至能找到基于它的完整毕业设计代码、报站程序、鱼缸控制器这类成品项目。相比之下一些新出的开发板虽然性能强但资料零散新手容易在环境配置阶段就放弃。1.2 它和 3588、ESP32 这类板子的分工经常有人问现在 3588 开发板、ESP32-C3 这么火还有必要学 F103 吗我的看法是它们解决的是不同层次的问题。ESP32 自带 Wi-Fi 和蓝牙适合做联网终端3588 这类板子跑 Linux适合做边缘计算和多媒体。而 STM32F103 是裸机实时控制的典型代表你在这里学到的时钟树配置、中断优先级、寄存器操作、定时器 PWM是理解所有嵌入式系统的底层基础。打个比方ESP32 和 3588 像是已经装修好的房子你拎包入住F103 像是毛坯房你得自己拉电线、接水管。后者麻烦但你对“电从哪来、水怎么走”会有真正的概念。后面你再去用 ESP32 的 Arduino 环境或者给 3588 挂载 Ubuntu 系统心里会清楚每一层在干什么。1.3 买板子时容易忽略的几个细节拿到板子先别急着插电脑。我见过太多人因为板子上的跳线帽位置不对折腾半天以为芯片坏了。重点检查三处BOOT0 和 BOOT1 跳线决定启动模式正常跑程序时 BOOT0 要接地电源选择跳线确认是 USB 供电还是外部供电下载器接口是 SWD 还是 JTAG现在绝大多数板子用 SWD 四线制。另外注意板子上的晶振。F103 通常有 8MHz 外部晶振和 32.768kHz 低速晶振前者给系统时钟用后者给 RTC 用。如果板子没焊外部晶振你就得靠内部 RC 振荡器精度差很多做串口通信时容易出乱码。买之前看清楚商品页有没有标注“外部晶振”这个细节很关键。2. 开箱后第一件事把开发环境搭稳2.1 Keil MDK 与芯片包的安装顺序Keil MDK 是 F103 最主流的开发环境但它的安装有个顺序讲究。正确流程是先装 Keil MDK 主程序再装对应的器件支持包。器件包有两种获取方式一种是从 Keil 官网下载 Pack 文件双击安装另一种是在 Keil 里通过 Pack Installer 在线安装。国内网络环境下在线安装经常卡住建议直接下载离线 Pack。装完之后打开 Keil新建工程时如果能搜到 STM32F103 系列的具体型号说明器件包生效了。这里有个常见坑有人装了 Keil5 之后发现同时要兼容 C51结果两个版本冲突导致器件包加载异常。如果你确实需要 C51 和 STM32 共存建议装在不同目录并且用管理员权限运行避免注册表写入失败。提示Keil 的安装路径不要带中文和空格否则后面编译时可能出现找不到文件的报错这个坑很隐蔽。2.2 下载器驱动J-Link、ST-Link 与 DAP 的区别开发板配套的下载器常见三种ST-Link、J-Link、DAP-Link。ST-Link 是 ST 官方方案配合 STM32CubeProgrammer 很好用J-Link 通用性强但盗版固件容易掉DAP-Link 开源方案性价比高。不管哪种驱动装不对Keil 里就识别不到设备。以 ST-Link 为例装完驱动后设备管理器里应该出现对应设备没有黄色感叹号。如果 Keil 的 Debug 设置里选 SW 模式后能读到芯片 ID说明链路通了。读不到先查三样下载器驱动、SWD 四根线是否接反、板子是否上电。SWD 接口是 SWCLK、SWDIO、GND、3.3V其中 GND 必须共地这是最容易被忽略的一条。2.3 用 VSCode 搭建开发环境的取舍现在不少人想用 VSCode 配 STM32 开发环境配合 J-Link 下载调试。这条路可行但配置成本明显高于 Keil。你需要装 Cortex-Debug 插件、配置 launch.json、指定 OpenOCD 或 J-Link GDB Server 路径。对于刚入门的人我不建议一上来就折腾这套先把 Keil 跑通理解编译、下载、调试的完整链路再去换工具。如果你确实要用 VSCode核心是 launch.json 里的几个字段servertype选 jlink 或 openocddevice填具体型号interface选 swd。配置错了最常见的表现是能编译但下载失败或者下载成功但断点不生效。这套环境适合已经熟悉命令行工具链的人新手用它容易把“环境问题”和“代码问题”混在一起排查起来更痛苦。3. 从零建一个能跑的工程3.1 标准库、HAL 库、寄存器三种路线的选择建工程前先决定用哪套库。标准外设库贴近寄存器代码直观资料最多适合理解底层HAL 库抽象程度高配合 CubeMX 生成代码快适合快速开发直接写寄存器最锻炼人但效率低实际项目很少纯手写。我的建议是入门阶段用标准库建一个工程把 GPIO、时钟、中断这几个基础外设跑一遍理解每行代码在操作哪个寄存器。等熟悉了再转 HAL 库用 CubeMX 做图形化配置。这样你既知道 HAL 帮你做了什么也不会被它的层层封装绕晕。很多人直接上 HAL结果遇到问题不知道从哪查就是因为跳过了底层这一环。3.2 新建工程时那几个必须改的配置新建工程后有几个默认配置必须手动改否则后面会出各种怪问题。第一是目标芯片型号选错型号会导致 Flash 算法不匹配下载报错。第二是外部晶振频率在 Options for Target 的 Target 页里填 8MHz系统时钟配置才能算对。第三是下载算法在 Utilities 设置里确认 Flash 算法和芯片容量对应。还有一个容易漏的C/C 里的宏定义。用标准库时要定义USE_STDPERIPH_DRIVER并指定头文件搜索路径。漏了这一步编译时会报一堆“未定义”错误。这些配置一次配好后面新建工程可以直接复制模板省很多事。3.3 点亮第一颗 LED 背后的时钟逻辑点灯例程看着简单但它把 STM32 最核心的时钟使能讲清楚了。F103 的外设默认不供电你要用某个 GPIO 端口必须先使能对应端口的时钟。比如用 PA5 接 LED就要先开 GPIOA 的时钟再配置引脚为推挽输出最后写输出寄存器。为什么要有这一步因为芯片里外设众多全部常开功耗受不了。时钟使能相当于给某个外设“通电”不通电你写它的寄存器也没反应。这个逻辑贯穿所有外设用串口先开 USART 时钟用定时器先开 TIM 时钟用 ADC 先开 ADC 时钟。理解了这一点后面配置任何外设你都知道第一步该干什么。4. 串口、定时器、CAN 这些外设怎么上手4.1 串口调试新手最该先掌握的技能串口是嵌入式开发里最重要的调试手段没有之一。你后面调 PID、看传感器数据、打印日志全靠它。F103 的 USART1 默认接 PA9 和 PA10配置步骤是开时钟、配引脚复用、设波特率、使能收发、写发送函数。波特率计算和系统时钟挂钩。假设系统时钟 72MHz要设 115200 波特率就按公式算出分频值写进寄存器。算错了表现就是串口助手收到乱码。我建议第一个串口程序就写一个“收到什么回什么”的回环测试用 USB 转串口模块接到电脑确认收发都正常再往下做别的。注意USB 转串口模块的 TX 要接板子的 RXRX 接板子的 TX交叉连接。很多人直连导致收不到数据查半天以为是代码问题。4.2 定时器捕获测频率的实用场景定时器捕获测频率是个很典型的应用比如测电机转速、读传感器输出。原理是用输入捕获模式记录两次边沿之间的计数值再换算成频率。配置时要选对通道、设好预分频和自动重装载值还要处理溢出情况。实际做的时候有个细节信号频率范围决定预分频系数。频率高就少分频频率低就多分频否则计数值溢出或者精度不够。另外建议开启捕获中断在中断里读捕获寄存器避免主循环轮询丢事件。这套逻辑搞明白测超声波回波、读编码器信号都是类似思路。4.3 CAN 通信突然连不上的排查思路CAN 在工业控制里用得很多但新手常遇到“昨天还通今天连不上”的情况。排查顺序建议这样先看终端电阻CAN 总线两端各要一个 120 欧姆电阻少了信号反射会导致通信失败再看波特率两端必须一致差一点都通不了然后看收发器供电CAN 收发器芯片要单独供电供电异常时总线电平不对。还有一点容易被忽略CAN 引脚复用。F103 的 CAN 默认在 PA11 和 PA12但也可以重映射到 PB8 和 PB9。如果你用了重映射却没开 AFIO 时钟、没配置重映射寄存器引脚就没切过去自然通不了。这类问题用示波器看总线波形最直接有波形说明物理层通没波形就往硬件查。5. 那些没人明说但一定会踩的坑5.1 延时函数卡死的几种原因delay函数卡死是高频问题。常见原因有三个一是系统时钟没配对延时基于 SysTick时钟错了延时就不准甚至死循环二是中断里调用了延时如果延时依赖的中断优先级低于当前中断就会一直等三是看门狗没喂程序跑飞后被复位看起来像卡死。排查时先确认时钟配置用示波器或逻辑分析仪测一个 GPIO 翻转周期看实际延时和预期差多少。如果差得离谱基本就是时钟问题。另外提醒一句中断服务函数里尽量别用长延时需要延时就用计数器或标志位在主循环处理。5.2 芯片第一脚怎么确认焊接或接线前确认芯片第一脚方向这个看似基础但真有人搞反。F103 常见封装是 LQFP第一脚附近有个小圆点标记逆时针数第一脚。如果板子上丝印不清可以看芯片表面的文字方向通常文字正读时左下角是第一脚。接反了轻则不工作重则烧芯片动手前务必确认。5.3 禁用 JTAG 释放引脚的正确姿势F103 的 PA13、PA14、PA15、PB3、PB4 默认被 JTAG 占用。如果你想把这些脚当普通 GPIO 用需要禁用 JTAG 保留 SWD。操作是配置 AFIO 的复用重映射寄存器把 JTAG 功能关掉。注意别把 SWD 也关了否则下载器就连不上了只能靠 BOOT 模式救回来。正确做法是只关 JTAG 不关 SWD这样既释放了引脚又保留了下载调试能力。这个操作在引脚紧张的板子上很实用比如你要用 PB3 做 SPI 或者 PWM 输出时。6. 学完基础之后往哪个方向走6.1 做 USB 设备、HTTP 库这类进阶功能基础外设跑通后可以往 USB 设备方向走。F103 部分型号带 USB 外设能做 HID、CDC 这类设备。做 USB 的难点在于描述符配置和端点管理建议先跑通官方例程再改描述符实现自己的功能。另外 F103 资源有限跑 HTTP 库这类协议栈要精打细算内存别开太多缓冲。6.2 结合具体项目练手单纯跑例程容易忘找个具体项目做最有效。比如做个超声波测距涉及定时器捕获和串口输出做个步进电机控制涉及 PWM 和 GPIO做个数据采集涉及 ADC 和串口。这些项目网上都有参考但建议自己从头搭一遍遇到问题再查这样学到的东西才是自己的。6.3 从 F103 迁移到其他平台F103 学扎实后换到其他平台会快很多。比如换到 ESP32你会发现 GPIO、定时器、串口的概念是相通的只是 API 变了。换到 3588 这类 Linux 板子你理解的中断、时钟、外设概念依然有用只是操作方式从寄存器变成了系统调用。底层知识是通用的这也是为什么值得花时间把 F103 啃透。我个人带人入门时发现真正拉开差距的不是谁学得快而是谁在环境配置和第一个工程上少卡壳。把这篇里的顺序走一遍该检查的检查到位基本能顺利点亮第一颗灯。后面再遇到串口乱码、CAN 连不上、延时卡死这些问题回头看对应的章节大概率能找到方向。板子买回来就是用来折腾的别怕出错每一次排查都是在积累经验。