写这篇东西的起因很简单,有朋友给我发消息问“怎么用Keil5.23建一个STM32工程并编译”,我第一反应是这问题太基础了,网上一搜一大把。但聊深了才发现,真正卡住新手的往往不是建工程那几步,而是安装环境时一堆乱七八糟的小选项、固件包版本对不上、编译出来一堆看不懂的英文报错,任何一个环节出错都能让人卡一晚上。所以我把这十几年的经验整理成一篇完整流程,从环境准备、芯片支持包,到新建工程、编译出HEX文件,再到高频报错排查,从零开始带你走一遍,保证你照着做就能把板子上的灯点亮。
这篇文章适合刚接触STM32、没有任何开发环境经验的入门者,也适合装了好几次Keil但始终没编译成功过的朋友。标题里说的“固件包自带版本”,其实就是指Keil5.23配合官方芯片支持包来创建工程,不用自己找库、配路径,只要把环境选对,剩下的都是肌肉记忆。
1. 先搞清楚这个标题里的三个关键词
1.1 Keil5.23:不是越新越好,稳定才是王道
先说版本号。市面上能下载到的Keil MDK版本五花八门,有5.14、5.17、5.23、5.27、5.36、5.38,再新的还有6.x系列。很多新手一看到新版本就忍不住去装最新的,其实对入门来说这反而是个坑。Keil 5.23是老一代的经典稳定版本,它的界面、编译流程、插件兼容性都经过大量用户验证,网上教程也基本都是基于这个版本写的,你遇到问题搜解决方案时,绝大多数都能直接对上号。
我自己测试过,5.23对标准外设库(StdPeriph_Lib,也就是老教程里最常见的STM32F10x固件库)支持得很好,编译速度快,占用内存也不高,调一个入门级的工程完全够用。对比起来,5.27以上版本虽然界面更现代,但如果你用的还是老库或者旧工程,反而容易出现奇怪的兼容问题。5.23这个版本,卡在一个“功能刚好够用、生态最成熟”的位置上,对自学者来说,这是最好的起点。
使用5.23还要注意一个细节:这个版本的默认编译器是ARMCC(ARM Compiler 5),而新版本会默认切换到ARM Compiler 6。编译器一变,很多老代码的编译行为就不一样了,比如语法检查更严格、优化策略不同,对新手来说这是额外变量。用5.23,你默认用的就是最主流的ARMCC 5.06,踩坑概率大幅下降。
1.2 “固件包自带版本”到底指什么
继续说回标题里的“固件包自带版本”。在STM32开发的世界里,有两个“包”特别容易混淆,一个是芯片支持包(DFP,Device Family Pack),一个是固件库(Firmware Library)。
芯片支持包是给Keil用的“芯片身份证”,装好之后,你在新建工程时才能在选择界面看到“STM32F103C8”“STM32F407ZGTx”这样的具体型号。没有这个包,Keil根本不认识任何STM32芯片。而固件库是编程时用到的“底层驱动代码集合”,比如你想操作GPIO、配置串口、初始化定时器,直接调用库函数就行,不用自己去翻寄存器。固件库又分为标准外设库、HAL库、LL库三种。
标题里说的“固件包自带版本”,通常是指Keil安装包或教程配套资源里已经集成了某个版本的芯片支持包,你装好Keil之后,再手动把那个.pack文件双击安装一下,就能直接建工程。这种方式对新手最友好,省去了去官网找包、担心版本不匹配的麻烦。我见过太多人卡在这一步:Keil装好了,但在Device选择界面怎么都找不到STM32型号,就是因为没装芯片支持包。
1.3 认识你即将面对的三个“包”
为了避免后续流程里晕头转向,我们先把“包”这件事彻底理清。你接下来会接触到的有三个东西:
- Keil MDK 5.23:集成开发环境,也就是我们“写代码和编译”的软件本体。
- STM32F1xx_DFP(或F4、F0等):芯片支持包,作用是让Keil“认识”你的芯片型号。相当于你在手机上下了一个输入法,手机才知道怎么打出这个语言的文字。
- 标准外设库/固件库:写程序时的底层驱动源码。相当于输入法里自带的词库,你打出“GPIO”三个字母,它能帮你联想出完整的那一串寄存器配置代码。
这三者的关系可以打个比方:Keil是厨房,芯片支持包是菜谱(告诉厨房有什么食材、怎么开火),固件库是已经洗好切好的配菜(拿来即用,不用自己从头备料)。理解了这层关系,后面所有操作都会豁然开朗。
2. 环境准备:安装Keil5.23和芯片支持包
2.1 安装前需要知道的几个原则
先说安装这件事,其实没什么高难度,但有几个坑是新手必踩的。第一,安装路径千万不要有中文和空格。我见过有同学把Keil装到“D:\软件\Keil_v5”下面,结果编译的时候报了一堆莫名其妙找不到文件的错误,后来把整个路径改成“D:\Keil_v5”就全好了。不是Keil矫情,是老外写的工具链对非ASCII字符支持不太好,包括后面建的工程路径也一样,一律用英文。
第二,安装时最好关闭杀毒软件和防火墙,或者至少把Keil的安装目录加入白名单。Keil安装包里有破解工具、License授权相关文件,这些经常被误报成病毒。我并不是让你用盗版,其实Keil有评估版可以免费试用,只是很多教程资源里的安装包附带了License生成工具,这类文件确实容易被拦截。如果你只是学习,评估版32KB代码限制完全够用,点个灯、跑个串口根本不会超。
第三,安装过程中会让你选择“Core”还是“Pack”,新手不要改动默认配置,直接选全部安装就行。有些教程为了省空间会让只装Core,但这样后面装芯片支持包时反而容易缺东西。空间不够的话,装完再把C盘一些缓存文件清一清就行。
2.2 芯片支持包(DFP)安装实操
Keil装好后,默认是找不到STM32型号的,别慌,这只是因为还没安装芯片支持包。装包有两种方式,第一种是通过Keil自带的Pack Installer在线安装,打开Keil,菜单栏点“Pack Installer”,左边列表里搜索“STM32F1xx”,找到对应芯片系列,点Install即可。这种方式需要网络畅通,下载速度有时候很慢,如果等半天没反应,就果断换第二种。
第二种方式是离线安装。从官网或网盘下载“Keil.STM32F1xx_DFP.2.3.0.pack”这样的文件,直接双击,Keil会自动打开并执行安装流程,等右下角出现“Pack Installed”的提示就完成了。我推荐你用这种方式,因为安装包体积大(一般几百MB),用下载工具拖下来更稳定,而且以后重装系统时还可以再拿来用。
判断芯片支持包有没有装成功,很简单:在Keil菜单栏点“Project”→“New uVision Project”,在弹出的窗口里左侧列表展开“STMicroelectronics”,如果能看到“STM32F103系列”之类的型号列表,说明已经装好了。这里顺便说一句,不同系列对应不同DFP,F103用STM32F1xx_DFP,F407用STM32F4xx_DFP,不要贪多下载好几个,哪个系列就装哪个。
2.3 顺便说下C51和STM32共存的事
热搜词里有“keil5兼容c51和stm32安装”,这确实是很多人的真实痛点。很多同学之前学过51单片机,电脑里已经有了Keil C51(注意,C51和MDK是两个不同的产品),现在学了STM32,又装了Keil MDK 5.23,结果发现两个软件的图标长得一模一样,打开之后芯片列表却不一样,搞得一头雾水。
解决方案很简单:先装C51,再装MDK,装到同一个目录下,比如都装在“D:\Keil_v5”。这样两个工具链会合并到一个IDE里,你在新建工程时,如果看到的是“Atmel 89C51”,说明当前默认是C51模式;看到“STMicroelectronics STM32F103”,说明正常显示的是MDK模式。两个模式共存互不干扰,不会出现打开后只能看到其中一个的情况。
如果先装了MDK再装C51,或者装到了不同目录,就容易出现只看到一个模式的情况。处理方法是重新运行一下C51的安装程序,把路径指到MDK的安装目录,覆盖安装一遍就好了。这个问题太典型了,每次带新人基本都要解释一遍,所以单独拿出来说一下。
3. 手把手创建一个最小STM32工程
3.1 新建工程的完整操作步骤
环境准备好了,接下来就是重头戏:新建工程。现在我就以一个最常见的STM32F103C8T6(蓝板那种)为例,把每一步操作和白话解释同步给你。
第一步,打开Keil5.23,菜单栏找到“Project”,点“New uVision Project”,在弹出的对话框里先选好工程保存路径。注意,这里一定不要放在桌面,也不要放进有中文的文件夹,我习惯在D盘根目录下建一个“stm32_project”文件夹,然后工程名写“LED_test”,点击保存。
第二步,弹出的“Select Device”窗口中,左侧栏展开“STMicroelectronics”下的“STM32F1 Series”,接着找到“STM32F103”,选择你的具体型号。蓝板常用的是STM32F103C8T6,在列表里选它,右侧会显示这个芯片的内核信息、Flash大小、RAM大小。选好之后点OK。
第三步,这一步最容易被新手跳过,接下来会弹出一个“Manage Run-Time Environment”窗口,里面一大堆勾选项,看着头大。对于标准库工程来说,这里全部取消勾选,直接点OK。因为我们后面要手动添加启动文件和库文件,不需要Keil自动帮你管这些。
第四步,此时工程已经建好,但左边Project栏里还是空的。我们需要手动添加启动文件和固件库。鼠标右键“Target 1”→“Add Existing Files to Group”,能找到已存在的文件并添加进去。先添加启动文件,这个文件的路径在固件库压缩包里,标准库解压后的路径大致是“STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm”,文件夹里有很多startup_stm32f10x_xxx.s文件,分别是不同芯片型号的启动文件,我们用的是C8T6(中等容量),选“startup_stm32f10x_md.s”添加进来。
第五步,添加固件库的“系统文件”和“内核文件”。还是在同一个库目录下,“Libraries\CMSIS\CM3\CoreSupport”下的“core_cm3.c”和“Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x”下的“system_stm32f10x.c”都要加进来。这两个文件一个是ARM内核的抽象层,一个是STM32系统时钟初始化代码,缺一个都会编译报错。
第六步,在Source Group 1上右键,“Add New Item to Group”,选择C File,文件名写main.c,点击Add。这样工程文件就建好了。
3.2 为什么推荐用“标准库+寄存器混搭”的方式起步
说到这,顺便分享一个我的教学经验:新手学STM32,建议先别急着上HAL库。虽然现在ST官方主推的是HAL库和STM32CubeMX图形化配置工具,画个引脚图就能生成代码,很方便,但我一直觉得,入门阶段用标准外设库和寄存器混搭的学习方式,能帮你把底层原理摸得更透。
为什么?因为标准库是一层“薄封装”,每个函数背后对应的寄存器操作一眼就能看懂。比如你想让PA1引脚输出高电平,标准库写的是“GPIO_SetBits(GPIOA, GPIO_Pin_1)”,你去翻源码,能看到它最终操作的是“GPIOA->BSRR = (uint32_t)GPIO_Pin_1”这个寄存器。而你用HAL库,看到的是“HAL_GPIO_WritePin(GPIOA, GPIO_Pin_1, GPIO_PIN_SET)”,虽然写法更统一,但背后多了一层抽象,新手如果不去深挖源码,根本不知道底层发生了什么。
当然,这只是我的个人观点。如果你以后打算长期做STM32开发,HAL库确实是大势所趋,生态更完善、代码移植性更强。但对入门第一个工程来说,标准库能让你在几十行代码内就明白时钟、GPIO、引脚配置这些核心概念,而不会被一堆中间件和回调函数淹没。我倾向于“先用标准库把门推开,再决定要不要换HAL”。
所以第三步里我们没有用RTE环境自动管理文件,而是手动添加启动文件和系统文件,这也是有意为之。手动添加让你亲眼看到“一个工程由哪些部分组成”,以后编译器报错说“找不到某个文件”时,你能直接判断是缺了哪个部分。
3.3 魔术棒里这几个配置不改必后悔
工程文件添加完毕,不要急着写代码,先把“Options for Target”配置好。在工具栏上找到那个长得像魔术棒的图标,点击打开,这里有三个选项卡必须看。
第一个是“Output”选项卡,“Select Folder for Objects”可以自定义编译输出文件存放位置,默认在工程目录下新建一个Objects文件夹即可。关键是把“Create HEX File”勾上,这样编译之后才会生成烧录用的HEX文件。很多新手编译成功了,却找不到.hex文件去烧录,就是因为没勾这个选项。
第二个是“C/C++”选项卡,在“Define”栏里输入“STM32F10X_MD, USE_STDPERIPH_DEVICE”,因为F103C8属于中等容量芯片,需要用这个宏定义来告诉编译器启用哪些代码分支。标准库源码里有很多条件编译语句,比如“#ifdef STM32F10X_MD”,如果没有定义这个宏,很多外设驱动代码根本不会被编译进去,后面调用库函数必然报错“undefined symbol”。
第三个是“Debug”选项卡,这里选择你手头的调试器。用ST-Link就在右侧下拉框里选“ST-Link Debugger”,用J-Link就选“J-LINK/J-TRACE”,旁边“Settings”里有可能会在“SW Device”标签页显示一个芯片IDCODE串,如果显示了,说明仿真器连接正常。这一步配置错了,后面点仿真调试时会提示“No target connected”。
这三个配置是新手最容易漏做的。我不止一次在答疑群看到有人发出“编译零错误,但烧录失败”的求助,一问全是没勾HEX或者没选Debug模式。
4. 编译一顿操作:从报错到出HEX
4.1 第一次编译会遇到什么
现在,到了检验成果的时刻。先给main.c里写下最简单的点灯代码,然后直接按F7(或者点工具栏的“Build”按钮)开始编译。如果你和我当年一样是纯新手,大概率会看到Output窗口里冒出一堆红色警告和错误,别慌,一件件来看。
这里给出一个最简单的main.c内容,你可以先照着抄:
#include "stm32f10x.h" int main(void) { GPIO_InitTypeDef GPIO_InitStructure; // 打开GPIOB端口时钟(LED接在PB12,具体以你板子为准) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 配置PB12为推挽输出,最大翻转频率2MHz GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); while (1) { GPIO_SetBits(GPIOB, GPIO_Pin_12); // 拉高电平,LED灭 for (volatile int i = 0; i < 500000; i++); // 简单延时 GPIO_ResetBits(GPIOB, GPIO_Pin_12); // 拉低电平,LED亮 for (volatile int i = 0; i < 500000; i++); } }如果你是第一次接触这段代码,不需要完全理解每一行的意思,只需要知道它的大致逻辑是:把某个引脚配置成输出模式,然后在死循环里交替拉高拉低,让LED闪烁。这个点,后续你学完GPIO章节就全懂了。
编译后,在Output窗口的Build Output子窗口里,如果你看到“0 Error(s), 0 Warning(s)”,并且下方多了一行“creating hex file...”,恭喜你,工程已经建好并成功编译了。哪怕有三五个Warning,只要没有“Error”字样,一般都能正常烧录。
4.2 高频报错速查与解决
我整理了新手问的最多的几类编译报错,做成一个速查表,你遇到问题时直接对着查:
| 报错内容 | 原因 | 解决方法 |
|---|---|---|
| cannot open source input file "stm32f10x.h" | 头文件路径没有添加到工程 | 在C/C++选项卡的Include Paths里,把固件库所在路径添加进去,如...Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x |
| Error: L6218E: Undefined symbol GPIO_Init | 标准库源码没有编译进工程或宏定义缺失 | 确认GPIO相关.c文件已添加,确认Define里已写STM32F10X_MD |
| core_cm3.c not found | 内核文件漏添加 | 回到第3.1节第五步,把core_cm3.c和system_stm32f10x.c都加入工程 |
| .\Objects\LED_test.axf: Error: L6406E: No space in execution regions | Flash内存溢出 | 一般是把代码写满了或者启动文件选错了芯片容量,检查启动文件是否为md版本 |
| *** Target 'Target 1' uses ARM-Compiler 'Default Compiler Version 5' which is not available. | Keil版本缺少AC5编译器 | 安装MDK5.23时不要选“Without AC5”之类的精简安装,重装时确保勾选ARM Compiler 5 |
其中第一条出现频率最高,原因是你在include头文件时,编译器不知道头文件在哪。解决方法是在“C/C++”选项卡的“Include Paths”右侧点“...”,把固件库中所有包含.h文件的文件夹添加进去。我一般把这三个路径都加进去,省得以后出问题:
- 工程源码目录(你自己的.h文件)
- ...Libraries\CMSIS\CM3\CoreSupport
- ...Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x
还有个小技巧:双击Output窗口里的红色报错行,Keil会自动跳到出错的代码位置,光标停在出错行上。用这个方法定位问题,比一行行找快得多。
4.3 编译速度优化:Keil5.23其实可以很快
热搜词里有“keil5编译很慢?”,这个问题确实困扰了不少人。很多同学用的都是老旧笔记本电脑,编译一次要等半分钟以上,如果是用的固态硬盘还好,机械硬盘的话,本来就慢的Keil雪上加霜。我分享几个实测有效的提速方法。
第一,关闭“Browse Information”。在工程Options→Output选项卡里,有一个“Browse Information”复选框,改成不勾选。这个选项是用来生成代码跳转和变量查找索引的,对入门学习和编译动态调试来说用处不大,但开着会让编译产物体积增大不少,编译时间也变长。实测下来,关闭这个选项后,编译时间大约能缩短30%。
第二,编译时只点“Build”而不是“Rebuild”。“Build”会让Keil只编译上次编译之后修改过的文件,增量编译,速度很快;而“Rebuild”是重新编译所有文件,花的时间多好几倍。这个问题上我见过很多新人以为点那个“Rebuild”图标才是编译,其实“Rebuild”的意思是“全部重来”,平时的常规操作点“Build”就行。
第三,把工程放到固态硬盘上。这个建议听起来像废话伤钱,但确实效果立竿见影。我有一台老笔记本,原来工程放在机械硬盘里编译要40秒,换到固态盘后只要12秒。如果条件允许,哪怕外接一个USB3.0的移动固态硬盘都比原来的机械盘强。
第四,关闭不必要的软件。Keil编译时CPU会跑满一个核,浏览器、微信、网盘这些后台软件如果都在抢CPU,编译时间自然就长了。编译那几秒,把后台大软件临时关一关,体验会好很多。
5. 自学者踩过的坑,我给你摊开讲
5.1 芯片包版本与固件库版本别搞混
关于版本匹配,我吃了不少亏,这里专门给大家提个醒。芯片支持包的版本(比如2.3.0)和固件库的版本(比如V3.5.0)是两个完全独立的东西,很多人会拿它们的版本号去对谁新谁旧,其实完全没必要。芯片支持包只管“让Keil认识这块芯片”,固件库才是你写代码时调用的那个东西。
实际开发中,只要固件库代码能编译通过,芯片支持包和固件库版本差异大一点也没关系。比如你装的是STM32F1xx_DFP的旧版本2.1.0,用V3.5.0的标准库写代码,完全没问题。反过来,如果你用的是新版HAL库,可能要求DFP版本高一些。
唯一要担心的,是不同芯片型号要用对应的DFP。比如你现在用F103,装的是F1系列的DFP,哪天换成F407,就得再装一个F4系列的DFP。这不算坑,算是常识,但老有人在这儿卡住。
5.2 中文注释乱码与编码格式(GBK/UTF-8)
热搜词里有“mdk工程编码gbk改为utf-8”,这个坑我先说结论,再讲原因。Keil5.23这个版本默认是按ANSI(中文系统下就是GBK编码)解释源文件的,如果你用VS Code或者别的现代编辑器把源码保存成了UTF-8格式,那么在Keil里打开就能看到满屏的乱码注释,甚至可能导致编译报错,因为字符串常量里的中文被编译器按GBK读取时解析错了,编译器会把后面的代码内容一起当成字符串内容,一路报错到文件结尾。
如果你想在Keil里用中文注释,最简单的方法就是:统一用Keil自带的编辑器写代码,别用其他的编辑器代劳,这样默认就是ANSI/GBK,不会乱码。如果你确实要用VS Code等现代编辑器,那可以在Keil的Edit→Configuration→Editor→Encoding里改成“UTF-8”,然后再重新打开所有项目文件。改完之后,同一个文件在Keil和VS Code里显示都正常。
但注意,Keil5.23对UTF-8的支持不算完美,改了编码后,之前用ANSI保存的文件如果不在工程里统一处理,反而会乱得更厉害。我的建议是:既然是自学,干脆注释全部用英文写。别担心英文不好,嵌入式领域常用的注释词就那么几十个,练几次就能顺手上。用英文注释还有一个额外好处,就是编译时永远不用为了注释乱码而分心,代码的通用性也好很多,以后你把代码发到GitHub上,别人看着也舒服。
5.3 工程路径、文件命名这些细节
这一节讲的都是小事,但小事不改,大事早晚翻车。第一,工程文件夹的路径总长度不要太长。系统对路径长度有上限,太长了编译器会找不到文件。我自己习惯把工程路径控制在“D:\stm32_project\LED_test”这样的两到三级以内,别放在“D:\Desktop\stm32学习资料\1.代码\练习\第3课_GPIO_LED\版本2\最终版”这种路径下,且不说编译容易出问题,光每次打开工程找路径就得找半天。
第二,源文件和工程名尽量保持简单,少用“test1_最终版_改版”,这是代码管理的大忌。我在实际工作中见过一个工程叫“final_final_v2_ok_真的能用”这种名字,谁看到谁头大。给工程起名直接用英文小写+下划线,比如led_test、key_scan、uart_echo,清爽利落。
第三,工程建好之后,不要轻易移动位置或改文件名。Keil的工程文件(.uvprojx)里记录了各种绝对路径,移动位置后,路径对不上,就会报“cannot open file”。如果你确实要搬家,最好的办法不是移动文件,而是直接重新新建一个工程,把源代码重新添加进去,几十秒的事情,别折腾。
5.4 下载调试环节的常见拦路虎
编译通过,只是万里长征走完一半。等你想把程序烧进板子,可能又会碰到新问题。最常见的两个,一个是“No target connected”,一个是“Error: Flash Download failed - Cortex-M3”。
“No target connected”通常是仿真器没识别到芯片,解决办法首先是检查接线:SWD模式只需要SWDIO、SWCLK、GND三根线,另外最好把3.3V也接上,给目标板供电,避免电压不稳。检查完之后,在Debug选项卡的Settings里点“Detect”重新搜索一次,看能否识别到IDCODE。有时候是驱动问题,插上ST-Link后设备管理器里显示黄色感叹号,那就需要重装ST-Link驱动。
“Flash Download failed”一般是烧录算法没选对。在Options→Debug→Settings→Flash Download里,要勾选对应的烧录算法,比如STM32F103C8只有64KB Flash,应该选择“STM32F10x Medium-density 64K Flash”。如果算法选成了High-density或者256K的,虽然大多数情况下也能烧,但偶尔会报错。特别是C8T6这种小容量芯片,经常有人从F103ZET6的工程改过来,忘了换烧录算法,一烧就报错。这个坑很隐蔽,一旦遇到,先去检查这里。
6. 一些掏心窝的建议
说了这么多,最后聊点个人体会。我见过太多初学者在第一个星期就被环境问题劝退,觉得嵌入式开发太难了,其实很多时候不是因为难,而是因为“没人告诉你这些坑在哪”。Keil5.23建STM32工程这件事,说透了就三步:装对软件、装对芯片包、配好编译选项。只要这三步走稳,后面就是不断写代码、编译、看现象的正循环。
我个人建议,第一个工程不要抄太复杂的代码,就从LED闪烁开始。点亮一颗灯,看似简单,但它验证了整个工具链——Keil能建工程、编译器能编译、烧录器能下载、单片机能运行。这四个环节全部打通之后,你才真正拥有了继续学下去的底气。接下来无论是点灯、按键检测、串口打印,还是中断、定时器、PWM,每一关都建立在这个基础上。
最后分享一个小技巧:每次换个开发板或者换台电脑,我都会从建一个LED工程重新开始验证环境。磨刀不误砍柴工,十五分钟验证完环境,后面几天开发遇到问题就知道不是环境锅,能省很多怀疑人生的时间。希望这篇教程能帮你少走一些弯路,早点点亮你的第一块STM32。