1. 拿到板子先别急着点灯,搞清楚你手里这块板到底能干什么
STM32-103的开发板到手那一刻,很多人第一反应是插上USB线看灯亮不亮。这个动作没错,但如果你只停留在“灯亮了”这个层面,后面大概率会在环境搭建阶段卡住。STM32F103是意法半导体基于ARM Cortex-M3内核的32位微控制器,主频72MHz,常见型号如F103C8T6拥有64KB Flash和20KB SRAM,片上集成了USART、SPI、I2C、CAN、USB、ADC、定时器等外设。这些参数意味着它能做的事情远超一块普通单片机:从超声波测距、步进电机控制、CAN总线通信,到USB设备开发、ILI9341屏幕驱动、甚至鱼缸自动喂食器这类生活项目,都在它的能力范围内。
我见过太多人买了板子之后,在“安装Keil”“找芯片包”“配置下载器”这三件事上耗掉一周,热情直接磨没了。所以这篇内容的核心目标很明确:帮你把STM32-103开发板从开箱到跑通第一个工程的全流程理清楚,同时把后续可以深入的方向和常见坑点一次性讲透。不管你是电子专业的学生、准备做毕业设计的准工程师,还是想从Arduino转向32位平台的爱好者,下面这些内容都能直接参考。
需要提前说明的是,STM32F103属于经典款,资料丰富到几乎任何问题都能搜到答案,但这也带来一个副作用:网上教程质量参差不齐,很多步骤互相矛盾。我会在关键环节标注哪些做法是经过验证的,哪些是需要根据自己板子实际情况调整的。
2. 开发环境搭建:从Keil到VSCode,选对工具少走三天弯路
2.1 Keil MDK还是VSCode加插件,先想清楚你的目标
刚拿到板子的人最纠结的问题就是用什么IDE。Keil MDK是STM32开发的老牌工具,优势在于上手快、调试方便、教程多,缺点是界面老旧、代码补全弱、正版授权费用高。VSCode加STM32插件或者PlatformIO的方案这几年越来越流行,代码编辑体验好、免费、插件生态丰富,但初始配置步骤多,对新手不够友好。
我的建议是:如果你之前完全没有32位单片机开发经验,先用Keil把第一个工程跑通,建立信心。等你能独立完成GPIO控制、串口收发、定时器配置之后,再考虑迁移到VSCode。这样你不会在“环境配置”和“代码逻辑”两个战场上同时作战。
Keil的安装本身不复杂,但有两个关键点容易被忽略。第一,安装路径不要有中文和空格,否则后续编译可能出现莫名其妙的错误。第二,安装完成后必须安装对应的芯片包,STM32F1系列需要安装Keil.STM32F1xx_DFP,这个包包含了启动文件、外设寄存器定义和标准外设库。芯片包安装失败是新手最常见的卡点,通常是因为网络问题或者Keil版本与包版本不匹配。如果在线安装一直失败,可以去官网下载离线包手动安装。
2.2 标准库还是HAL库,新手别在这件事上反复横跳
STM32F103支持三种开发方式:标准外设库、HAL库和直接操作寄存器。标准库是ST早期推出的,代码直观、贴近硬件、资料最多,但ST已经停止维护。HAL库是现在的主流,抽象程度高、跨系列移植方便,但代码体积大、执行效率略低。寄存器操作最底层,适合深入学习,但开发效率低。
对于F103这块板子,我强烈建议新手从标准库入手。原因很简单:F103的标准库资料最丰富,你遇到的几乎所有问题都能找到现成答案。HAL库虽然先进,但在F103上的教程质量不如标准库,而且HAL库的抽象层会让初学者对硬件理解不够深入。等你用标准库把外设都玩过一遍,再转HAL库就是几天的事。
新建工程时,你需要从ST官网或者开发板配套资料里获取标准外设库,通常包含Libraries文件夹下的CMSIS和STM32F10x_StdPeriph_Driver。工程目录结构建议这样组织:User文件夹放main.c和用户代码,Hardware文件夹放外设驱动,Library放标准库文件,Startup放启动文件。这个结构清晰,后续添加新外设时不会乱。
2.3 下载器选型与接线,SWD四根线走天下
STM32F103支持JTAG和SWD两种调试接口。JTAG需要20针,SWD只需要4根线:VCC、GND、SWDIO、SWCLK。实际开发中SWD完全够用,而且接线简单、占用引脚少。常见的下载器有ST-Link、J-Link、DAP-Link,其中ST-Link性价比最高,某宝几十块钱就能买到,配合Keil和STM32CubeProgrammer都能用。
接线时注意几个细节。第一,开发板的SWD接口丝印可能是SWDIO/SWCLK,也可能是PA13/PA14,对应关系要搞清楚。第二,如果板子上有复位按键,建议把下载器的RST也接上,这样下载器可以控制板子复位,调试更方便。第三,供电问题要确认:如果开发板已经通过USB供电,下载器的VCC可以不接,只接GND、SWDIO、SWCLK三根线即可,避免电源冲突。
注意:有些廉价ST-Link克隆版需要升级固件才能被最新版Keil识别,如果Keil提示“No ST-Link detected”,先去ST官网下载ST-Link Utility升级固件。
3. 第一个工程:从点亮LED到串口打印,把最小系统跑通
3.1 GPIO输出实验,理解推挽与开漏的区别
点亮LED是嵌入式开发的“Hello World”,但这里面藏着不少知识点。STM32的GPIO有八种模式:输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、推挽输出、开漏复用、推挽复用。驱动LED通常用推挽输出,因为推挽可以同时输出高电平和低电平,驱动能力强。
配置GPIO的步骤在标准库中很固定:先使能GPIO时钟,再定义GPIO_InitTypeDef结构体,设置引脚、模式、速度,最后调用GPIO_Init。这里有个容易忽略的点:STM32的每个外设都有独立的时钟,不使能时钟外设完全不工作。RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)这行代码就是给GPIOA供电,漏掉它LED永远不会亮。
LED的接法也影响代码逻辑。如果LED阳极接VCC、阴极接GPIO,那么GPIO输出低电平LED亮,这叫灌电流接法,STM32的GPIO灌电流能力比拉电流强,推荐这种接法。如果LED阳极接GPIO、阴极接GND,那么输出高电平LED亮,但驱动电流有限,亮度可能不够。
3.2 串口通信配置,printf重定向的完整流程
串口是调试利器,能把程序内部的变量值打印到电脑上。STM32F103通常有3个USART,配置步骤包括:使能USART和GPIO时钟、配置TX为复用推挽输出、RX为浮空输入或上拉输入、设置波特率、数据位、停止位、校验位、使能USART。
波特率计算是重点。STM32的USART波特率通过公式计算:波特率 = fCK / (16 * USARTDIV),其中fCK是USART时钟频率,通常为72MHz(APB2)或36MHz(APB1)。以72MHz、115200波特率为例,USARTDIV = 72000000 / (16 * 115200) = 39.0625。整数部分39写入BRR的[15:4]位,小数部分0.0625乘以16等于1,写入BRR的[3:0]位。标准库的USART_Init函数会自动计算,你只需要填入波特率数值即可。
printf重定向需要实现fputc函数,把字符通过USART_SendData发送出去。具体做法是在main.c中添加#include <stdio.h>,然后重写fputc:
int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); return ch; }同时需要在Keil的Target选项中勾选“Use MicroLIB”,否则printf不会正常工作。这个选项在Options for Target -> Target标签页里,很多人漏掉这一步,然后纳闷为什么串口没输出。
3.3 延时函数怎么写才靠谱,SysTick是最佳选择
延时函数看似简单,但用for循环实现的软件延时在不同优化等级下时间完全不同,而且占用CPU。STM32内置了SysTick定时器,是一个24位的递减计数器,专门用于产生精确延时。
配置SysTick延时的思路是:设置重装载值为72000-1,时钟源选择HCLK的8分频即9MHz,这样每个计数周期是1/9微秒,72000个周期就是8毫秒。更常见的做法是设置重装载值为9000-1,得到1毫秒的基准,然后通过循环实现任意毫秒延时。
void delay_ms(uint32_t ms) { uint32_t i; for(i = 0; i < ms; i++) { SysTick->LOAD = 9000 - 1; SysTick->VAL = 0; SysTick->CTRL = 0x01; while(!(SysTick->CTRL & 0x10000)); SysTick->CTRL = 0; } }这段代码不依赖库函数,直接操作寄存器,执行效率高。注意SysTick是Cortex-M3内核的外设,不是STM32芯片特有的,所以换到其他M3内核芯片上也能用。
4. 进阶方向选择:根据你的项目需求挑外设深入
4.1 定时器捕获测频率与超声波测距
定时器是STM32最强大的外设之一,F103有多个通用定时器和高级定时器。输入捕获模式可以测量外部信号的频率和占空比,原理是当引脚检测到边沿跳变时,定时器当前计数值被锁存到捕获寄存器,通过两次捕获值的差值和定时器频率就能算出信号周期。
超声波测距模块HC-SR04就是典型应用。给它Trig引脚一个10微秒的高电平脉冲,模块发出8个40kHz的超声波,Echo引脚会输出高电平,高电平持续时间就是超声波往返时间。距离 = 高电平时间 * 340m/s / 2。用定时器输入捕获测量Echo高电平时间,精度可以做到毫米级。
配置输入捕获时要注意:捕获边沿选择、输入分频、滤波参数都会影响测量结果。如果信号有抖动,适当增加滤波器的采样频率和阈值。另外定时器溢出问题必须处理,否则测量长距离时计数值会回绕导致结果错误。
4.2 CAN通信与485控制伺服电机
CAN总线在工业控制和汽车电子中应用广泛,STM32F103自带CAN控制器,配合外部收发器如TJA1050就能组网。CAN通信突然连不上是常见问题,排查顺序是:先确认终端电阻是否接好(CAN总线两端各需要120欧姆终端电阻),再检查波特率是否一致,最后用示波器看CAN_H和CAN_L的差分信号是否正常。
485通信则是另一种工业现场总线,半双工、差分信号、传输距离远。用STM32控制伺服电机时,通常通过485发送Modbus协议指令。关键点是DE/RE引脚的控制时序:发送数据前拉高DE进入发送模式,发送完成后拉低DE回到接收模式,这个切换时机不对会导致数据丢失或总线冲突。
4.3 USB设备开发与ILI9341屏幕驱动
STM32F103的USB外设支持全速设备模式,可以做HID键盘、虚拟串口、大容量存储设备等。USB开发比串口复杂得多,需要理解端点、描述符、枚举过程。新手建议先用STM32CubeMX生成USB HID例程,跑通后再研究描述符结构。
ILI9341是一块常见的2.8寸TFT屏幕,分辨率240x320,SPI接口驱动。读ID返回0xA1A1说明通信正常,如果返回0x0000或0xFFFF则检查接线和初始化时序。驱动屏幕的难点在于初始化寄存器序列很长,而且不同厂家的屏幕模组可能略有差异。建议直接使用成熟的驱动库,把精力放在图形绘制和界面逻辑上。
5. 常见问题排查与避坑经验实录
5.1 下载失败与芯片识别问题
下载失败是新手遇到最多的问题,表现五花八门:Keil提示“No Cortex-M Device found”、ST-Link Utility连接不上、下载后程序不运行。排查思路如下表:
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 提示找不到设备 | SWD接线错误或接触不良 | 检查SWDIO/SWCLK是否接反,重新插拔杜邦线 |
| 能识别但下载失败 | 芯片被读保护或写保护 | 用ST-Link Utility解除保护 |
| 下载成功但不运行 | BOOT引脚状态不对 | BOOT0接GND,BOOT1任意 |
| 偶尔能连上偶尔不行 | 电源不稳定或时钟问题 | 检查供电电压,降低SWD速度 |
还有一个隐蔽的坑:有些开发板把PA13/PA14复用为其他功能,导致SWD无法使用。这时候需要在代码中禁用JTAG但保留SWD,或者用BOOT0拉高的方式从系统存储器启动,擦除芯片后再重新下载。
5.2 串口乱码与延时卡死
串口打印乱码几乎只有一个原因:波特率不匹配。检查代码中设置的波特率和串口助手选择的波特率是否一致,晶振频率是否和代码中定义的一致。如果用的是外部晶振,确认实际焊接的是8MHz还是12MHz,SystemInit函数会根据宏定义配置时钟。
延时函数卡死通常发生在SysTick配置错误或者中断优先级冲突时。如果程序中开了其他中断,而SysTick中断优先级设置不当,可能导致延时循环永远等不到计数结束。解决办法是检查NVIC优先级分组和SysTick中断优先级配置。
5.3 芯片包安装与工程模板复用
STM32芯片包安装失败时,可以尝试以下步骤:关闭Keil,删除Pack文件夹下的缓存,以管理员身份运行Keil,重新安装。如果在线安装始终不行,去Keil官网下载对应的.pack文件,双击安装。
工程模板建议自己整理一份,包含标准库、启动文件、延时函数、串口驱动。以后新建工程直接复制模板,改改main函数就能用,省去重复配置的时间。模板中的头文件包含路径、宏定义、编译选项都配置好,避免每次新建工程都要重新设置。
6. 从开发板到完整项目,我的实际体会
STM32F103这块板子最大的价值在于它的“教学完整性”。它不像一些高性能芯片那样外设复杂到让人望而却步,也不像8位单片机那样资源紧张到每个字节都要精打细算。72MHz主频、丰富的外设、充足的资料,让它成为从入门到进阶的理想平台。
我在实际使用中发现,真正决定学习效率的不是板子本身,而是你选择的第一个项目。如果第一个项目是“点亮LED”,你可能一周就失去兴趣。如果第一个项目是“用超声波测距做一个倒车雷达”,你会主动去查定时器捕获、串口打印、蜂鸣器驱动,学习动力完全不同。所以我的建议是:拿到板子后,先想一个你真正想做的小东西,哪怕只是一个会自动开关的鱼缸灯,然后围绕这个目标去学外设。遇到问题就查手册、搜论坛、看例程,这种“以项目驱动学习”的方式,比按部就班看教程快得多。
另外,STM32的参考手册和数据手册要养成查阅习惯。中文参考手册虽然厚,但每个外设的寄存器说明、时序图、配置流程都写得清清楚楚。网上教程可能过时或者有误,手册永远是最权威的来源。刚开始看手册会觉得枯燥,但坚持查几次之后,你会发现很多问题在手册里早有答案。