开发板到手的那一刻,确实挺兴奋的。STM32-103的开发板,也就是基于STM32F103芯片的那些板子,可能是国内学习嵌入式接触最多的一类硬件了。不管你是电子相关专业的学生,还是工作后转行想搞单片机,这个板子基本是绕不过去的一站。这篇文章就针对刚把板子买回来、还没想好怎么下手的朋友,把开箱确认、环境搭建、第一个程序到进阶模块的路线完整捋一遍,顺便把那些容易踩的坑提前给你标出来。
先说清楚这块板子能干什么。STM32F103是意法半导体推出的一款基于ARM Cortex-M3内核的32位单片机,主频最高72MHz,片上资源包括Flash存储、SRAM、ADC、定时器、USART串口、I2C、SPI、CAN、USB等常见外设。你手头这块板子,一般就是把最小系统、USB转串口、LED、按键、TFTLCD接口、Flash芯片等外设集成在一起的开发板。它能做的事情非常多,从简单的跑马灯、按键检测,到超声波测距、控制伺服电机、驱动打印机,再到读取显示屏、做USB设备、跑CAN通信,全都能覆盖。适合零基础的初学者,也适合做毕业设计或者产品原型验证。
买回来之后,很多人第一件事是迷茫,不知道从哪里开始。别急,我按自己的实操经验把整个流程拆成几个阶段,一步一步来说。
1. 开箱之后先别急着上电,把板子认清楚再说
1.1 先确认主控芯片型号和封装
STM32F103这个系列有很多型号,常见的有STM32F103C8T6、STM32F103RCT6、STM32F103ZET6等。后缀里的字母和数字代表封装和Flash容量。C8T6是48引脚,Flash 64KB,常用的“蓝板”就是这颗;RCT6是64引脚,Flash 256KB,很多入门开发板用的也是它;ZET6是144引脚,Flash 512KB,属于大容量型号。
拿到板子后,先找到主控芯片,看丝印上的型号。这个动作很重要,因为后续建工程选芯片型号、配置启动文件、选择Flash容量都要用它。千万别凭感觉选错型号,否则程序烧进去可能跑不起来,或者下载器报错说识别不到芯片。我第一次就因为这个折腾了大半天,板子是RCT6,工程里选的C8T6,编译下载都正常,但一跑就死机。
1.2 确认第一脚,养成看原理图的习惯
很多新手拿到板子会问,芯片第一脚怎么确认。方法很简单:芯片上有圆形或斜切的标记,从标记处开始逆时针数,就是第1脚。开发板出厂一般会在PCB上印上芯片的方向和1脚位置,不会太明显但放大看能找到。
这个细节千万不要忽视,因为后面你接外设、量信号、接示波器探头都要从原理图出发,原理图里芯片引脚编号就是按第一脚顺序排的。顺便说一句,开发板的原理图一定要从卖家页面或者配套资料里下载保存好,后面查问题全靠它。
1.3 上电前的检查清单
上电前最好做三件事:一是看板子供电方式,大多数开发板通过USB供电,也有支持DC电源座或外部电源输入的;二是确认板子上的电源开关是否拨到ON;三是检查有没有明显焊锡短路或者元器件脱落,尤其是USB接口附近的保护元件。
确认没问题后,插上USB线。正常情况下,板子上的电源指示灯会亮,如果是带USB转串口的板子,电脑上会识别到一个串口设备。如果你的电脑识别不了,先检查驱动。很多板子用的USB转串口芯片是CH340,在Windows 10/11下一般会自动装驱动,但偶尔需要手动安装。如果连的是什么CP2102或者FT232,也都有对应驱动,去官网下载安装就行。
1.4 确认串口芯片和板子版本
有个经验:买开发板一定要看清串口芯片型号。CH340的兼容性最好,驱动好装,烧录也方便。部分老板子用的CP2102在某些系统上会抽风,FT232虽然稳定但假货多。板子到手后打开设备管理器看端口那一栏,确认识别到一个COM口,并且记下COM几,后面下载程序要用。
2. 开发环境搭建:Keil和VSCode,两条路都要会
2.1 Keil MDK的安装和芯片包
STM32开发最主流的IDE是Keil MDK,也就是Keil uVision。去官网下载MDK安装包,建议用5.x版本。装完之后必须装芯片包,否则Device里找不到STM32F103。芯片包在Keil官网的Pack Installer里在线安装,或者下载离线pack包手动装。
打开Pack Installer,搜索STM32F1,找到STM32F1xx系列的支持包,点击Install。这一步很关键,很多人装完MDK发现没有STM32选项,就是漏了芯片包。装完后新建工程,在弹出的Device选择界面搜索STM32F103,根据你的型号选择对应的具体芯片,比如STM32F103RCTx。
启动文件也要选对。在Manage Run-Time Environment里,Device下的Startup勾选。MDK会自动帮你选择对应容量型号的启动文件,大容量和小容量启动文件不一样,不要自己乱改。
2.2 标准库还是HAL库,选型背后的逻辑
STM32开发有两条主流路线:标准外设库(Standard Peripheral Library,简称标准库)和HAL库。标准库是意法半导体早期的封装库,代码直观,一个外设对应一组API,比如GPIO_Init、USART_SendData,适合理解寄存器操作逻辑。HAL库是后来的抽象库,代码更臃肿,但跨平台迁移好,配合STM32CubeMX图形化配置工具非常方便。
我的建议是:如果是学生做毕设、比赛,或者产品要用STM32CubeMX生成工程,直接用HAL库;如果想把单片机底层搞透、希望代码精简可控,标准库更适合练手。现在的开发板资料里,F103的标准库资料非常多,绝大多数入门教程都是标准库写的,所以新手用标准库跟着教程走最顺畅。但也要提醒一句:能读懂HAL库也总要会的,因为现在的芯片型号和第三方SDK越来越多地默认用HAL。
2.3 VSCode搭建STM32开发环境的补充方案
除了Keil,也可以用VSCode搭配EIDE(Embedded IDE)插件或者PlatformIO来开发STM32。热词里也有不少人搜“VSCode配置STM32开发环境”,说明这个需求确实在增长。EIDE插件的思路是:在VSCode里管理工程、编译,然后配合OpenOCD或者pyOCD下载调试。
这个方案的好处是编辑器体验好,代码补全比Keil舒服太多,而且工程可以方便地放进Git管理。缺点是要自己折腾配置,编译链要用arm-none-eabi-gcc,调试配置文件要自己写launch.json。如果你只是入门阶段,建议先用Keil把流程跑通,等代码量上来了再考虑切VSCode,否则环境问题会把你劝退。
2.4 下载调试工具的选择
开发板通常板载ST-Link,或者用DAP-Link,也有的是用USB转串口ISP下载。ST-Link是意法半导体官方的调试器,支持SWD模式,接线只有SWDIO、SWCLK、GND三根,非常省事。如果你的板子没有板载ST-Link,外接一个ST-Link V2也很便宜,几块钱到十几块不等,能用就行。
注意一点:很多板载ST-Link和板载串口是分开的两个USB口,上电的时候两个口都插上,调试和串口监视才能同时工作。有些初学者只插了串口口,结果Keil里怎么都识别不到ST-Link,就是这个原因。
3. 第一个程序:跑马灯和按键,GPIO的核心你要吃透
3.1 跑马灯背后的原理
很多人的第一个STM32程序就是点亮LED。看似简单,但里面的知识点一点也不简单。LED的引脚一般接在芯片的某个GPIO上,你要做的就是把这个GPIO配置成推挽输出模式,然后写高电平或低电平控制LED亮灭。
GPIO配置在标准库里就是几行代码:
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);这段代码干的事情是:打开GPIOB的时钟、把Pin0设置为推挽输出、速度50MHz。STM32的每一个外设在使用前都要先打开对应的时钟,这一点和51单片机非常不一样,也是新手最容易忘的。忘了使能时钟,代码看起来全对,但外设就是不工作。
推挽输出是什么意思?简单说就是引脚既能输出高电平、也能输出低电平,而且驱动能力比较强,适合驱动LED这种负载。对应的还有开漏输出,开漏模式不能主动输出高电平,必须接上拉电阻才能输出高,一般用于I2C这类总线,或者需要在外部接不同电压电平的场合。
跑马灯就是多个LED依次亮灭,本质上就是循环控制几个引脚的电平变化。用延时函数控制节奏,比如每点亮一个灯延时500ms再切换。这是练习GPIO输出和延时函数的好项目。
3.2 按键输入的上拉下拉和消抖
按键输入和LED相反,要配置成输入模式。这里有两个关键点:上拉/下拉电阻的选择和消抖处理。
按键的一端接GPIO,另一端接GND或者VCC。如果按键一端接地,那么GPIO需要配置成上拉输入,平时读到高电平,按下时读到低电平。反过来,如果按键接VCC,就要用下拉输入。标准库配置里对应的是GPIO_Mode_IPU和GPIO_Mode_IPD。
消抖的问题是机械按键固有的。按下和松开的瞬间,机械触点会抖动,单片机读到的电平在几毫秒里会跳变多次。如果不对这个跳变做处理,一次按键可能会被识别成好几次。最简单的消抖方法就是软件延时,检测到电平变化后延时10到20毫秒再读一次,确认电平真的变化了再执行操作。这个延时消抖是嵌入式里非常基础的手法,后面做矩阵键盘、旋转编码器都要用到。
3.3 启动配置BOOT0和BOOT1
板子上一般有两个跳线或者拨码开关,标注BOOT0和BOOT1。这两个引脚决定芯片从哪个地址启动。BOOT0拉低时从Flash启动,正常运行你的程序;BOOT0拉高、BOOT1拉低时从系统存储器启动,此时可以通过串口ISP烧录固件;BOOT0和BOOT1都拉高时从SRAM启动,一般调试用。
新手经常犯的问题是:程序下载进去没反应,或者下载的时候出现“Cannot access target”,结果发现BOOT0跳线插错了位置。记住一个规律:正常运行时BOOT0接GND;如果需要用串口ISP下载,把BOOT0接到3V3,下载完再拨回去。
3.4 下载程序时JTAG和SWD的坑
热词里有“STM32禁用JTAG”,这个是很经典的一个坑。STM32默认的调试接口是JTAG,占用了PA13、PA14、PA15、PB3、PB4这几个引脚。如果你的程序初始化里复用或者重映射了这些引脚,那么调试器可能就接不上了,表现为下载失败、芯片锁死。
解决办法有两种:一种是在程序里保持默认的SWD引脚配置,也就是说你即便不用调试接口,也别动PA13和PA14,这两个是SWDIO和SWCLK;另一种是你真的要用这些引脚做其他功能,那就得在程序里禁用JTAG功能,比如标准库里写GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);但禁用之后再用调试器就识别不到芯片了,需要先设置BOOT0为系统存储器模式、通过串口擦除或者用ST-Link的Connect under reset方式恢复。
所以建议:新板子刚开始玩,PA13和PA14别离它们。调试接口比多两个GPIO重要得多。
4. 进阶模块的学习路线:定时器、中断、串口、显示和总线
4.1 中断系统:让CPU学会响应事件
中断是STM32里最核心的机制。没有中断的话,CPU只能不停地轮询外设状态,效率低,实时性也差。STM32F103的NVIC(嵌套向量中断控制器)支持多个中断优先级分组,每个外设都可以产生中断请求。
学习中断建议从外部中断入手,也就是EXTI。配置步骤是:初始化GPIO为输入、把引脚连接到EXTI线、配置EXTI触发方式(上升沿、下降沿或双沿)、配置NVIC优先级、编写中断服务函数。中断服务函数执行时间要短,不要在中断里做耗时的事情,比如延时、打印、浮点运算。原因很简单,中断期间主程序是被打断的,你在中断里磨蹭太久,后面的中断就会排队,实时性就崩了。
我自己踩过的一个坑是中断服务函数里调用了printf,结果波特率又没配好,程序一进中断就卡死。后来查了几天才发现是printf重定向的问题。现在我的习惯是中断里只置标记位,主循环里查标记位处理业务。
4.2 定时器:不仅会数数,还能捕获、比较、产生PWM
定时器是STM32里水最深的一个外设。F103有高级定时器TIM1和TIM8、通用定时器TIM2到TIM5、基本定时器TIM6和TIM7。学习定时器可以从最基本的定时中断开始:配置定时器时钟分频、计数周期、使能更新中断,然后在中断服务函数里累加一个标志变量,就能实现非阻塞的时间片轮询,比裸奔的delay好用得多。
进阶的操作是输入捕获,热词里有“STM32定时器捕获测频率”,这个功能非常实用。输入捕获的原理是:定时器计数器不断自增,当检测到引脚上的边沿信号时,把当前的计数值捕获到寄存器里。两次捕获的计数值之差乘以定时器时钟周期,就是信号周期,一算就是频率。用这个功能不需要额外外部电路,就能测量PWM频率和脉宽。
还有一个非常常用的功能是PWM输出,也就是定时器比较输出。通过调节比较值可以改变占空比,占空比不同,LED亮度不同,舵机角度不同,电机转速也不同。这是后面做控制和驱动的基础。
4.3 串口通信和printf重定向
USART串口是调试和通信的必备外设。STM32F103一般有多个USART,其中USART1的引脚是PA9(TX)和PA10(RX)。配置串口要注意的引脚复用:PA9和PA10默认就是USART1的功能,但要确保没有其他代码把这两个引脚配置成了普通GPIO。
串口调试的一个利器是printf重定向。标准库里通过重写fputc函数,让printf输出到USART,这样在代码里写printf,电脑串口助手就能看到格式化输出。重定向代码大致是这样:
int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return ch; }这里要注意,发送完数据要等待发送数据寄存器空,否则数据会丢。还有,用MDK标准库时记得在配置里勾选Use MicroLIB,否则printf会占用大量Flash和RAM,还有可能因为堆栈问题死机。
4.4 显示模块的坑:ILI9341读ID是0xA1A1是怎么回事
热词里有“STM32使用ILI9341读ID是A1A1”,这个问题也很有意思。ILI9341是常见的TFTLCD驱动芯片,读ID的时候正常应该返回0x9341,但很多人读到0xA1A1。这说明通信时序上有点问题,大概率是数据线没接对,或者是在读ID前没正常初始化,甚至可能是你手里的屏幕根本不是ILI9341,而是国产的兼容主控。
排查思路一般是先检查接线,尤其是DB0到DB15的数据线有没有次序错位;然后检查复位时序,屏幕的复位引脚要先拉低再拉高,延时足够;再检查初始化序列是不是对应你屏幕型号的厂商校准版本。这类问题不是代码逻辑错误,是硬件时序和器件差异导致的,调试起来要有耐心,用示波器或者逻辑分析仪看一遍波形就能定位。
4.5 I2C和SPI总线,理解总线的握手规则
F103的I2C外设口碑一般,硬件I2C的时序要求苛刻,很多老手宁可用GPIO模拟I2C。模拟I2C其实就是用代码控制时钟线SCL和数据线SDA的电平变化,按I2C协议时序把数据发出去,注意开始信号、停止信号、应答位这些细节。模拟的好处是引脚随便选,调试直观,也不会有硬件I2C那些怪问题。
SPI总线的学习可以配合Flash芯片或者屏幕驱动来做。SPI有四种模式,区别在于时钟极性和相位,主设备和从设备不匹配就会读到全0或者乱码。你需要看好从设备数据手册里要求的CPOL和CPHA取值。比如某些Flash芯片要求模式0或模式3,配置错了通信就是废的。
4.6 CAN通信和USB设备,打开更广的应用空间
CAN通信在工业控制、汽车电子领域用得非常广泛。STM32F103的bxCAN外设支持标准帧和扩展帧,波特率靠分频和位时间配置。很多人搜“STM32 CAN通信突然连不上”,这个问题的排查技巧是:先看CAN收发器(比如TJA1050)的供电和接线,再看波特率是否一致,三看有没有给总线接上终端电阻(120欧姆),最后看硬件滤波和软件滤波配置。CAN总线上如果只有两个节点,至少一端要接终端电阻,否则信号反射会导致通信不稳定。
USB设备方面,F103的USB是符合USB 2.0全速规范的设备控制器,可以做键盘、鼠标、虚拟串口这些设备。做USB设备的一个坑是F103的USB需要外接晶振,而且很多开发板上的晶振可能是8MHz或者12MHz,直接影响USB的时钟,配置不一致时USB枚举不成功。起步阶段建议先跑官方的虚拟串口例程,把USB枚举流程跑通,再改造成自己的设备。
4.7 综合实战项目:超声波测距和步进电机
学完上面这些外设,就可以做点综合性的项目了。超声波测距是一个很典型的练习:用定时器的输入捕获测超声波模块ECHO引脚的高电平时间,再乘以声速除以2得到距离,然后把结果显示在OLED或者串口上。这个项目串起了定时器捕获、GPIO、显示、串口等多个模块,做完一次,整块知识的连接感就建立起来了。
步进电机控制也是非常合适的练手项目,热词里的“五线四相步进电机STM32”就是这个。五线四相步进电机内部有四个线圈,用双极性或者单极性驱动,控制方式是给四相线圈按顺序通电,每换一次相,电机轴就转一步。用GPIO输出脉冲时序表,或者用定时器产生精确脉冲,配合ULN2003驱动模块,就能做匀速转动和定位控制。做这个项目可以顺便理解PWM输出、延时精度和机械传动的基本概念。
5. 常见问题速查表:这些坑我替你踩过了
| 问题 | 原因 | 排查方法 |
|---|---|---|
| 识别不到芯片/下载失败 | BOOT0配置不对;驱动没装;ST-Link接线错误;芯片锁死 | 检查BOOT0跳线;重新装驱动;检查SWD三根线;进入系统存储器模式后擦除 |
| 打开时钟仍然外设不工作 | 引脚复用冲突;误配置了JTAG占用引脚 | 看原理图和引脚复用表;检查PA13/PA14/PA15/PB3/PB4是否被占 |
| 延时函数卡死 | 延时函数用了SysTick且中断冲突;HAL库和标准库混用 | 确认系统时钟配置;检查是否在中断里调用延时;统一库版本 |
| printf没有任何输出 | 串口引脚配错;没有重定向fputc;未勾选MicroLIB;波特率不匹配 | 检查USART引脚;对比重定向代码;打开MicroLIB;核对波特率 |
| 屏幕读ID异常 | 时序问题;复位异常;数据线错位;主控不兼容 | 检查接线;逐行比对初始化序列;用逻辑分析仪看波形 |
| CAN通信突然连不上 | 收发器问题;波特率不一致;缺少终端电阻 | 检查CAN收发器供电;确认波特率;总线两端接120欧姆 |
| USB设备枚举失败 | 晶振频率不对;VBUS连接问题;USB拉电流不足 | 确认晶振;核查USB D+/D-走线;检查电源供应 |
| PB3/PB4做不了普通IO | JTAG默认占用 | 禁用JTAG功能或者仅保留SWD |
这些坑非常典型,我基本都碰到过一遍。很多问题并不是代码逻辑有多难,而是你还没建立起硬件和软件一一对应的那种感觉。遇到问题先别急着怀疑代码,先拿万用表测电平,拿示波器看波形,再回头看代码,定位效率会高很多。
6. 顺着这个方向继续深入,你还能走多远
很多新手学了GPIO和串口之后,就不知道该学什么了。实际上STM32F103只是整个嵌入式世界的一个起点,这个板子带给你的能力是可以直接迁移到更高阶平台的。F103上学会的GPIO、中断、定时器、串口、I2C、SPI,在STM32F4/H7上一样适用,在国产的GD32、AT32、APM32上也是同一套思路,只不过寄存器地址和库接口略有差异。
我自己用过很多芯片之后回头想,F103最好的一点并不是性能有多强,而是资料足够多、生态足够成熟、踩坑成本足够低。一个F103工程能把中断优先级、时钟树、启动文件、链接脚本这些东西全部过一遍,这些底层知识到哪都值钱。
6.1 从裸机到操作系统,进阶的几条路
如果想把F103玩得更深入,可以考虑往这几个方向走。一个是学习使用RTOS,比如FreeRTOS,F103跑FreeRTOS完全没有问题,任务调度、信号量、队列、互斥锁这些概念通过实操理解最深。另一个是引入上位机通信,比如用串口或者WiFi模块把板子采集的数据传到电脑上,再用Python写个显示界面,这就是一个很完整的物联网小项目了。
还有一条路是做电机控制和工业控制方向。F103在伺服电机、步进电机、无刷电机驱动上非常常见,热词里的“STM32控制伺服电机485”就是这种场景。伺服驱动器一般支持RS485总线,用MODBUS协议进行位置、速度、扭矩控制,STM32只需要作为主站发指令,通过AGILE_MODBUS这类开源协议栈就能实现。工程应用价值非常高,也是很多自动化岗位面试会问的内容。
6.2 代码规范和调试习惯,越早养成越好
学到后面你会发现,真正限制你的已经不是语法和技术点,而是开发习惯。我从一开始就吃了不少亏:代码文件命名乱七八糟、全局变量满天飞、修改了程序不写注释,结果过两周回来看完全不知道当时在干什么。
建议从一开始就养成几个习惯:一是每个外设的功能单独放在一个.c和.h文件里,接口函数命名清晰;二是全局变量尽量少用,能用传参和返回值解决的就不要用全局变量;三是程序里保留版本号注释和修改记录,哪怕简单到只是加一行说明;四是每次改动前先备份一个能编译通过的版本,防止改坏了回不去。
调试习惯方面,有一个很实用的技巧:把调试打印信息分级,比如ERROR、WARN、INFO,并且在串口输出里带上时间戳。这个习惯在系统比较复杂的时候能救命,否则你面对一堆printf根本不知道哪条和哪条是对应关系。另外,能用调试器单步就不加printf,能用示波器就不瞎猜,工具越熟练,排查问题越快。
6.3 学习资源的取舍
现在的学习资源比十年前好太多了。买开发板附带的视频和资料一般是最贴合你板子的,建议先跟着配套视频过一遍,按部就班地把点亮LED、按键检测、串口打印、定时器中断、外部中断这几个例程全部自己敲一遍。注意是自己敲,不是复制粘贴,很多细节只有自己敲一遍才会暴露出来。
然后再去看芯片参考手册和数据手册。ST官方的手册写得其实很清晰,比如《STM32F10xxx参考手册》里的GPIO章节会详细列出每个寄存器的位定义和配置模式。刚开始看可能看不懂,但每做完一个例程就回去翻对应章节,你会发现手册越来越看得懂,这是一个螺旋上升的过程。
最后,尽量加入一个技术社区,有问题先搜索再提问。提问的时候把芯片型号、开发环境版本、代码片段、问题现象发全,这样别人才能真正帮你定位问题。不要一上来就问“为什么我的程序不跑”,没有人能凭空知道答案。
7. 写在最后的一些体会
板子买回来只是第一步,后面能学到什么程度,取决于你动手的频率和遇到问题时查资料的耐心。ST的开发板资料已经非常齐全,只要你能耐着性子把每一个例程不看教程就手动敲一遍,遇到报错先自己分析再查答案,基本四到八周就能把GPIO、串口、定时器、中断这些核心内容吃透。
我个人实际玩下来有个体会:嵌入式这行,台上一分钟,台下十年功。芯片型号会更新,库版本会迭代,但底层的那套逻辑——时钟、引脚、寄存器、总线协议、中断优先级——几十年来没有变过。你现在在F103上花的时间并不会白费,迟早会在别的芯片上兑现成更高的效率和更短的调试时间。
最后再分享一个小技巧:学STM32不要贪多,不要今天看USB明天看CAN后天玩屏幕,没有连成体系的知识很快就忘光了。你可以按照“点灯→按键→中断→定时器→串口→I2C/SPI→项目实战”的路线,每一步花三到五天,做完了再做下一个。只要按这个节奏坚持下来,单片机开发的基本功就算打牢了。后面无论去搞家电控制、智能硬件还是工业设备,你都会感谢当初认真折腾F103的自己。