快递拆开那一刻,蓝色板子从静电袋里滑出来,板面上印着“STM32F103C8T6”这排字母。如果你也正好把这样一块开发板买回来了,又不知道接下来该干嘛,这篇东西就是给你写的。我前后折腾过不下十块 STM32 开发板,从最小系统板到正点原子、野火的全功能板都摸过,可以负责任地说:这块 F103 的板子,只要你按顺序走完下面这些步骤,从“点个灯”到“跑一个带中断、定时器、串口打印的小系统”,大概就是两个周末的事。文章里我会把硬件认识、开发环境搭建、时钟、GPIO、中断、串口这些核心东西掰开揉碎讲清楚,还有新手最容易踩的下载失败、芯片锁死、串口乱码这些坑,我都会把排查思路写出来。目标是让零基础的读者也能照着把板子跑起来,并且知道每一步背后的原因。
1. 为什么第一块板子选STM32F103
1.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,只添加你用到的外设即可)、Project(Keil 工程文件目录)。
然后在 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 的时钟树对所有型号来说都是同一种套路:芯片上电后默认使用内部高速时钟 HSI(8MHz),但这只是备用时钟,精度差、稳定性一般。真正的“主时钟”一般选择外部晶振 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 MicroLIB,printf就能直接往串口输出。注意 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,就是带你入行的一块好跳板,把它吃透,后面什么板子都不慌了。