开发板拿到手的第一天,我就给它换了个家——从纸箱里取出来,静电袋还没撕完,板子已经被我举到灯光下翻来覆去看了好几遍。STM32F103,这个名字在嵌入式圈子里几乎等同于“入门标配”,无数人第一次点灯、第一次跑串口、第一次做小项目,都是从这片板子开始的。我这次入手的就是一块经典的STM32F103开发板,接下来打算把整个学习路线、外设玩法、踩坑记录都陆续整理出来。这篇内容既是给自己做知识沉淀,也是给想入坑STM32的朋友一份参考地图,从开箱到跑通常见外设,全部是实测过的路径。
1. 板子到手先别急着插电:开箱检查与第一印象
1.1 为什么选STM32F103而不是C8T6或者H7
很多新手在选板子的时候会被型号绕晕,这里我直接说结论:STM32F103系列是学习曲线最平缓的选择。它基于ARM Cortex-M3内核,主频72MHz,Flash从64KB到512KB不等,RAM从20KB到64KB,这个配置在上位机、传感器、电机控制、简单的协议处理等场景下完全够用。相比之下,F4系列主频高、带DSP和FPU,H7更是双核加高主频,性能确实强,但对新手来说反而容易迷失——外设太多,中断优先级系统更复杂,功耗和PCB布线的坑也更深。F103的寄存器手册、库函数、例程资料、网上教程数量多得惊人,你遇到任何问题,基本都能搜到解决方案。
我选的这块板子是经典的“最小系统板+外设扩展”结构,上面除了芯片本身,还带了USB转串口芯片、一颗8MHz晶振、复位按键、BOOT选择跳线帽,以及一排排的排针引脚。板子背面丝印很干净,每个引脚都标了对应的GPIO编号,比如PA0、PB5这种,这对后续接线和查手册来说太重要了。不要小看这些丝印,很多廉价板子丝印模糊甚至标错,会让人排查半天。
1.2 上电前的三个检查步骤
拿到板子之后,别急着插线,先做三件事。第一,检查板子上的跳线帽是不是都在正确位置。常见的是BOOT0和BOOT1的跳线,正常运行时BOOT0要接GND,如果它在VCC位置,上电后会进入系统存储器引导模式,你会发现程序烧不进去或者跑的都是默认的ISP程序。第二,确认USB转串口芯片型号,常见的是CH340和CP2102,这两种芯片的驱动不通用,系统不识别的时候先看看是不是驱动问题。第三,用万用表量一下3.3V和GND之间的电阻,正常应该在几十到几百欧姆之间,如果接近短路就要警惕,可能是焊接问题或者芯片已经损坏。
插上USB线之后,电脑应该会识别出一个串口设备,设备管理器里能看到对应的COM口编号。这里有个小细节:如果你用的是CH340,系统第一次连接时需要安装驱动,Windows会提示“设备未识别”,这是正常的,去WCH官网下载对应驱动装上就好。不要慌,这一步卡住的人特别多。
注意:MCU芯片的供电电压是3.3V,但USB口输出的是5V。板子上的USB转串口芯片通常带LDO稳压器,会自己把5V转成3.3V,所以直接插USB供电没问题。但如果你同时用外部电源和USB供电,务必先断开其中一个,否则电压叠加很容易烧芯片。
2. 环境搭建别踩坑:Keil、芯片包与标准库的完整安装流程
2.1 Keil MDK的版本选择与安装细节
STM32开发最主流的IDE还是Keil MDK,虽然VSCode + GCC的组合这两年越来越火,但Keil在下载调试、查看外设寄存器、生成工程方面仍然是最省心的方案。我这里用的是Keil MDK 5.x版本,注意它和Keil C51不是一个软件,前者是ARM内核用的,后者是8051内核用的,两者虽然都叫Keil,但完全独立安装互不相干。
安装的时候有几个要点。第一,安装路径不要带中文和空格,建议直接装到D盘根目录比如 D:/Keil_v5,后面你会感谢这个决定,因为很多GCC工具链和脚本对路径的解析能力非常脆弱,中文路径会引发各种莫名其妙的问题。第二,安装过程中如果弹出安装驱动或者PACK的选项,先全部跳过,等主软件装完再手动添加。第三,激活和License的问题我不多说,但请一定使用正版授权或评估版本,这是基本的合规意识。
2.2 芯片支持包(PACK)的安装与路径问题
Keil本身不内置STM32的设备支持,它需要通过Pack Installer来安装对应芯片的Device Family Pack。打开Pack Installer有两种方式:一种是Keil菜单栏的Project -> Manage -> Pack Installer,另一种是直接运行安装目录下的PackInstaller.exe。在Pack Installer里找到STMicroelectronics -> STM32F1 Series,展开后选最新的版本安装。
这里有一个新手最容易卡住的地方:Pack下载慢或者下载失败。原因多半是网络访问国外服务器不稳定。解决方案有两个:一是用Pack Installer自带的“Import”功能,从本地手动导入已经下载好的.pack文件;二是直接在搜索引擎找到对应Pack的镜像下载源。安装Pack之后,在Keil的Device选项卡里就能看到STM32F103C8、STM32F103RCT6、STM32F103ZET6等具体型号了。选什么型号取决于你的板子丝印或包装盒上的标注,核心板最常见的是C8T6和RCT6。
提示:如果新建工程时选错了芯片型号,后面烧录时会提示“Flash Download Failed”或者“No Target Connected”,排查时先检查Device选型,而不是急着怀疑板子坏了。
2.3 标准库(StdPeriph_Lib)还是HAL库?新手的选择策略
这是一道经典的“送命题”。我的建议很明确:学习阶段优先用标准外设库,也就是StdPeriph_Lib,也叫SPL库。原因有三个:第一,标准库的命名非常直观,比如GPIO_Init、TIM_Cmd、USART_SendData,每一个函数做什么一目了然,对理解寄存器操作有巨大的帮助;第二,网上十年积累的教程和例程绝大多数都是基于标准库写的,你遇到问题搜出来的代码能直接复用;第三,标准库的代码量小,不依赖CubeMX生成那一堆抽象层代码,编译速度快,逻辑链路短,适合新手追踪程序执行流程。
HAL库也不是不好,它胜在跨芯片移植方便,配合STM32CubeMX可以图形化配置时钟树和引脚,生成工程代码的效率极高。但它的层次封装重、回调函数多、初始化流程复杂,新手往往会在HAL_UART_Transmit和UART_Receive_IT的配合关系上绕圈子。等到你用标准库把GPIO、定时器、串口、中断这些基础吃透了,再切换到HAL库和CubeMX做快速原型开发,会平滑很多。不要贪多,先把一条路走通。
2.4 新建工程的完整步骤与烧录配置
新建标准库工程其实不难,但步骤繁琐,我建议固定一套流程,避免每次重复踩坑。第一步,在Keil里选择Project -> New uVision Project,命名工程名(比如“01_LED_Blink”),保存到项目文件夹。第二步,在Device里选好芯片型号。第三步,因为标准库不通过Pack自动安装,需要手动把标准库源码复制到工程目录下的Libraries文件夹,包含CMSIS核心头文件、启动文件(startup_stm32f10x_hd.s或md.s取决于你的芯片)、以及STM32F10x_StdPeriph_Driver里的inc和src目录。第四步,在工程管理里添加Group,把对应.c文件加进去,同时配置头文件包含路径(C/C++选项卡里的Include Paths)。第五步,在C/C++选项卡里定义宏:USE_STDPERIPH_DRIVER, STM32F10X_MD(或HD),这是标准库的条件编译开关。第六步,配置Debug选项,选择ST-Link或者J-Link,并在Utilities里勾选“Reset and Run”。这样烧录后程序会自动运行,不用每次手动复位。
这几个步骤第一次做会有点晕,但做三次之后你就会发现,其实核心就三件事:包含路径对不对、宏定义对不对、启动文件选没选对。后面我会单独写一篇保姆级工程创建流程,把每一步截图配齐。
3. GPIO点灯与延时函数:从“卡死”到真正理解
3.1 点灯不是无聊的开始,而是外设操作的“最小闭环”
在STM32的世界里,点灯这件事跟Arduino那种直接digitalWrite完全不同。你必须在代码里先启动GPIO的时钟(通过RCC_APB2PeriphClockCmd),再配置引脚模式(GPIO_InitStructure里的Pin、Mode、Speed),最后才能调用GPIO_WriteBit或GPIO_SetBits操作电平。这一套流程下来,你其实是在练习所有外设共有的操作逻辑:开时钟、配寄存器、操作数据。后面你用I2C、SPI、UART,本质上都是同一套思路。
很多教程会把GPIO模式分成输入浮空、输入上拉、输入下拉、模拟输入、推挽输出、开漏输出、复用推挽、复用开漏这八种,刚开始记不住很正常。我的建议是先用两个:输入上拉和推挽输出。按键扫描用输入上拉,LED控制用推挽输出。等这两招用熟了,再慢慢去琢磨开漏输出在I2C和电平转换里的妙处。
3.2 延时函数delay卡死的两个经典原因
热词里有一条“stm32延时函数delay卡死”,这几乎是每个人都遇到过的问题。我结合自己的经验,总结出两个最常见的原因。
第一个原因:没有初始化SysTick定时器就调用延时函数。在标准库的例程里,延时函数通常依赖DelayInit()或者SystemCoreClock的时钟配置。如果你直接复制了一个Delay_us或者Delay_ms函数,但是没有在main函数里先调用初始化函数,那么SysTick计数器根本不会跑,程序就像死循环一样卡在那里。排查方法很简单:单步调试时查看SysTick->CTRL寄存器的第16位(COUNTFLAG)是否有变化,或者直接把延时函数体注释掉,看主流程能否跑通。这个坑的本质是“依赖关系没满足”。
第二个原因:中断服务函数里调用延时函数。很多新手会在定时器中断或者外部中断回调里写Delay_ms,然后发现程序卡死。原因是SysTick的优先级通常设置得比当前中断低,当中断被打断后,SysTick中断一直无法响应,延时永远走不到头。正确的做法是:中断服务函数里绝对不要用不依赖于中断的延时函数,处理完标志位和数据就立即返回,让主循环去处理耗时的逻辑。
3.3 关于RCC时钟:你第一眼看到的“SystemInit”到底干了什么
在标准的main函数里,一般会看到SystemInit()这个函数,它并不是Keil自动加进去的,而是标准库启动文件里的调用。它的作用是:把系统时钟从默认的HSI切换到HSE(外部高速晶振),然后配置PLL倍频到72MHz,并把AHB、APB1、APB2的分频系数设好。启动文件在调用main之前就已经把SystemInit执行完了,所以你在main里通常看不到它,但它决定了整个芯片的运行节奏。
APB1和APB2的最大允许频率不同,APB1最高36MHz,APB2最高72MHz。这也是为什么UART1和UART2不能直接用同一个波特率计算方式的原因,因为挂在APB2上的USART1用的时钟可能是72MHz,而挂在APB1上的USART2用的可能是36MHz。你在配置波特率寄存器时要注意这个区别,否则串口输出乱码的概率极高。
4. 从热词看常见应用:USB设备、超声波测距与定时器捕获
4.1 STM32如何做USB设备:比你想象的要麻烦,但也没那么恐怖
热词里有“stm32 如何做usb设备”,这个问题很典型。STM32F103内部有一个USB 2.0全速外设,可以当作USB设备接入主机,比如做成USB键盘、USB鼠标、USB串口(CDC类),或者自定义的HID设备。但它的USB模块和USB OTG不太一样,没有内置的PHY,也没有VBUS检测等功能,需要外部接1.5k上拉电阻到D+引脚,才能让主机识别到设备连接。
做USB设备最崩溃的地方在于USB协议栈的处理。你不光要配置端点、描述符、回调函数,还要处理各种控制传输的枚举流程。好在官方提供了USB固件库,例程里就有HID键盘、虚拟串口(VCP)、大容量存储(MSC)等现成的模板。我的建议是:先用虚拟串口(CDC)模式练手,因为它不需要写任何上位机代码,直接用串口助手就能看到数据,验证枚举和收发过程特别直观。等你能把数据从板子发到电脑,再反向收回来,USB的神秘感就消失了大半。
4.2 定时器捕获测频率:输入捕获的实用价值
定时器除了做延时、产生PWM,还有一个很重要的功能就是输入捕获。通过配置定时器为捕获模式,可以测量外部信号的频率和脉宽。这个功能在测速、解码遥控器、测量PWM占空比时非常有用。STM32F103的定时器支持通道1到通道4,可以配置为上升沿捕获、下降沿捕获或者双边沿捕获。捕获到边沿时,定时器会把当前计数器值锁存到捕获寄存器里,同时可以触发中断。
做输入捕获测频率的关键是:要计算两次上升沿之间的定时器计数差值,再除以定时器时钟频率得到周期,然后取倒数得到频率。这里最容易出错的是计数器溢出。如果你的输入信号频率很低,两次边沿之间的时间超过了定时器最大计数值(16位定时器最大65535),那就需要开启更新中断,用溢出次数来扩展计数范围。这个“溢出补偿”的思路,几乎是所有测频测距项目的必备技能。我在做超声波测距的时候就遇到过这个问题。
4.3 STM32超声波测距:经典HC-SR04的完整处理逻辑
超声波测距模块HC-SR04几乎是每个STM32玩家的第一课。它的原理非常简单:给Trig引脚一个10us以上的高电平脉冲,模块内部会发射超声波,然后Echo引脚会返回一个高电平,高电平持续的时间就是超声波从发射到接收的总时间。距离 = 高电平时间 × 声速340m/s / 2。
这里的关键不在于发射,而在于精准测量Echo高电平的持续时间。最可靠的方式就是使用定时器输入捕获:配置定时器为上升沿捕获,触发中断后切换为下降沿捕获,下降沿到来时读取当前计数值,两个值相减再换算成时间。另一个方式是用外部中断加一个软件计时循环,但这个方式误差大且容易受中断优先级影响,我不推荐。实测下来,HC-SR04模块在30cm到1m范围内的测量精度还是不错的,超过2m后由于波束发散和回波衰减,数据会明显波动,可能需要用多个回波取中值滤波。你如果只是做倒车雷达这类简易项目,F103的捕获能力完全够用。
5. 显示与编码问题的背后逻辑
5.1 ILI9341读ID是a1a1:一个引脚驱动短路的典型排查案例
热词里提到“stm32使用ili9341读id是a1a1”,这个问题我遇到过,而且相当经典。ILI9341是一款很常见的TFT LCD驱动芯片,分辨率240×320,通过SPI或并口和MCU通信。很多时候我们会先写一段读ID的代码来验证初始化是否正确,正常情况下应该读出0x9341,但如果你读出来的ID是a1a1,说明通讯链路出了问题,常见原因是D/C引脚(数据/命令选择)没有配置正确,或者SPI的时序太快导致数据错位。
解决思路分三步:第一步,降低SPI时钟频率,很多初始化失败都是因为SPI跑得太快,LCD控制器跟不上;第二步,仔细检查D/C和CS引脚的GPIO配置,确认模式是推挽输出且初始电平正确;第三步,用逻辑分析仪抓SPI波形,对比时序图看MISO上的数据是不是正确的24位ID。读ID时通常会先发送0xD3命令(读ID4命令),然后在三个字节内依次读到型号、版本和生产商信息。如果你是按照别人的例程接线但读不到,先检查引脚是否接对,再看初始化序列里是否需要额外的延迟。这个排查过程比单纯“重装驱动”更能帮助你理解SPI协议。
5.2 STM32 GBK转UTF8:嵌入式里那点Pitfall
做屏幕显示或者与服务器交互时,经常碰到编码问题。“stm32 gbk转utf8”这个热词背后,是无数做物联网项目的人踩过的坑。STM32的数据源可能来自串口接收、DHT传感器、GPS模块,也可能是从SD卡读取的文件,它们的字符串编码不一定统一。最典型的就是显示中文时,如果不做编码转换,屏幕上会出现乱码,或者发送到服务器的数据变成一堆奇怪的字节。
GBK和UTF8之间的转换不是简单的按字节替换,而是要查表。GBK采用双字节编码,UTF8对汉字部分通常采用三个字节,两者之间没有线性换算关系。嵌入式环境里一般有两种做法:一是预先把需要显示的字符串转成UTF8编码再写进代码,这样运行时不做转换;二是挂一张映射表,在运行时临时转换。第一种做法适合字符串量少的项目,第二种适合动态生成内容的项目。编码转换没有捷径,但可以借助一些开源的量化表格或者Python脚本在PC端预生成数组,下载到MCU里查表,效率很高。这个问题的核心认知是:UTF8和GBK的“可见字符串”相同,但字节流完全不同,调试串口输出时一定要确认PC终端的编码设置和板子一致,否则你会看到一篇乱码。
6. 通信接口与典型问题排查
6.1 UART管脚定义与printf重定向
UART是嵌入式开发中最常用、也最容易被忽略的通信接口。很多人用STM32与PC通信,用的就是串口转USB模块。F103上有USART1到USART3,还有UART4和UART5。每个串口的引脚映射还不完全一样,比如USART1的默认引脚是PA9(TX)和PA10(RX),但通过重映射功能也可以把它们移到PB6和PB7。如果你发现串口发不出数据,第一步不是检查波特率,而是先确认你操作的引脚和外部连接是否一致——选错引脚是超级常见的问题。
printf重定向也是新手必踩的坑。默认的C库printf是面向文件的,你需要用fputc函数把输出重定向到串口发送寄存器,同时注意Keil里MicroLib的启用选项。如果你不启用MicroLib,链接的时候可能会报半主机模式(Semihosting)相关的错误,那是因为没有实现对应的调试环境接口。我的经验是:直接用MicroLib,并且把fputc改成串口发送的轮询函数,这样printf就能愉快地工作了。
6.2 CAN通信突然连不上:现场排查思路
“stm32 can通信突然连不上”是另一个高频问题。CAN总线在工业控制、车载电子中应用极广,STM32F103内置的是bxCAN外设。它突然连不上的原因通常不是代码逻辑突然坏了,而是物理层的总线状态变了。排查顺序是这样的:先看是不是只有一块板子掉线,如果所有节点都掉线,说明总线阻抗匹配出问题,两个终端节点的120Ω终端电阻可能有一个断了,或者总线上有节点把电平拉死。如果只有特定节点掉线,重点检查它是不是进入了Bus Off状态,这种状态下它会持续发送错误帧,导致整个总线都被干扰。
调试CAN的时候,强烈建议用一个USB-CAN分析仪来抓总线上的报文。它能区分出到底是板子根本没发数据、发了但报文格式不对、还是总线存在电平冲突。如果是波特率不匹配导致的掉线,报文会全部显示错误帧,此时你只要用波特率扫描功能就能发现真正的速率。这个工具在排查CAN问题上比示波器还高效,属于必备配件。
6.3 禁用JTAG:为什么你的PA15、PB3、PB4不受控
很多人在用PA15、PB3、PB4这些引脚做GPIO输出时发现电平完全不受控制,查来查去也没错,其实原因在于这几个引脚默认是JTAG调试接口。STM32F103的JTAG功能占用PA13(JTMS)、PA14(JTCK)、PA15(JTDI)、PB3(JTDO)、PB4(NJTRST)这五个脚。当你把PA15配置成推挽输出时,JTAG功能会以更高优先级抢占这个引脚,你的软件配置不会生效。
解决办法是对GPIO复用时钟和AFIO进行特殊处理,在代码里调用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE),把JTAG模式禁用,仅保留SWD。这样PA15、PB3、PB4就可以作为普通GPIO使用了,同时你用ST-Link的SWD接口仍然可以下载调试。这个知识在很多项目里都会用到,尤其是当引脚不够用的时候。但注意不要禁用SWD——如果你同时禁用SWJ,芯片就可能无法再通过ST-Link连接,只能通过串口ISP模式苦苦挣扎。
7. 进阶方向与热门玩法:从单纯点灯到完整小项目的思路转变
7.1 VSCode搭建STM32开发环境:不依赖Keil也能开发
当你开始嫌弃Keil的界面老旧、代码补全太弱、编译速度太慢的时候,就可以考虑切换到VSCode + EIDE + GCC了。这个组合的本质是用开源的arm-none-eabi-gcc工具链编译,用OpenOCD或pyOCD完成下载调试,VSCode只是作为编辑器壳。EIDE插件几乎是为嵌入式开发量身定做的,它可以直接导入Keil工程,也可以从零创建GCC工程,自动管理编译器的路径和烧录脚本。
VSCode环境的优势是代码索引快、支持智能补全、配合clangd能实现精准跳转,这些体验远超Keil。但它也有代价:工程配置文件是json,需要你理解编译器的Include Paths、宏定义和链接脚本。尤其是ld文件,如果不小心改错,程序可能跑飞。我的经验是:先在Keil里把工程调通,再导入VSCode做调试和代码阅读,等到手里有几个熟练的小项目后,再完全切到VSCode。不要一开始就用VSCode,否则你会被无穷无尽的配置问题磨掉热情。
7.2 五线四相步进电机与伺服电机的485控制
热词里的“五线四相步进电机stm32”和“stm32控制伺服电机485”是两个非常实用的运动控制方向。五线四相步进电机通常用ULN2003驱动板驱动,只需要四路GPIO输出节拍脉冲就能让电机转动。你需要写一个步进顺序表,按A-B-C-D或者A-AB-B-BC-C-CD-D-DA的时序循环输出高电平。关键是控制节拍频率,太快了电机丢步,太慢了电机振动明显。对F103来说,用定时器中断来驱动步进电机的节拍是最合适的方案,主循环负责处理其他逻辑。
伺服电机和步进电机的控制逻辑完全不一样。伺服电机通常带位置反馈,通过485接口发送Modbus RTU或者厂商自定义协议来控制位置、速度和力矩。对STM32来说,难点不在发送指令,而在于485半双工通信的方向切换——发送时要把DE/RE引脚拉高,接收时拉低,切换时机不对就会导致数据不完整。我调试伺服电机时踩过的坑是,指令帧的CRC校验码算错,导致电机没任何反应。CRC16的计算代码网上很多,但要确认初始值和多项式与厂商协议一致。运动控制类项目对精度的要求远高于普通的传感采集,数据的完整性和时序的稳定性必须优先保障。
7.3 STM32接巴法云:低成本物联网方案
热词里还有“stm32 巴法云”,这也是这几年比较火的玩法。巴法云是一个对嵌入式设备友好的物联网平台,支持MQTT和HTTP协议,提供了免费层级,特别适合个人学习和小型产品原型验证。STM32通过ESP8266或者内置的网络模块接入WiFi,然后通过MQTT协议订阅和发布主题,就能实现远程控制LED、读取温湿度数据、甚至上报设备状态到微信小程序。
这个方案的落地难点在于ESP8266的AT指令流控和不稳定问题。ESP8266在弱网环境下会出现TCP连接断开、数据堆积的问题,你在代码里必须实现心跳重连机制,定时检查WiFi连接状态,发现断开就重启模块或者重新初始化连接。另外,MQTT的Topic命名和订阅规则要规划清楚,设备端和云端保持在同一个Topic的消息格式一致,否则服务端收不到有效消息。巴法云这类平台优势是接入门槛低,劣势是消息频率和长度有限制,适合做“低频控制”和“状态上报”,不适合做高吞吐的数据流传输。
7.4 从简单项目到毕业设计:选题思路和建议
如果你正在为“基于STM32的毕业设计”发愁,我的建议是不要临时找那种冷门课题。一个高性价比的毕业设计应该是“一个传感器 + 一个控制器 + 一种通信方式 + 一个上位机或APP”。传感器可以选温湿度、超声波、MPU6050陀螺仪、光敏电阻或者称重传感器;控制器就是STM32F103本身;通信方式可以是串口、CAN、蓝牙、WiFi或者ESP8266 + MQTT;上位机可以用Qt、Python的PyQt,甚至微信小程序。这四个模块任意组合,就能构成一个结构完整、工作量适中、答辩可讲清的项目。
真正让你脱颖而出的是“控制逻辑的闭环”和“异常处理的完善”。比如同样是做一个倒车雷达,能够显示波形、设置报警阈值、记录历史数据、处理传感器盲区的方案,和仅仅在LCD上打个数值的方案,工作量差不多,但评价完全不同。在做项目规划时,先想清楚“核心功能是什么”“哪些功能是锦上添花”“哪些功能是最后万不得已可以砍掉的”,这样时间安排才合理。F103的性价比和资料丰富度,决定了它是一个容错率极高的平台,前期多踩坑,后面就顺。
8. 还在路上:我踩过的坑和接下来想做的事
这块板子买回来不到两周,我已经从单纯的“点灯”走到了串口通信、定时器捕获和简单的传感器采集。说实话,STM32的学习曲线并不陡,但它的门槛在于“遗忘”——你很容易记住API的名字,却忘了为什么要开时钟、为什么用复用功能、为什么引脚会冲突。我目前的习惯是每做一个小功能就写一篇笔记,把寄存器配置的关键步骤和调试过程中用到的工具记录下来,这样过几个月回来查的时候,思路依然是清晰的。
如果你也正在学STM32,我的建议是准备一个最小系统板,搭配一个ST-Link下载器、一块OLED屏、一个HC-SR04和一个按键,就足够你折腾两三个月了。不要一上来就买各种高端传感器和模块,先把最核心的GPIO、定时器、串口、中断这四个基础吃透,再看什么做什么都会轻松很多。接下来我打算写一篇完整的“标准库新建工程保姆级教程”,把从安装到点灯的每一步都拆开讲,然后做一个用定时器输入捕获测速的小项目。学嵌入式这件事,本来就是一点一点“磨”出来的,能坚持到把第一个自己设计的小系统跑起来,你就算正式入门了。