先说个判断:如果你在电子、嵌入式、自动化这些方向里待过,哪怕只是刚开始接触,“STM32”这个词一定是绕不过去的。它不是什么小众芯片,而是过去十几年里国内单片机学习和产品开发中最常见、最扎实的一条主线。从大学的课程设计、实验室的项目,到工控板、四轴飞行器、平衡车、智能家居网关,甚至很多量产设备的内部主控,都能看到它的影子。
简单说,STM32是一系列基于ARM Cortex-M内核的32位微控制器,市面上能买到的型号超过一千种,价格从几块钱到几十块钱不等。它解决的核心问题非常朴素:用足够便宜的成本、足够简单的开发方式,做出带复杂外设控制、通信、信号采集能力的嵌入式系统。这篇文章不是芯片手册,也不是劝退指南,我打算从一个实际做项目的人的角度,把STM32是什么、该怎么选、该学哪些、会踩哪些坑,一次讲清楚。
1. STM32到底是什么:从8位机到32位机的跨越
1.1 名字拆解:ST、M、32分别代表什么
先把这个名字拆开看。ST是意法半导体(STMicroelectronics),一家总部在欧洲的半导体大厂;M是Microcontroller,微控制器;32是指32位。合起来就是意法半导体生产的32位微控制器。这个命名方式很直白,几乎不需要记忆成本。
但真正让它和传统8位单片机拉开差距的,不是“32位”这个字面数字,而是背后的ARM Cortex-M内核。早期单片机比如经典的8051,是8位内核,一次处理8位数据,主频普遍在12MHz到24MHz,RAM只有128字节到256字节,Flash也就几K。而STM32哪怕是最入门的型号,主频也在48MHz以上,Flash至少16K,RAM至少4K,而且自带硬件乘法器、嵌套中断控制器、DMA、多种通信接口。这不是单纯的“性能翻倍”,而是开发方式从“抠着资源用”变成了“拿外设堆功能”。
1.2 内核与架构:Cortex-M带来了什么
ARM的Cortex-M系列内核专门为微控制器设计,它和手机里的Cortex-A系列完全不同。Cortex-A追求高主频、跑操作系统、跑应用;Cortex-M追求的是低功耗、确定性强的实时响应、简单的编程模型。
STM32主要用的内核有Cortex-M0、M0+、M3、M4、M7、M33这几类。其中最具代表性的是M3和M4。M3内核的主频普遍到72MHz(F1系列),指令效率比51单片机高了不止一个量级;M4在M3基础上增加了FPU(浮点运算单元)和DSP指令,做数字信号处理、电机控制这类计算密集型任务明显更快。M7则更激进,主频能干到400MHz以上,甚至能处理简单的图像和音频任务。
除了内核,STM32的另一个特点是外设资源极其丰富。通用型芯片基本都带USART串口、SPI、I2C、定时器(含PWM输出、输入捕获、编码器模式)、ADC(模数转换)、DMA(直接内存访问)。高端型号还带DAC(数模转换)、CAN总线、USB、以太网MAC、摄像头接口(DCMI)、LCD控制器、加密引擎、SDIO等。以我常用的F4系列为例,一个不到10块钱的芯片,就能同时挂一个TFT屏幕、一个摄像头、两路串口、一组电机PWM、外加若干传感器,这在8位机时代是想都不敢想的。
1.3 和51、Arduino的同场对比
给新入行的朋友一个直观对比,可能会更好理解STM32的位置:
| 对比维度 | 传统51单片机 | Arduino | STM32 |
|---|---|---|---|
| 位数 | 8位 | 8位(AVR)/ 32位(部分板卡) | 32位 |
| 主频 | 12MHz左右 | 16MHz | 48MHz-480MHz |
| 内核 | Intel 8051 | AVR / ARM | ARM Cortex-M |
| 开发方式 | 寄存器为主 | 封装好的库函数 | 寄存器/HAL库/LL库均可 |
| 外设丰富度 | 较少 | 依赖扩展板 | 极高,且多为多实例 |
| 调试手段 | 仿真器较少 | 串口打印为主 | SWD/JTAG硬件断点调试 |
| 价格(裸片) | 1-3元 | 20-100元(板卡) | 3-20元(裸片) |
| 典型场景 | 小家电、简单控制 | 创客教育、快速原型 | 工业、消费电子、复杂系统 |
Arduino的价值是“把你从硬件细节里解放出来”,让通信、点灯、读传感器都变成一行库函数。STM32的价值是“给你足够强大的底层能力”,你想用库就用库,想抠底层就抠底层,上限完全由你自己的水平决定。很多从Arduino转过来的人会觉得STM32起步麻烦——没错,但这麻烦换来的是一套理解真正的嵌入式系统如何工作的能力。比如中断优先级、DMA搬运、时钟树配置、低功耗模式切换,Arduino里看不到的东西,STM32里全都摆在你面前。
2. 选型不迷茫:十几个系列怎么挑
2.1 主线系列定位:F0/F1/F4/L0/L4/H7
STM32的型号非常多,但真正值得普通人重点关注的只有几个系列。我用自己的理解把它们归个类:
- F0系列:Cortex-M0内核,48MHz主频,价格极低,适合做简单控制、IOT节点、替换传统8位机。如果你是要做大批量低功耗产品,F0是经济之选。
- F1系列:Cortex-M3内核,72MHz,最经典的入门系列。F103是几乎所有教程、开发板、毕业设计的“主角”。外设类型全面,资料海量,踩过的坑网上都能搜到。
- F4系列:Cortex-M4带FPU,168MHz(F407)、180MHz(F429),带DSP指令。适合做需要浮点运算、电机FOC控制、音频处理、中级图像采集的项目。F407也是工业应用里特别常见的一颗。
- L0/L4系列:低功耗系列,主打电池供电。L4在低功耗和性能之间平衡很好,适合做可穿戴设备、便携仪表。
- H7系列:Cortex-M7内核,主频最高能到480MHz(部分型号),双核版本还带一个M4协核,适合做复杂AI边缘计算、高性能人机界面、机器视觉这类重负载任务,但是功耗和设计复杂度也更高。
这里必须说一句,选型不是“越贵越好”,也不是“越新越好”,而是“外设需求 + 开发效率 + 采购成本 + 团队熟悉度”的平衡。我见过不少项目用H7的芯片,实际只用到了串口和GPIO,纯粹是杀鸡用牛刀,还白付了更高的BOM成本和更复杂的电源设计。
2.2 新手选型公式:预算、封装、外设、文档
给新手一个务实的选型思路,按下面四个问题一步步过滤就行:
- 预算多少?芯片单价希望在10元以内还是可以接受50元以上?
- 封装能不能手工焊?新手强烈建议选LQFP48或LQFP64这类引脚间距大、不需要热风枪就能焊的封装。QFN、BGA这些封装适合有设备的人,不适合第一块板。
- 需要哪些外设?数一下项目里要用的接口:几路串口?几路ADC?要不要CAN、USB、以太网?按最低需求去匹配型号。
- 教程和例程多不多?冷门型号的例程少,遇到问题排查成本极高。新手期选F103或F407,能让你的学习曲线平滑很多。
以我自己带过的学生为例,第一块板我几乎都让他们选STM32F103C8T6,原因就三条:便宜(散片几块钱)、资料多(整个中文社区都是积累)、引脚少(48脚,适合手工焊接和飞线调试)。等真正做完一个项目,再根据项目需求换F4或者L4都很顺畅。
2.3 一个容易被忽略的细节:芯片命名规则
很多人第一次看芯片丝印会懵,比如“STM32F103C8T6”这一长串到底什么意思。拆开看其实非常有规律:
- STM32:品牌系列
- F:通用型(还有L低功耗、H高性能、G通用型等)
- 103:子系列编号
- C:引脚数,C是48脚,R是64脚,V是100脚,Z是144脚
- 8:Flash容量,8代表64KB,B代表128KB,C代表256KB,E代表512KB
- T:封装类型,T是LQFP,H是BGA,U是QFN
- 6:温度等级,6代表-40到85摄氏度,7代表-40到105摄氏度
看懂了这套规则,你去翻数据手册或者选型器的时候就能快速定位,不至于看到型号就头大。顺便提一句,同型号的不同容量往往引脚兼容,比如F103C6和F103C8都是48脚,画板的时候可以考虑直接留一个通用封装,调试阶段用大容量版本,量产时根据实际烧录量换小容量版本。
3. 开发环境搭建:CubeMX、Keil和VSCode的关系
3.1 标准库、HAL库、LL库的区别
STM32开发绕不开“用什么库”这个问题。我刚接触的时候用的是标准外设库(Standard Peripheral Library),现在已经很少更新了。它的特点是每一类外设都有对应的函数,比如GPIO_Init、USART_SendData,代码透明,适合学习原理,但每次新建工程都要自己搭框架,比较繁琐。
HAL库(Hardware Abstraction Layer)是目前的主流选择。它把外设操作封装成更友好的接口,比如HAL_GPIO_WritePin、HAL_UART_Transmit,配合STM32CubeMX图形化配置工具,可以自动生成整个工程骨架。你只需要拿着鼠标点一点时钟、串口、GPIO,它就帮你把初始化代码全部写好了。这对新手非常友好,对要快速出原型的老手也是效率神器。
LL库(Low Layer library)则是跟寄存器更贴近的轻量封装,代码比HAL更精简、性能更好,但需要你对芯片本身有一定理解。一般建议是:学习阶段先用标准库或者直接看寄存器,理解原理;做产品和项目用HAL + CubeMX;到后期追求极致性能、想省Flash的时候再切LL。
3.2 CubeMX一键生成工程的正确用法
STM32CubeMX是ST官方提供的图形化配置工具,它的核心价值在于把时钟树、引脚复用、外设参数这些极其繁琐的配置图形化。举个真实例子:F407的APB1、APB2总线时钟最高分别是42MHz和84MHz,一不小心把分频系数配错了,串口波特率就会产生误差,进而导致通信乱码。手工查数据手册配时钟,新手很容易配错;CubeMX里面直接选“外部晶振8MHz,系统时钟168MHz”,它会自动算好所有分频和锁相环参数,一点冗余劳动都没有。
用CubeMX新建F103工程的步骤我建议按这个顺序来:
- 打开CubeMX,选择“New Project”,输入芯片型号(比如STM32F103C8Tx)。
- 在“Pinout & Configuration”页面,先配置RCC(时钟),把HSE选择为Crystal/Ceramic Resonator。
- 配置SYS(系统),把Debug选择为Serial Wire,这一步尤其重要,不然下载一次程序之后,仿真器可能就再也连不上芯片了。
- 逐个配置你需要的GPIO、串口、定时器。比如想点灯,就把某个引脚设成GPIO_Output;想调串口,就打开USART1,波特率设为115200。
- 在“Project Manager”里选择工具链为MDK-ARM,版本选V5或V6,然后点击GENERATE CODE。
- 生成之后用Keil打开工程,把代码补进主函数,编译、下载、收工。
整个过程熟练的话五分钟就能完成。但我得提醒一句:CubeMX生成的是“起点”,不是“终点”。它把你从重复劳动中解放出来,但最终的设计能力依然来自你对外设寄存器、中断机制、时序的理解。很多人用了CubeMX之后只会点鼠标,不懂底层,一旦遇到芯片手册上没提到的边界情况就束手无策,这算是工具带来的一个副作用。
3.3 Keil与VSCode:真刀真枪写代码的环境选择
Keil MDK是STM32开发最主流的环境,界面老、功能也谈不上优雅,但它和调试器(J-Link、ST-Link)的配合最稳定,生成烧录文件、在线调试、查看寄存器变量都非常方便,很多公司项目至今仍然用它。
如果你实在不喜欢Keil的界面,现在VSCode + EIDE插件或者PlatformIO也都能开发STM32。EIDE插件在国产工具链里做得很好,支持J-Link烧录和调试,配置launch.json之后甚至可以在VSCode里打断点看变量。不过需要提醒的是,VSCode的STM32调试环境在第一次配置时会有一定门槛,涉及编译器路径、调试器接口、工程文件格式等问题,建议至少先把Keil流程跑通一遍,再用VSCode作为效率增强工具。
4. 核心外设与经典项目案例
4.1 GPIO:点灯背后的温度与中断
所有STM32入门的第一步几乎都是点灯,但GPIO并没有看起来那么简单。STM32的GPIO有八种工作模式:输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、推挽输出、复用推挽、复用开漏。
推挽输出和开漏输出的区别值得多说两句。推挽输出可以主动输出高电平和低电平,驱动能力强,接LED、继电器、逻辑输入都没问题。开漏输出只能主动拉低,高电平是靠外部上拉电阻提供的,所以它非常适合“线与”逻辑和多设备共用总线(比如I2C)。如果你拿开漏方式去直接驱动LED,会发现灯根本不亮——这就是新手常踩的第一个坑。
GPIO的另一个关键点是外部中断EXTI。STM32不是所有引脚都能任意映射到中断线,同一组GPIO的多个IO共享一条EXTI线,需要检查引脚是否能够同时工作在中断模式下。做个简单按键触发可以,但如果每个按键都要产生独立中断,就要在引脚选择和硬件设计阶段提前规划好。
4.2 定时器:PWM、输入捕获、编码器
定时器是STM32里最灵活也最考验理解能力的外设之一。F103有基本定时器(TIM6/7,只负责计时)、通用定时器(TIM2/3/4/5,支持PWM、输入捕获、输出比较)、高级定时器(TIM1/8,额外支持互补输出和刹车功能,常用于驱动电机)。
PWM的频率计算是一个必须掌握的基础技能。以F103、72MHz的通用定时器为例,如果PSC预分频器设为71,计数器时钟就是72MHz / (71+1)=1MHz,也就是1微秒计数一次;如果ARR自动重载值设为999,那PWM周期就是(999+1)×1微秒=1毫秒,即1kHz。改变CCR比较值就能改变占空比。这个计算方法在很多项目中都会反复用到,建议直接背熟。
在热词里看到“stm32定时器捕获测频率”和“五线四相步进电机stm32”,这两个都是定时器的典型应用。测频率的核心思路是:用输入捕获通道检测上升沿,记录两次上升沿之间的计数器差值,再根据定时器时钟频率反推信号周期。测量精度取决于定时器分辨率,F103的72MHz主频下,理论上可以测到接近微秒级别的时间差;如果被测信号很快,还可以做多周期计数平均,进一步提高精度。步进电机控制则更依赖PWM输出的准确性和GPIO换相逻辑,五线四相步进电机需要按“A-B-C-D”四相顺序通电,用定时器生成固定频率的脉冲即可控制转速,脉冲数决定转角,方向则由换相顺序反向来实现。
4.3 串口与I2C/SPI:和外设打交道的基本功
串口(UART)是STM32调试和通信的生命线。调程序最常用的手段就是往串口打印调试信息。新手用HAL库时,最容易出错的地方有两个:一是波特率配置与时钟不匹配导致乱码,二是阻塞式的HAL_UART_Transmit在高速通信时会占用大量CPU时间。进阶做法是用DMA驱动UART收发,或者在RTOS里把串口放到独立任务中,这样通信数据量大时主逻辑不会被拖垮。
I2C和SPI则是外设传感器、屏幕、存储器最常用的接口。I2C走两根线(SCL、SDA),速度一般在400kHz左右,适合连接温湿度传感器、气压计这类数据量不大的设备。SPI走四根线(SCK、MOSI、MISO、CS,部分器件还要RESET、DC等控制引脚),速度可达几十兆赫兹,适合TFT屏幕、Flash存储、SD卡这类高速设备。
以热词里的“stm32使用ili9341读id是a1a1”为例,ILI9341是常见TFT屏幕的驱动芯片。读它的ID正确做法是:发送0x04命令获取ID,正常情况会读取到0x93、0x94等值,如果读到0xA1A1,通常说明SPI引脚的接线或者读取时序不对,比如MISO被拉死了、CS片选没有正确拉低、或者屏幕接线有虚焊。这种问题在驱动屏幕上非常典型,排查方向应当优先是硬件连接而非代码逻辑。
4.4 ADC、DMA、CAN:进阶玩法的关键词
ADC(模数转换)是读取电压、电流、温度等模拟信号的核心。STM32的ADC是12位逐次逼近型,也就是说输入电压0-3.3V会被映射成0-4095的数值。读取电池电压、NTC热敏电阻、光敏电阻都是ADC的典型场景。F4/H7系列的ADC采样率更高,部分型号还带差分输入,测小信号时性能更好。
DMA(直接内存访问)的意义在于解放CPU。比如你要定时采集一组ADC数据,传统写法是CPU不断触发转换、等标志位、读数据,全程占用CPU;用DMA的话,ADC转换完成后数据会自动搬到内存数组里,转换完成中断里只需要处理结果,CPU可以在数据搬运期间继续跑其他代码。看起来省的不多,但在数据量大或者多任务并行的场景里,DMA就是“能不能跑起来”和“跑起来卡不卡”的分界线。
CAN总线则是工业领域的关键外设。STM32很多型号集成了bxCAN控制器(支持CAN 2.0A/B),配合TJA1050这类收发器,就能在一条两线差分总线上挂几十个节点,适应远距离、强干扰环境。热词里“stm32 can通信突然连不上”是工控现场非常经典的故障,常见原因包括:终端电阻缺失或重复配置、波特率不一致、CAN_H和CAN_L接反了、总线被某个节点破坏性拉死。排查时不要急着测软件,先把万用表打到通断档,量一下总线两根线之间是否有约60欧姆阻抗——如果开路,说明120欧终端电阻没接好;如果是0欧姆,说明两条线之间短路了。
5. 新手必踩的坑和排查实录
5.1 JTAG/SWD引脚被占用后的自救
STM32的调试接口(JTAG/SWD)默认复用在一组固定的引脚上:PA13/PA14(SWDIO/SWCLK),PA15/PB3/PB4(JTAG的JTDI/JTDO/JTRST)。如果你在代码里把这些引脚配置成了普通GPIO去点灯或者读按键,程序烧进去之后,调试器可能就再也连不上芯片了,这就是常说的“把调试口占用了”。
这个坑的解法其实很简单:在CubeMX的SYS配置里把Debug选成Serial Wire,调试器就会走SWD协议;同时避免在代码里复用PA13/PA14。但如果已经烧进去了怎么办?办法是按住复位键,点击下载,在芯片复位松开的瞬间立刻开始下载操作,让bootloader在用户程序运行之前接管芯片,然后烧录一版不占用调试口的程序,就能恢复。这就是为什么我前面强调,新建工程第一件事就是配置SYS的Debug模式。
5.2 CAN总线失联的常见原因
CAN通信的“突然连不上”让我多讲几句。CAN是差分总线,靠CAN_H和CAN_L的电压差表示逻辑,只接一根线或者接反了,虽然不会立即烧掉收发器,但通信一定失败。此外,CAN总线两端必须有120欧姆的终端电阻,如果多节点网络中有人重复加了多个终端电阻,电平差会被拉低,距离一远就会丢帧甚至完全不通。
排查步骤我建议固定成一个顺序:首先用示波器或万用表测量CAN_H和CAN_L之间的静态电压,正常约为2.5V,发送时会在1.5V到3.5V之间跳动;然后检查总线上两个终端电阻是否都完好接入;接着在代码里确认所有节点的波特率完全一致,然后把预置的诊断信息打印出来,检查CAN发送失败后的错误状态寄存器(ESR),里面记录的错误类型能快速缩小范围。很多情况下,“突然连不上”其实是初始化时没做错误恢复处理,总线上一旦积累错误帧,控制器会自动进入Bus Off状态,必须在代码里做好总线恢复机制,比如延时后重新请求上线或者软复位CAN外设。
5.3 ILI9341读ID是0xA1A1的真相
这个热词我在前面提到过,再展开一下。ILI9341是TFT屏幕的常见驱动IC,正常读ID应该得到0x93、0x94等值,“读ID是a1a1”听起来像是一串有规律的字节,但其实它是SPI接口在“没人回话”的时候读到的高低电平组合(通常是因为MISO悬浮被上拉到了高电平)。换句话说,不是芯片的ID真的是A1A1,而是你的读操作根本没有获得有效数据。
排查方向一般有三步:第一步查接线,SPI四根线的连接顺序和屏幕模块固件定义可能不一致,尤其是DC引脚(数据/命令选择)如果接到错误的GPIO,读ID的命令可能被当成写像素数据来处理;第二步查SPI模式,ILI9341通常要求SPI模式0(CPOL=0,CPHA=0),如果配成了其他模式,时序直接错乱;第三步测焊接有没有虚焊,TFT屏幕排线非常细,手工焊很容易出现一脚不导通的情况。经验上,九成这类问题的根因都在硬件,而不是代码。
5.4 delay()卡死的隐蔽原因
“stm32延时函数delay卡死”这个热词也很典型。F103的老工程里经常用SysTick做毫秒延时,SysTick是ARM内核里的系统定时器,它和应用代码共享优先级。如果某个中断服务函数里关了全局中断(__disable_irq)却没有在延时前恢复,SysTick中断就无法触发,delay里那个while循环就永远等不到标志位置位,程序就死在那里了。
更隐蔽的是HAL库的HAL_Delay,它依赖HAL_GetTick(),而HAL_GetTick()的值来自SysTick中断累加。如果你在一段关中断代码里调用HAL_Delay,就会卡死;如果在某个高优先级中断里调用它,也会因为SysTick中断优先级比它低而卡住。解决办法有两个:要么在中断里不要调用阻塞延时,改用状态机或标志位;要么把SysTick中断优先级调到最高,同时保证关中断代码块里不调用任何延时函数。这是RTOS环境下尤其容易犯的错误,排查思路可以概括为“看延时函数依赖的是哪个时钟,再看这个时钟的中断有没有被打断”。
6. 2025年的STM32学习路线
6.1 经典路线:裸机、外设、RTOS、项目
网上关于STM32的学习路线已经有很多版本,但核心主线一直没有变过,就四步。
第一步,裸机点灯和GPIO:理解芯片怎么被初始化、主循环怎么跑、引脚怎么控制。 第二步,外设逐个击破:串口调通、定时器PWM调通、ADC采集一个模拟量,这三大件掌握之后,任何开发板项目基本都能玩了。 第三步,中断与DMA:用中断处理按键、串口接收、定时器溢出,用DMA搬运大块数据,体会“事件驱动”的编程思路。 第四步,RTOS与工程化:跑一个轻量级RTOS(比如FreeRTOS),理解任务、信号量、队列、互斥锁,然后做一个相对完整的项目,比如两轮差速小车、智能鱼缸控制系统、四轴飞控的上位机通信。
不要直接跳到最后一步。我见过太多人一开始就上FreeRTOS,结果连中断优先级和临界区都不知道怎么回事,任务之间互相干扰,最后整个项目变成一团乱麻。先把裸机思维理顺,再引入操作系统,你会突然发现RTOS其实是让事情变简单的工具,而不是负担。
6.2 新工具链与新方向
2025年的STM32开发环境已经比十年前友好太多了。CubeMX + HAL库成了事实上的主流组合,AI代码补全工具(比如通义灵码、GitHub Copilot)对嵌入式C语言的支持也越来越好,很多模板化代码和寄存器配置可以直接靠AI辅助生成,效率提升非常明显。
新方向上,热词里“stm32与K210通讯”“stm32 H743 dcmi”“stm32 FOC代码”都指向一个趋势:STM32开始越来越多地和AI芯片、图像处理、高性能电机控制结合。比如H743自带DCMI摄像头接口,可以直接采集摄像头数据做简单的色块识别和图像预处理;FOC(磁场定向控制)则需要高频率的ADC采样、PID运算和PWM输出,对芯片的计算能力和外设协同能力提出了很高要求,而这恰好是M4/M7内核带FPU的优势所在。
我建议学有余力的朋友关注两个方向:一是无线通信与云端,STM32加ESP8266或ESP32实现物联网上报下发,MQTT协议、HTTP请求、JSON解析都是实际产品里频繁用到的技能;二是电机控制,步进电机、BLDC、伺服电机的驱动和控制贯穿了整个智能制造行业,薪资和项目含金量都比较可观。
6.3 几条个人建议
最后说几条我在实际项目中攒下来的个人体会。
第一,买开发板不如画板子。入门阶段买一块二十块钱的蓝色板子(F103C8T6)就可以开始学。等你真正需要做项目的时候,我的建议是花点时间自己画一块PCB,电源电路、晶振、复位、SWD调试接口是单片机的生命线,亲手焊一遍、跑一遍,你会对这些细节有完全不同的理解。
第二,用示波器比用万用表多一步。很多通信问题、PWM占空比问题、时序问题,用万用表看不出来,示波器一量就真相大白。入门示波器几百块钱就够用,这是非常值得的投资。
第三,建一个自己的代码仓库。把每个项目里用过的模块封装成通用驱动,比如OLED显示、DS18B20温度、BH1750光照、超声波测距(HC-SR04)、电机驱动,下次做新项目直接复制粘贴改引脚。时间长了,你会发现自己写代码的速度越来越快,调试也越来越有节奏感。
第四,坚持把问题记录下来。嵌入式调试里最耗时间的往往不是“改代码”,而是“排查问题”。把自己的排查过程写成笔记,一方面能加深理解,另一方面,很多问题过了三个月再遇到,你可能连当时的思路都想不起来了。笔记是最好的第二块硬盘。