
STM32 开发板到手之后真正让人卡住的往往不是写代码而是从“板子亮起来”到“程序能稳定跑起来”之间的那一堆琐碎事。我前后用过 F103C8T6 最小系统板、F103ZET6 大板、普中 A2、正点原子 Mini 这几类板子也帮别人处理过“Keil 里编译成功但烧不进去”“ST-Link 识别不到芯片”“延时函数一调用就卡死”这类问题。这篇内容就是围绕 STM32-103 这块经典开发板把新手从开箱到跑通第一个工程、再到能自己改外设的完整路径讲清楚。不管你是刚下单等快递还是板子已经在桌上吃灰都可以顺着往下看。1. 拿到 STM32-103 开发板后先别急着写代码1.1 先确认你手里这块板子到底属于哪一类STM32-103 这个叫法其实是一个统称核心芯片通常是 STM32F103 系列常见型号有 C8T6、RCT6、ZET6 等。不同型号的 Flash 和 RAM 大小不一样引脚数量也不一样直接决定了你能跑多大的工程、能不能上文件系统、能不能接摄像头这类外设。我见过有人拿着 C8T6 最小系统板去跑带 LCD 和 FATFS 的例程编译出来直接爆 Flash然后到处问“为什么下载失败”其实根本不是下载的问题是芯片资源不够。拿到板子第一件事是看板子上的丝印或者芯片表面的激光刻字确认具体型号。F103C8T6 是 64KB Flash、20KB RAMF103ZET6 是 512KB Flash、64KB RAM两者能做的事情差很多。如果你买的是那种蓝色最小系统板大概率是 C8T6如果是带一堆排针、带 LCD 接口、带 SD 卡座的大板多半是 ZET6 或者 RCT6。提示不要只看商品标题写的“STM32-103”一定要看芯片本体。有些板子标题写 103实际焊的是兼容芯片或者别的型号虽然大部分情况下能跑但遇到需要唯一 ID、特定外设地址的时候就会出问题。1.2 开箱后必须检查的几个硬件细节板子到手先别插电脑花两分钟做几个检查能省掉后面很多莫名其妙的故障。第一看供电跳线帽有没有插好很多最小系统板有 3.3V 和 5V 选择跳线插错位置会导致芯片供电异常表现就是电脑能识别下载器但死活连不上芯片。第二看 BOOT0 和 BOOT1 跳线正常跑程序时 BOOT0 要接 GND如果被拨到 VCC芯片会进入系统存储器启动模式你烧进去的程序不会运行。第三看晶振有没有焊有些廉价板子为了省成本不焊 8MHz 晶振结果你写延时函数的时候发现时间完全不对。我自己的习惯是新板子第一次上电之前先用万用表量一下 3.3V 和 GND 之间有没有短路确认没有之后再插 USB。这个动作看起来多余但真遇到过一次板子出厂时电源滤波电容焊反的情况插上电脑直接发烫幸好提前量了一下。1.3 开发环境的选择Keil、IAR 还是 VS Code这个问题几乎每个新手都会问。我的建议是如果你目标是快速跑通、跟着教程走先用 Keil MDK5因为绝大多数 STM32 教程和例程都是基于 Keil 的遇到问题搜索到的答案也最多。Keil 的安装本身有个坑就是芯片包要单独装装完 Keil 之后还要去官网下载 STM32F1 的 Device Family Pack否则新建工程时找不到芯片型号。如果你已经习惯 VS Code想用 VS Code 开发 STM32那需要装 Cortex-Debug 插件、配置 OpenOCD 或者 ST-Link GDB Server还要自己写 tasks.json 和 launch.json。这条路不是不行但新手阶段容易在配置上耗掉大量时间建议先把 Keil 跑通再回头折腾 VS Code。至于 IAR编译效率确实好但授权和界面习惯对新手不太友好不是首选。开发环境上手难度教程丰富度适合阶段Keil MDK5低极高新手入门首选VS Code 插件中高中等有一定基础后IAR中中等工程化项目2. 从零新建一个能跑的 STM32F103 工程2.1 标准库还是 HAL 库新手到底选哪个这是另一个高频问题。标准库Standard Peripheral Library代码直观寄存器操作封装得比较薄看代码能大概猜到硬件在干什么适合理解原理。HAL 库Hardware Abstraction Layer是 ST 现在主推的配合 CubeMX 可以图形化配置引脚和时钟生成代码快跨系列移植方便但封装层次深出问题的时候不容易定位。我的建议是如果你时间充裕、想真正搞懂 STM32先用标准库把 GPIO、定时器、串口、中断这几个基础外设跑一遍知道寄存器大概怎么配。之后再转 HAL 库用 CubeMX 提高开发效率。如果你只是要做个课设或者快速出原型直接上 HAL CubeMX 也完全可以。两条路都能走通关键是别在两者之间反复横跳今天看标准库教程明天看 HAL 教程最后哪个都没学透。2.2 新建工程时最容易漏掉的三个配置第一个是时钟频率。STM32F103 外部晶振通常是 8MHz经过 PLL 倍频到 72MHz。如果你在代码里没配置时钟芯片默认跑内部 8MHz RC 振荡器延时函数的时间基准就全错了。标准库的SystemInit函数会帮你配好但如果你自己新建工程没加这个文件或者system_stm32f10x.c里的宏定义没改就会出现“延时 1 秒实际只有 0.1 秒”这种问题。第二个是调试接口配置。STM32F103 的 PA13、PA14、PA15、PB3、PB4 默认是 JTAG 功能如果你想把它们当普通 GPIO 用需要在代码里禁用 JTAG、保留 SWD。具体操作是开启 AFIO 时钟然后调用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)。很多人不知道这一步结果 PB3 接 LED 怎么都不亮查半天以为是硬件坏了。第三个是启动文件的选择。Keil 工程里要根据芯片容量选startup_stm32f10x_ld.s、md.s还是hd.s选错了会在链接阶段报错或者运行时跑飞。C8T6 是中等容量用md.sZET6 是大容量用hd.s。2.3 用 ST-Link 烧录时连接失败的排查顺序“Keil 里编译成功却怎么也烧录不进开发板”是热词里出现频率极高的问题。我按实际排查经验给一个顺序照着走基本能定位。先看 ST-Link 驱动有没有装好设备管理器里有没有识别到 ST-Link Debugger。如果识别到了但 Keil 里选不到去 Keil 的 Debug 设置里把调试器改成 ST-Link Debugger然后点 Settings看 SW Device 那一栏能不能读到芯片 ID。读不到的话检查排线有没有插反、板子有没有独立供电、SWDIO 和 SWCLK 有没有接对。如果 SW Device 能读到 ID 但下载报错多半是 Flash 算法没选对在 Settings 的 Flash Download 页面确认编程算法和芯片容量匹配。还有一种情况是芯片被读保护了表现是能连上但下载失败这时候需要用 ST-Link Utility 或者 STM32CubeProgrammer 做一次全片擦除把读保护解除。注意如果板子上电后芯片发烫立刻断电不要反复尝试下载。发烫通常是供电短路或者芯片已经损坏继续通电可能烧掉下载器。3. GPIO 和延时第一个能看见效果的程序3.1 点灯之前先理解推挽和开漏的区别点灯是所有人的第一个程序但很多人点完灯也没搞明白 GPIO 输出模式到底怎么回事。推挽输出Push-Pull可以输出高电平和低电平驱动能力强适合直接驱动 LED。开漏输出Open-Drain只能输出低电平高电平需要外部上拉电阻适合做电平转换或者 I2C 这种总线。如果你用推挽输出接 LEDLED 一端接 GPIO 一端接 GND那 GPIO 输出高电平灯亮如果 LED 一端接 VCC 一端接 GPIO那 GPIO 输出低电平灯亮。这两种接法在开发板上都常见写代码之前先用万用表确认一下 LED 的接法能避免“代码没错但灯不亮”的困惑。3.2 延时函数为什么一调用就卡死热词里有个“stm32 延时函数 delay 卡死”这个问题我遇到过好几次。最常见的原因是用了 SysTick 做延时但中断优先级配置有问题或者在其他中断里调用了延时函数导致嵌套卡住。还有一种情况是delay_init没有传对系统时钟频率比如实际跑 72MHz 但你传了 8MHz延时时间会差 9 倍看起来就像卡死。如果是用空循环做的软件延时卡死通常是因为编译器优化等级太高把循环优化掉了。解决办法是在循环变量前加volatile关键字或者降低优化等级。我个人的习惯是能用 SysTick 就用 SysTick不要用空循环因为空循环延时在不同优化等级下行为不一致很难调试。3.3 按键输入为什么要做消抖按键接 GPIO 输入配置成上拉或者下拉这个大家都知道。但很多人写完发现按一次键程序执行了好几次这就是抖动。机械按键在按下和松开的瞬间会产生几毫秒到十几毫秒的抖动CPU 跑得快会把这几次抖动都当成按键事件。消抖有两种做法一种是硬件消抖在按键两端并联一个 0.1uF 电容另一种是软件消抖检测到按键按下后延时 10 到 20 毫秒再检测一次两次都按下才认为是有效按键。软件消抖更常用但注意不要在中断里做延时消抖会阻塞其他中断。更好的做法是用定时器定期扫描按键状态做状态机消抖。4. 串口、定时器和中断让板子真正动起来4.1 串口通信的波特率为什么会对不上串口是 STM32 调试最重要的工具printf 重定向到串口之后调试信息直接打到电脑上比点灯高效得多。但串口最常见的坑就是波特率对不上电脑端显示乱码。原因通常是系统时钟配置不对导致串口分频计算出来的实际波特率和设定值偏差太大。STM32F103 的 USART 波特率计算公式是baud fCK / (16 * USARTDIV)其中 fCK 是 APB 总线时钟。如果 APB2 跑 72MHz你要 115200 的波特率USARTDIV 大约是 39.0625配置的时候整数部分和小数部分都要写对。标准库的USART_Init会帮你算但前提是你传进去的USART_BaudRate和实际时钟匹配。4.2 定时器模式那么多先搞懂最常用的三种STM32F103 的定时器功能很丰富但新手先掌握三种模式就够了。第一种是基本定时用来做周期性的任务比如每 1 毫秒扫描一次按键。第二种是 PWM 输出用来调光、调速、控制舵机。第三种是输入捕获用来测频率、测脉宽热词里的“stm32 定时器捕获测频率”就是这一类。配置定时器的时候核心是算清楚预分频器PSC和自动重装载值ARR。定时器时钟频率除以 PSC1 得到计数频率再乘以 ARR1 得到溢出周期。比如 72MHz 时钟PSC 设 71计数频率就是 1MHzARR 设 999溢出周期就是 1 毫秒。这个计算过程建议自己手算几遍比直接抄代码理解得深。4.3 中断优先级配置错了会有什么后果NVIC 中断优先级分组和抢占优先级、响应优先级的配置是 STM32 新手最容易搞混的地方。简单说抢占优先级高的可以打断抢占优先级低的中断响应优先级只在同时发生的时候决定谁先执行不能打断。常见错误是把所有中断都设成一样的优先级结果串口接收中断和定时器中断互相干扰表现为串口数据丢包或者定时器周期不准。我的习惯是对实时性要求高的中断给高抢占优先级比如电机控制对实时性要求不高的给低优先级比如串口打印。另外中断服务函数里尽量只做标志位处理和简单的数据搬运耗时操作放到主循环里做。5. 进阶路上绕不开的几个实战问题5.1 USB 虚拟串口和 USB 设备开发怎么入门热词里“stm32 如何做 usb 设备”和“stm32 usb 虚拟串口发送数据”出现频率很高。STM32F103 部分型号带 USB 外设可以做 USB 转串口、HID 设备、自定义设备。入门建议先用 CubeMX 配置 USB Device选 CDC 类生成代码之后电脑会识别出一个虚拟串口直接就能收发数据。但要注意USB 虚拟串口的收发和普通串口不太一样发送数据要等上一次发送完成才能发下一次否则会丢数据。接收数据也是回调式的需要在CDC_Receive_FS回调里处理。另外USB 时钟配置要求 48MHzF103 的 USB 时钟是从 PLL 分频来的CubeMX 会自动算但如果你手动改时钟树要确保 USB 时钟准确否则电脑识别不到设备。5.2 用 VS Code 开发 STM32 的配置要点“stm32 vscode 配置”也是高频搜索词。用 VS Code 开发 STM32核心是装 Cortex-Debug 插件然后配置调试器路径和 OpenOCD 脚本。编译可以用 Makefile 或者 CMake也可以用 Keil 的命令行编译。我自己的配置是用 STM32CubeMX 生成 Makefile 工程VS Code 里装 Cortex-Debug 和 C/C 插件调试用 ST-Link GDB Server。配置过程中最容易出问题的是 include 路径和宏定义VS Code 的 IntelliSense 需要知道芯片型号和头文件路径否则代码里全是红波浪线。解决办法是在.vscode/c_cpp_properties.json里把includePath和defines配全或者直接用 CubeMX 生成的配置。5.3 毕业设计和项目实战怎么选方向“基于 stm32 的毕业设计”这个热词说明很多同学是带着任务来的。我的建议是选题不要贪大选一个能完整跑通、有演示效果、自己能讲清楚原理的题目。比如超声波测距加数据显示、温湿度采集加报警、直流电机调速加 PID这些都是经典且资料丰富的方向。选方向的时候考虑三个因素硬件成本、代码复杂度、答辩时能不能讲清楚。超声波测距模块十几块钱代码量不大原理也好讲适合时间紧的同学。如果要做物联网方向可以加一个 ESP8266 或者 ESP32 做无线传输但要注意两个芯片之间的串口通信协议要设计好不然调试起来很痛苦。6. 我踩过的那些坑和给你的建议6.1 芯片包安装和 Keil 兼容 C51 的问题“stm32 芯片包安装”和“keil5 兼容 c51 和 stm32 安装”这两个问题经常一起出现。Keil MDK5 和 Keil C51 可以装在同一台电脑上但要注意安装路径不要冲突最好装在不同的盘符或者不同的目录下。装完之后如果 C51 的工程打不开检查一下是不是文件关联被 MDK 抢走了。芯片包安装失败通常是网络问题Keil 的 Pack Installer 下载速度不稳定。解决办法是去官网手动下载 Pack 文件然后双击安装。安装完之后在 Keil 里新建工程搜索芯片型号能搜到就说明装好了。6.2 程序下载成功但不运行的几种可能下载成功但不运行除了前面说的 BOOT 跳线问题还有几种可能。一是复位电路有问题芯片一直处于复位状态二是晶振没起振程序卡在SystemInit里等时钟稳定三是中断向量表偏移没设置对如果你用了 Bootloader 或者程序从非默认地址启动需要设置SCB-VTOR。排查的时候可以先用调试器单步运行看程序能不能走到 main 函数。如果连 main 都进不去问题在启动阶段如果能进 main 但外设不工作问题在外设配置。这个二分法能帮你快速缩小范围。6.3 给新手的三个实在建议第一买板子的时候顺手买一个 ST-Link 下载器和一个 USB 转串口模块这两个东西加起来不到三十块钱但能让你少走很多弯路。很多廉价板子自带的下载器功能不全调试的时候很受限。第二养成看数据手册和参考手册的习惯。STM32F103 的参考手册有一千多页不需要从头看到尾但用到哪个外设就去看对应章节的寄存器说明比在网上搜碎片化的答案靠谱得多。第三代码要自己敲一遍不要直接复制例程。复制来的代码跑通了你也不知道为什么能跑通换个需求就改不动了。自己敲的过程中遇到报错查资料解决这个过程才是真正学到东西的地方。板子买回来只是开始真正有意思的是你用它做出第一个属于自己的小项目。可能是让 LED 按你的节奏闪烁可能是做一个能显示温湿度的桌面小屏也可能是控制一个小车跑起来。不管是什么先让它跑起来再慢慢加功能这个过程本身就是最好的学习方式。