很多朋友第一次接触 STM32,都是被毕设逼的,或者看到实验室学长用它做了个很酷的小车,自己也想试试。但搜了一圈资料,发现网上的内容要么是零散的代码片段,要么是让人云里雾里的数据手册,越看越懵。这个系列就是想把这些年的实战经验梳理清楚,从芯片选型、环境搭建,到实际项目里最容易踩的坑,一条线讲明白,不管你是刚拿到开发板的新手,还是已经在用 CubeMX 生成代码但遇到问题的进阶者,应该都能在这里面找到点有用的东西。这篇先解决"它到底是什么、从哪里开始、以及那些高频问题到底是怎么回事"这几个最基本却最绕不开的问题。
1. 跳出迷宫:STM32 到底是个什么东西,为什么大家都在用
1.1 从 Cortex-M 内核说起
很多教程上来就让你点灯、跑串口,但如果你连"内核、芯片、开发板"这三者的关系都没理清,后面学起来会非常难受。简单来说,ARM 公司只设计处理器内核,它自己不造芯片。它把 Cortex-M0、M3、M4、M7 这些内核卖给意法半导体(ST)、恩智浦、瑞萨等芯片厂商,厂商拿到内核授权之后,再往里塞自己的存储、外设、时钟管理,封装成一颗颗具体的芯片。所以,我们常说的 STM32,不是一颗芯片,而是一个庞大的家族,这个家族里每一颗芯片,都以 ARM 的某个 Cortex-M 内核为"大脑"。
Cortex-M 系列内核是专门为微控制器设计的,它追求的是低功耗、实时响应、低成本,而不是像手机处理器那样追求极致性能。拿内核翻一下 STM32 的分类就很清楚了:Cortex-M0/M0+ 内核主打低功耗和低成本,对应的 STM32F0、L0、G0 系列;Cortex-M3 内核是经典主力,对应 STM32F1 系列,这也是网上教程最多、资料最全的系列;Cortex-M4 内核在 M3 基础上加了 DSP 指令和浮点运算单元(FPU,也就是硬件算小数更快),对应 F3、F4、L4、G4 系列;Cortex-M7 内核性能更强,对应 F7、H7 系列,已经面向高性能应用了。
我在实际项目里的感受是,绝大多数场景根本不需要顶级内核。跑个传感器采集、电机控制、简单通信协议,一颗 M3 内核的 F103 绰绰有余,省下来的钱和功耗才是最实际的。
1.2 STM32 全家族怎么选:F0、F1、F4、H7 和 G 系列
选型是很多新手的第一道坎,也是项目失败的第一步。你去某宝搜 STM32,能出来几百个型号,看着就头大。我给一个简单粗暴的分法:
- STM32F0/G0 系列:M0 内核,主频 48MHz 左右,价格便宜,适合做简单的 I/O 控制、传感器读取。如果你只是做个简单逻辑控制且对成本敏感,选这个系列。
- STM32F103 系列:M3 内核,主频 72MHz,价格适中,有丰富的例程资料,是学习的默认首选。它的定位有点像嵌入式界的丰田卡罗拉——没有惊艳的参数,但皮实耐用,哪都能见到它。
- STM32F407/411 系列:M4 内核,主频 168MHz(F411 是 100MHz),带 FPU 和 DSP 指令,有摄像头接口、更多串口和 SPI,适合做需要一定计算量的项目,比如简单的图像采集、音频处理、实时控制算法。我在调电机驱动和做简单 FFT 频谱分析时,体验明显比 F103 流畅很多。
- STM32H7 系列:M7 内核,主频最高到 480MHz,性能怪兽,能跑比较复杂的算法,甚至可以直接跑点简单的神经网络模型。但这个系列也是出了名的难伺候,供电要求高、引脚复用复杂、调试器也要够好,新手不建议直接上。
G 系列算是一个"后起之秀",它用更新的工艺和更灵活的封装,在低功耗和性价比上做了很多优化。比如 STM32G030 有时候能做到和 8 位单片机差不多的价格,但性能强了一大截,现在很多消费电子产品里都能看到它。所以选型的逻辑不是"越贵越好",而是"够用就好、资料越多越好"。第一次上手,买一块 F103 核心板,是性价比最高的投资。
1.3 为什么说 STM32 的生态才是最大优势
如果你只用过 51 或者 Arduino,可能感觉不到生态的差别。但当你真正开始做项目,遇到一个奇怪的问题,百度一搜全是别人的踩坑记录,那种感觉真的能救命。STM32 最大的优势有两个:一个是 ST 官方提供的 HAL 库和 LL 库,配合 STM32CubeMX 这个图形化配置工具,把引脚复用、时钟树、外设参数这些繁琐的初始化工作,从"手写几百行寄存器代码"简化成了"在界面上点几下生成代码";另一个是庞大的社区资料,从正点原子、野火这些开发板厂商的公开教程,到 GitHub 上无数开源项目,几乎所有你能想象到的应用场景,都有人做过并留下了记录。
所以说,选 STM32 不只是选一颗芯片,更是选了一套围绕它建立的完整资源体系。这也解释了为什么很多公司在产品选型时,宁愿用性能不是最强的 STM32,也不去选一颗资料稀少、遇到问题只能自己啃数据手册的同性能芯片——因为开发效率和风险控制远比那一点点芯片差价重要。
2. 开发环境三岔路:Keil、STM32CubeMX 和 VSCode 该怎么配合
2.1 官方路线:STM32CubeMX 生成工程 + Keil 编译调试
我最开始用 STM32 的时候,还是标准外设库时代,初始化一个串口要手动配置 GPIO、时钟、中断优先级,稍不留神就漏一步,然后程序死活跑不通。现在环境发生了很大变化,官方主推的是 HAL 库,配合 STM32CubeMX 工具,基本思路是:你在这个图形界面里选好芯片型号,配置好引脚功能(比如把 PA9 设为 USART1_TX)、时钟树(告诉它外部晶振是多少 MHz、想跑到多少 MHz)、外设参数(波特率、数据位、校验位),它就能自动生成一套基于 HAL 库的完整工程。
对于新手,我建议这个配置流程必须走一遍,它不是可有可无的辅助,而是理解芯片内部资源的重要途径。举个例子,你在 CubeMX 里把系统时钟从 72MHz 改成 168MHz,它会自动帮你计算 PLL 的分频倍频系数。这个过程会强迫你理解时钟树是怎么工作的,而这恰恰是嵌入式开发最容易出问题的地方之一。
生成的工程怎么编译,目前国内大多还是用 Keil MDK。说实话,Keil 是个很有"年代感"的 IDE,界面老、代码补全弱、还时不时抽风崩溃,但它的调试功能确实好用,尤其是对 STM32 的寄存器级调试、断点设置、变量实时查看,依然是最稳的选择。注意一个容易踩坑的细节:Keil MDK 只支持 ARM 内核芯片,用来写 STM32 没问题,但如果你想同时开发 51 单片机,需要额外装一个 C51 版本,而且两个版本不能同时打开同一个工程文件,需要手动切换。
2.2 VSCode 路线:为什么越来越多人弃用 Keil
很多做嵌入式的老工程师到现在还在用 Keil,但如果你去 GitHub 上看,越来越多的新项目已经开始使用 VSCode + ARM GCC 工具链来开发 STM32 了。理由很直白:VSCode 有现代编辑器应该有的代码补全、代码跳转、Git 集成、终端,调试界面也比 Keil 好看太多。
具体路线是:先用 STM32CubeMX 生成一个 Makefile 类型的工程(CubeMX 支持这个选项),然后用 VSCode 打开,安装 ARM 插件和 Cortex-Debug 插件,配合 arm-none-eabi-gcc 交叉编译器,以及 ST-Link 调试器,就能实现代码编写、编译、烧录、调试的全流程。这套方案里最容易出问题的是 launch.json 和 tasks.json 的配置,当年我折腾了半天,其实核心就是两件事:告诉编译器怎么编译(Makefile 其实已经帮你写好了),告诉调试器怎么连(指定调试器类型、接口、目标芯片型号)。
如果你用的调试器是 DAP-Link 或者 J-Link,在 Cortex-Debug 的配置里需要对应的 debugger 设置。这块确实比 Keil 的"点一下下载"要麻烦,但换来的是舒适的编辑体验和更清晰的编译过程。如果你以后要往 Linux 嵌入式方向发展(比如树莓派、全志、瑞芯微平台的开发),提前习惯 GCC 工具链和 VSCode 流程,是完全值得的。
2.3 PlatformIO 和 Arduino:快速验证想法的捷径
还有一种更"现代"的开发方式,就是用 PlatformIO。它是一个跨平台的嵌入式开发环境,可以装成 VSCode 插件,也可以独立运行。PlatformIO 不仅支持 STM32,还支持 Arduino、ESP8266、ESP32 等几乎所有主流开发板,包管理做得很好,编译和上传都是在命令行里自动完成的。
什么时候用 PlatformIO?我个人的建议是:做原型验证、学习项目、参加比赛时,它非常高效。因为它内置了 STM32 的多种框架(包括 Arduino 框架和 HAL 框架),你甚至可以用 Arduino 的语法来写 STM32——比如直接用digitalWrite(LED_BUILTIN, HIGH)代替 HAL 库的HAL_GPIO_WritePin。这样写的好处是上手极快,坏处是如果你想深入理解寄存器底层的控制逻辑,会被框架挡住一层。我自己的习惯是:学习时老老实实用 HAL 库理解原理,做 demo 和新想法验证时用 Arduino 快速跑通,正式项目则看团队规范而定。
2.4 芯片包安装与 ST-Link 调试器选型
不管你是 Keil 还是 VSCode 路线,都有一个绕不开的步骤:安装芯片支持包。Keil 里叫 PACK,VSCode 里叫 SVD 文件或编译器支持。简单说,只有安装了你手上这颗芯片的支持包,编译器才知道该芯片有多少寄存器、多少外设、存储地址怎么分布。很多人新建工程时报错"Error: Device not found",十有八九就是 PACK 没装或者版本不对。STM32 系列都有对应的 DF PACK(Device Family Pack),去 Keil 官网或 ST 官网下载即可,注意跟芯片型号和 Keil 版本对上。
调试器方面,最推荐 ST-Link V2。它便宜(十几块钱的兼容版就够用)、稳定,而且不仅支持烧录调试,还支持虚拟串口——接上 ST-Link 的 USB,电脑上会多出一个 COM 口,相当于省了一颗 USB 转串口芯片。我自己有一个用了五年的 ST-Link V2,至今没出过问题。如果你用的是 J-Link 或者 DAP-Link,要特别注意:J-Link 的 SWD 接口和 ST-Link 不完全一样,接错脚会烧芯片,烧之前一定要核对好接线。网上那句"玩 STM32 的第一课,先学会看原理图确认第一脚在哪",说的就是这个事。
3. 高频外设实战:那些被搜索了几万次的问题,到底在问什么
3.1 串口与 printf 重定向:调试的第一条命脉
如果说嵌入式开发只能学会一个外设,那一定是串口。它只有 TX(发送)、RX(接收)两根线(地线也算一根),但它的作用巨大:做 log 调试、跟模块通信、和上位机交互,全都靠它。尤其是在没有示波器的情况下,串口几乎是唯一的调试窗口。
但真正的难点在于,串口调试不只是把数据发出去那么简单。我用 HAL 库的时候,最常被问的问题就是"为什么我的串口能收不能发"或者"为什么 printf 没输出"。第一个问题八成是配置里 GPIO 复用功能没配对,比如你让 PA9 作为 USART1_TX,但 CubeMX 里选错成了 USART2;第二个问题则需要做 printf 重定向。这里要说明白一个底层机制:C 标准库的 printf 最终调用的是fputc这个底层函数往输出设备写字符。在 PC 上输出设备是显示器,在 STM32 上输出设备是串口,所以你需要自己重写fputc函数,告诉它:把所有要打印的字符,通过HAL_UART_Transmit写到指定的串口去。代码看起来很简单——
int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); return ch; }但如果你用的是 GCC 工具链(比如 VSCode 路线),光有这段代码还不够,还要处理半主机模式(semihosting)的问题,否则程序会卡死在 printf 调用处。这也是为什么很多人换了 VSCode 之后第一个感觉是"串口怎么不能用了"的根源。
调试时还有一些别的细节要提醒:串口接收时,如果开启了中断接收,但没有及时把接收到的数据保存下来,容易被新数据覆盖;如果用 DMA 接收,要小心缓冲区大小和半满中断的配置。这些坑看起来小,实际调起来能卡一整天。
3.2 ADC 多通道切换:为什么采出来的数据总是乱的
ADC(模数转换)采集在传感器项目里太常见了,但"ADC 切换通道"这个问题在搜索热词里出现,说明很多人踩过同一个坑:采集两路以上的模拟信号,第一路正常,第二路出来的数值总是跟第一路一样,或者来回跳动。
我第一次做多通道采集时也遇到过,后来搞明白了:STM32 的 ADC 在扫描模式下,一轮会连续采集所有配置好的通道,但这"一轮"的时间极短,而且如果在采集过程中切换通道,通道之间的建立时间不够,特别是通道对应的外部源阻抗较大时(比如光敏电阻直接接到引脚上),引脚上的电压还没稳定,ADC 就去采样了,读出来的自然就是上一路的残留电压。解决方案有两个方向:一是降低 ADC 时钟频率,延长采样时间(在 CubeMX 里把 Sample Time 调大);二是不要用扫描模式,每次切换通道后加一点延时再读取——说白了,要给模拟前端一点时间去"反应"。
还有一个更隐蔽的问题是,不同的 ADC 通道可能映射在同一组引脚上(比如 PC0 可以映射到 ADC123_IN10),如果你在 CubeMX 里没有把 GPIO 配置为模拟输入模式,而是保持默认的推挽输出,读出来的数值大概率是 0 或者乱码。所以当你发现问题时,先不要怀疑硬件,回去看 CubeMX 里引脚的颜色是不是已经变成了模拟输入的淡绿色。
3.3 定时器输入捕获测频率:PWM 之外的隐藏技能
定时器几乎是 STM32 里功能最复杂的外设,可以输出 PWM、可以计时、可以做编码器接口,还能用来测频率——通过输入捕获。比如你想测一个方波信号的频率,硬件上没有频率计,用 STM32 的一个定时器就能完成。
原理不复杂:定时器有一个时钟基准(比如 72MHz),你在信号的上升沿触发捕获,记录下当前计数值,下一个上升沿再触发一次,再记录一次,两个计数值的差值除以时钟频率,就是一个信号周期。测量脉冲宽度(占空比)的逻辑也类似,只是配置边沿的触发条件不同。
但实际项目里有个经典坑:信号频率太高,定时器溢出了。比如你用 16 位定时器(计数值最大值 65535),以 72MHz 计数,最快每 0.9ms 溢出一次,超过这个频率的信号直接测不出来。解决方法是配置定时器为级联模式,或者不用定时器,改用外部中断 + SysTick 计算时间差。我做旋转编码器测速时也遇到过类似问题——编码器输出脉冲频率不算高,但如果在中断里做算术运算,中断频率太高会让主循环卡死。那种场景下的经验是:能用硬件定时器捕获,就不要用外部中断计数,因为定时器模块的边沿检测是硬件逻辑,几乎不占用 CPU。
3.4 CAN 通信突然连不上:大概率是收发器的事
车载电子、电机控制、工业现场,CAN 总线几乎是标配。它的好处是两根差分线(CANH、CANL)抗干扰能力强,支持多节点组网,能在一条总线上传输大量设备的数据。但正因为是差分信号,它的调试比起串口要难一些,因为你需要同时关注两个引脚的电平关系。
很多用户的"CAN 通信突然连不上"问题,实际排查时你会发现,代码一模一样,硬件也没改,今天好好的,明天一上电就连接失败。这种情况下,大概率不是代码逻辑问题,而是总线电平状态问题。CAN 协议规定,显性电平就是逻辑 0,隐性电平是逻辑 1,总线上至少要有一个节点定时发送显性电平来维持同步,如果总线上只有一个节点,而且这个节点没做自动重发和错误处理,总线很容易进入 Bus Off 状态。再加上你的板子如果用的是廉价的 CAN 收发器芯片(比如 TJA1050 的替代品),上电瞬间的毛刺就可能导致收发器进入异常状态。
我能想到的最靠谱的排查链路是:第一步用万用表测量 CANH 和 CANL 之间的电阻,正常应该在 60Ω 左右(两个 120Ω 终端电阻并联),如果测出来是 120Ω,说明有一个终端电阻没接或者接错位置;第二步用示波器看 CANH 和 CANL 的波形,看是不是差分对称的;第三步是在代码里打开 CAN 的错误中断,打印 Error Code,看是不是 ACK Error——如果总线上真的只有一个节点,没有其他节点回应 ACK,就算你发数据发到对方嘴里,通信也建立不了,这时候就需要在测试时至少接两个节点,或者打开环回模式(Loopback Mode)。这个坑,真的只有连上 CAN 分析仪一看才知道。
3.5 SPI 读设备 ID 读出来 0xA1A1:经典中的经典
如果你玩过 ILI9341 这类 TFT 液晶屏,大概率遇到过 SPI 读 ID 读出 0xA1A1 的情况。这个数字简直是个通关密语,在 STM32 的讨论区里一搜一大片。
先说结论:读出 0xA1A1,说明你的 SPI 通信没有建立起有效的数据通路,读取到的数据全是高电平(0xFF 取反后的结果,或者取决于具体的 MISO 电平状态),也就是说,屏幕根本没有正确响应你的读命令。排查方向有这么几个,按优先级来:
- SPI 的 CPOL(时钟极性)和 CPHA(时钟相位)配置对不对。ILI9341 手册要求 SPI Mode 0 或 Mode 3,也就是 CPOL=0、CPHA=0 或 CPOL=1、CPHA=1,如果你用的是 Mode 1,屏幕根本不搭理你。这是最高频的原因。
- 读命令和读数据之间需要的时间。有些屏幕对响应读取操作有时间要求,手册里会有 Read Cycle Timing,命令发完之后要等一段时间再读,不然读到的就是空的。
- MISO 引脚是不是已经被 Touch 控制器占用了。很多屏幕模块的 MISO 同时连接了 ILI9341 的 SDO 和 XPT2046 触摸芯片的 DOUT,如果触摸芯片的片选没有拉高,它的输出会跟 ILI9341 的 SDO 打架,导致读回来的数据全乱。
遇到这个问题,我的固定排查顺序是:先看配置(时钟和相位),再看时序(加延时),最后查硬件冲突(触摸芯片或别的挂在同一条 SPI 总线上的设备)。这个思路可以套用到几乎任何 SPI 设备的初始化上,因为 SPI 读寄存器是所有传感器、显示、存储类设备的标准开场白。
4. 新手最容易栽的坑:从芯片实物到代码逻辑一次讲清
4.1 芯片第一脚怎么确认,以及最小系统的几个隐形条件
"STM32 芯片第一脚怎么确认"这个问题,问的人比想象中多得多。其实很简单:芯片正面有一个圆点或者斜角标记,把芯片摆正(让圆点朝左上角),圆点所在的引脚就是第 1 脚,然后逆时针数就是第 2、3、4……脚。如果用到 LQFP 封装,有一个角是缺角的三角形标志,那个角对应的第 1 脚周围,丝印上通常会有一个小点。这个基础常识,在做 PCB 设计或者手工焊接时非常重要,接反了轻则芯片发热,重则直接烧毁。
比引脚更重要的是最小系统。很多人买一块裸芯片准备自己做板子,结果怎么都跑不起来,就是因为最小系统的几个隐性条件没满足:电源要干净——STM32 有多组 VDD 引脚,全部要接到稳定的 3.3V,并且每个电源引脚旁边都要放一个 100nF 的退耦电容,这个电容不能省;复位引脚要接 10kΩ 上拉电阻和 100nF 电容到地,保证上电时能被正确复位;BOOT0 引脚要接下拉电阻到地,否则上电默认从系统存储器启动,而不是从 Flash 启动——这一点很多新手完全没意识到;最后是外部晶振,如果你在 CubeMX 里选择了 HSE(外部高速时钟),但板上没焊晶振,那程序会直接卡死在时钟初始化里。这些条件少一个,芯片就像工作在薛定谔状态——有时候能跑,有时候不能跑。
4.2 delay 卡死、JTAG 被占用、GBK 转 UTF8:三个程序员日常噩梦
delay 卡死:用 HAL 库的
HAL_Delay在定时器中断或回调函数里调用,这个是必死无疑的,因为HAL_Delay底层依赖 SysTick 中断,而 SysTick 中断的优先级默认是最低的,如果你在更高优先级的中断里调用HAL_Delay,SysTick 永远抢不到 CPU,程序就卡死在延时函数里。所以我在中断里从来不用HAL_Delay,改用简单的变量计数,或者干脆用空循环加 NOP(但要小心编译器优化掉)。JTAG 被占用:STM32 的很多调试引脚(PA13/PA14/PA15/PB3/PB4)默认就是 JTAG 功能的,如果你把它们配置成了普通 GPIO,下次插上 ST-Link 调试器你会发现"无法连接",也就是调试器找不到芯片。解决办法是按住板子上的复位键,先点击烧录,在编程器开始擦除的瞬间松开复位键,让芯片在擦除过程中被复位,调试器就能重新连上了。这个技巧我用了好几年,每次不小心把 SWD 引脚废掉都能救回来。
GBK 转 UTF8:这个问题真的折磨过很多人。PC 上写的字符串是 UTF8 编码,但 STM32 默认使用的是 GBK(尤其是 LCD 显示中文时),如果你直接把字符串传给液晶屏显示,全是一堆乱码。解决办法要么是在代码里用一个编码转换函数,要么在编译时加上
--input-charset=GBK --execution-charset=UTF-8之类的编译选项,告诉编译器源代码的输入字符集是 GBK,转换后输出为 UTF8。但这块要特别注意编译器版本,不同 GCC 版本支持的选项不一样,最好在项目里放一个统一的中文编码转换工具集,需要时调用——这样至少不用每次都在编译选项里折腾。
4.3 电机控制、物联网网关、语音和视觉扩展:热词背后的真实项目需求
除了基础外设,那些搜索热词也暴露了大部分用户真正在做的项目方向。我来逐个拆一下:
五线四相步进电机 + STM32:几乎所有 3D 打印机和旧式打印机里都有五线四相步进电机。控制它的核心是用 ULN2003 驱动板,STM32 按顺序给四相绕组通电(A→B→C→D 或 A→AB→B→BC→C→CD→D…的顺序),每切换一步,电机转一个固定角度。实际上我在做的项目里,步数计算很重要:如果你知道步进角是 5.625°/64,步距角约 0.087°,转一圈需要 4096 个半步。如果不用定时器控制换相速度,而只用 delay 函数,频率高了会丢步,频率低了会震动。所以我都会用定时器中断来切相,这样频率精确稳定,加减速也好处理。
伺服电机 485 控制:很多工业项目用的是带 Modbus 协议的伺服驱动器,通过 RS485 总线和 STM32 通信。这块的核心不是电机本身,而是 Modbus RTU 协议的 CRC16 校验。我记得第一次写 Modbus 主机时,因为 CRC 计算错了驱动完全不响应,后来我把 CRC 查表法单独提出来做单元测试,确认无误后再集成才通过。RS485 还有一个特性:收发切换需要时间,发送完必须等发送缓冲区为空后才能把方向引脚拉低,否则最后一个字节会被"腰斩"。
K210 与 STM32 通讯、语音识别、鱼缸等场景:这些项目里有两颗芯片,一个是主控 STM32,一个是 AI 加速芯片(K210)。它们之间的通信方式几乎都是串口,但要注意波特率匹配和数据协议自定义的问题。我做这类多芯片项目时,会自定义一个简单的帧协议来解决粘包问题,比如帧头加设备号加长度加数据加校验,如果解析失败就丢弃重新同步帧头,这个方法在串口通信里非常实用。至于"STM32 鱼缸",本质就是温湿度采集、水泵控制和光照定时这些外围联动,难度不大,但很能培养系统思维——它是小型 IoT 项目的绝佳演练场。
5. 从点亮第一颗 LED 到能独立做项目:一条务实的成长路线
如果你完全是从零开始,我建议不要朝三暮四,按这条路线走,基本四到六周能到达"能独立做小项目"的水平:
- 第一周:环境 + 点灯 + 按键。装好 Keil 或 VSCode,跑通 CubeMX 的配置流程,理解 GPIO 的输入输出模式,做流水灯和按键控制灯亮灭。这一周核心是打通工具链,而不是学多少功能。
- 第二周:中断 + 定时器 + 串口。用定时器做精确延时和 PWM 呼吸灯,用串口跟电脑互发数据,并完成 printf 重定向。这一阶段如果能把串口调试玩熟练,后面所有模块的开发效率都会翻倍。
- 第三周:ADC + 传感器 + I2C/SPI。做温度读取、超声波测距(HC-SR04 测距用定时器输入捕获),用 I2C 读 MPU6050 姿态传感器。这一周你会开始理解"通话协议"(通信时序)这个概念,也能体会到时序不对时模块毫无反应的那种焦虑。
- 第四周:综合项目。做一个两轮差速小车或者环境监测站,把上面学的东西组合起来。这个过程才是真正的学习:你得自己画流程图,分配引脚,处理模块之间的优先级和冲突。如果你能熬过这一周,说明你是真的入门了。
这个过程中,我还想特别提醒"江科大 STM32"系列视频的作者方式,他讲的不是高大上的理论,而是一个引脚一个状态地、一步一步带着你做实验,很多人的第一个 STM32 项目就是跟着他的视频搭出来的。类似的资源还有正点原子和野火的文档,他们都会提供完整的原理图、源码和视频教程,当你卡住的时候,不要只看文字,直接去手动过一遍视频的操作,往往能发现是自己在某个细节上漏了一步。
做毕设或者实际项目的朋友,也不要一上来就选一个特别大的课题。我看到太多人毕设选"智能家居系统",结果摄像头、WiFi、语音控制全都要做,最后每个模块都没调通。我建议把范围尽量收窄,比如先做好"温湿度采集和 OLED 显示",再往上面加联网和控制——小步快跑,每步都有看得见的成果,比什么都重要。
从最开始看 STM32 数据手册像看天书,到后来能根据一篇"ST 官方勘误表"找到芯片手册里的隐藏限制,这个过程其实是所有嵌入式开发者都会经历的。我踩过的坑不下几十个,但正是这些坑让我对每一根引脚、每一个寄存器的脾气摸得比任何文档都透。写这篇文章的过程中,我反复在想,如果我一开始就有人把这几个坑提前告诉我,我可能能少熬十几天夜。所以,真心建议你先把这篇文章收藏,等你在某个问题上卡住的时候,再找出来翻一翻——毕竟,嵌入式这行的常态就是:问题总是出其不意,但解法往往有规律可循。