各位做 STM32 开发的朋友,这次我们来聊一个比较轻松但又很实用的话题:用 AI 辅助生成流水灯程序。你没听错,就是我们入坑单片机时第一个接触的流水灯。
接触过 AI 编程的朋友应该都有体会,现在用 Cursor、通义灵码这类工具写业务代码、写脚本已经很成熟了,但拿来写嵌入式底层代码,效果到底怎么样?特别是 STM32 这种需要操作寄存器、配置时钟树、处理中断的芯片,AI 生成的东西能直接烧录吗?
这篇文章不聊虚的,直接带大家把整个流程走一遍。我们先看 AI 写 STM32 流水灯能做到什么程度,再给出一套可复用的提示词模板和代码验证方法,最后聊聊哪些代码可以直接用、哪些地方容易踩坑。
先说结论:如果你已经有 STM32 基础,AI 可以帮你把流水灯从“写代码”变成“提需求”,效率提升非常明显;如果你是纯新手,AI 生成代码也能跑,但前提是你得会用 Keil 建工程、会下载程序、会看报错。这篇文章会按照实际可操作的流程一步步展开。
1. 核心能力速览
先给大家一个总览,看看 AI 辅助生成 STM32 流水灯代码这件事的整体情况。
| 能力项 | 说明 |
|---|---|
| 核心功能 | 通过自然语言对话,由 AI 生成 STM32 流水灯初始化代码、延时函数和控制逻辑 |
| 适用模型 | 支持 GPT-4 系列、Claude 3.5/4 系列、通义千问、DeepSeek 等主流大模型 |
| 目标芯片 | STM32F103C8T6、STM32F407、STM32F103ZET6 等常见型号 |
| 开发环境 | Keil MDK5,需提前配置 STM32 芯片包(DFP 包) |
| 代码方式 | AI 可生成寄存器版本、标准库版本、HAL 库版本 |
| 硬件需求 | 普通电脑即可,不需要 GPU,网页版 AI 工具零门槛 |
| 启动方式 | 网页对话、本地 IDE 插件,不需要额外安装服务端 |
| 接口能力 | 通过 API 可批量生成注释、补全代码或做代码审查 |
| 是否支持批量任务 | 支持,但需要自己写脚本调用大模型 API |
| 适合场景 | 学习入门、课程设计、项目原型验证、代码注释补全 |
| 局限提醒 | AI 不保证时钟树配置一定正确,不读芯片手册,需要人工验证 |
从表里可以看到,AI 生成 STM32 代码这件事技术上没有障碍,门槛主要在两部分:一是你有没有能力描述清楚需求,二是你有没有能力判断生成代码是否正确。前者是提示词工程问题,后者就是单片机基础问题。
2. 为什么选流水灯作为 AI 编程试验场
很多朋友可能会疑惑,流水灯这么简单的程序,为什么要单独开一篇番外来说?
实际上流水灯是验证“AI + 嵌入式开发”工作流的最佳起点。流水灯涉及嵌入式开发的几个核心环节,包括 GPIO 输出模式配置、时钟使能、延时函数设计、主循环逻辑,麻雀虽小五脏俱全。如果 AI 连流水灯都写不好,那项目级嵌入式 AI 辅助开发就更不用想了。
另外从学习角度看,流水灯是所有 STM32 开发者的第一个实践项目,市面上大量教程都是拿它入门。如果把 AI 辅助流程跑通,后面学串口、定时器、中断、ADC 等模块时,都可以复用同一套工作流,效率提升不是一点半点。
还有一个很现实的原因是,AI 生成流水灯代码的失败率是可控的。就算代码有问题,出错也就是 GPIO 配置顺序、延时不准确、引脚编号搞错这几类问题,排查成本低,很适合反复测试提示词。换个复杂项目,AI 生成的代码出问题你根本不知道从哪查起。
3. 环境准备
AI 生成 STM32 代码不需要多高配置,但本地的 Keil 开发环境还是得提前搭好。这里把需要准备的东西列清楚。
3.1 硬件清单
- 一块 STM32 最小系统板或者开发板,常见的有 STM32F103C8T6 蓝色板,价格低且资料多。
- ST-Link V2 下载器,或者板载 ST-Link / DAP-Link。
- 若干 LED 和限流电阻,或者直接用开发板上自带的 LED。
- 杜邦线若干,用于外部连接 LED。
3.2 软件环境
| 软件 | 说明 |
|---|---|
| Keil MDK5 | 主流的 STM32 开发 IDE,需要安装对应芯片型号的 Device Pack |
| STM32CubeMX | 可选,用于图形化配置时钟和引脚,可以辅助验证 AI 生成的配置是否有误 |
| ST-Link Utility | 可选,用于设备连接测试和烧录校验,搜索热词里出现较多,很多场景下是排查下载问题的关键工具 |
| AI 工具 | 任选,网页版即可,建议同时准备一个通用大模型和一个代码专用模型做对比 |
这里特别说一下 ST-Link Utility 的使用场景。AI 生成的代码编译通过后,如果下载时频繁报错,比如No target connected或RDDI-DAP Error,大部分情况不是代码逻辑问题,而是下载器连接或驱动问题。打开 ST-Link Utility 点 Connect,如果能看到芯片型号和容量信息,说明硬件链路是通的,再回到 Keil 里排查下载设置。
3.3 Keil 芯片包检查
AI 生成的代码涉及具体芯片型号,如果 Keil 里没有装对应芯片包,编译会直接报Unknown target之类的错误。
打开 Keil MDK5,点击菜单栏的 Pack Installer 图标,在 Devices 选项卡里搜索 STM32F1 系列,确认 Device Pack 已经安装到本地。如果是第一次安装 Keil,还要注意 Pack Installer 可能会因为网络问题加载缓慢,这时候可以先去 ST 官网手动下载对应型号的 DFP 安装包,再双击安装。
3.4 通用环境检查清单
AI 生成代码后,在编译之前按以下顺序检查环境:
- Keil 版本是 5.2x 以上,太老的版本可能打不开新格式工程。
- 芯片包已经安装,搜索芯片型号时能正常高亮显示。
- ST-Link 驱动已安装,设备管理器里能识别到 ST-Link 设备。
- 下载器接线正确,SWDIO、SWCLK、GND、3.3V 四条线没有接反。
4. AI 生成流水灯代码的完整流程
下面进入正题,看看实际怎么用 AI 生成 STM32 流水灯代码。
这部分的思路是:先用通用大模型生成一版寄存器版本的代码,然后在 Keil 中编译验证,再让 AI 用标准库或者 HAL 库生成一版做对比,最后让 AI 帮我们加注释和改功能。
4.1 设计提示词
AI 生成代码的质量很大程度上取决于提示词。不要只丢一句“写一个 STM32 流水灯”,这样 AI 很容易按照默认配置生成一个泛泛的答案,不一定适用于你的板子。
一个比较完整的提示词模板可以参考:
你是一名嵌入式开发工程师,熟悉 STM32F103C8T6 芯片,请用寄存器方式写一个 GPIO 流水灯程序。 要求如下: 1. 使用 GPIOA 的 PIN0-PIN7 共 8 个引脚连接 LED。 2. 使用内部 HSI 时钟,不要配置外部晶振。 3. 编写 void delay_ms(uint16_t ms) 延时函数,使用简单循环实现。 4. 主循环中依次点亮每个 LED,间隔 200ms,点亮的顺序从左到右循环。 5. 需要完整代码,包含所有必要的 #define 和寄存器的位操作,不需要多余的注释。 6. 输出的代码要能在 Keil MDK5 中编译通过。提示词里尽量包含这几类信息:芯片型号、编程方式(寄存器/标准库/HAL)、引脚连接、时钟配置要求、延时时间、输出格式要求。信息越明确,AI 生成的代码越接近可用状态。
4.2 常见提示词设计参数对照
把需求描述拆成结构化参数,会让 AI 更容易输出满足要求的代码:
| 参数项 | 建议描述方式 | 说明 |
|---|---|---|
| 芯片型号 | STM32F103C8T6 / STM32F407ZET6 | 不同芯片引脚映射不同,必须写清楚 |
| 开发方式 | 寄存器 / 标准库 / HAL 库 | 决定代码整体风格 |
| 引脚编号 | PA0-PA7 / PB12-PB15 | 要写清楚具体引脚 |
| LED 电平逻辑 | 低电平点亮 / 高电平点亮 | 决定 GPIO 配置时是否要设置推挽输出 |
| 延时方式 | 简单延时 / SysTick 定时器延时 | 简单演示选循环,精确控制选 SysTick |
| 功能扩展 | 正向流水、反向流水、呼吸灯、按键控制 | 有特殊需求一定要写 |
4.3 让 AI 生成寄存器版本的流水灯
把上面的提示词发给 AI 模型,会得到类似下面这样的代码:
#include "stm32f10x.h" #define LED_GPIO_PORT GPIOA #define LED_GPIO_CLK_EN RCC_APB2Periph_GPIOA void delay_ms(uint16_t ms) { uint16_t i, j; for (i = 0; i < ms; i++) { for (j = 0; j < 7200; j++) { __NOP(); } } } void LED_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(LED_GPIO_CLK_EN, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure); GPIO_SetBits(LED_GPIO_PORT, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); } int main(void) { LED_GPIO_Init(); while (1) { uint8_t i; for (i = 0; i < 8; i++) { GPIO_ResetBits(LED_GPIO_PORT, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); GPIO_SetBits(LED_GPIO_PORT, (uint16_t)(GPIO_Pin_0 << i)); delay_ms(200); } } }这里注意一个细节,AI 给出的代码其实混合了标准库函数和部分寄存器概念,真正完全手写寄存器版本的代码一般不会用GPIO_InitTypeDef这种结构体。这个现象很常见,因为 AI 训练语料里标准库代码占比远高于寄存器代码,所以它会在“看上去像是寄存器版本”和“实际使用标准库函数”之间自由切换。
实际测试下来,这段代码在 Keil 里是可以编译的,前提是你已经建好了标准库工程,并且把stm32f10x_gpio.c和stm32f10x_rcc.c这两个库文件加入到了工程中。
5. 在 Keil 中验证 AI 生成代码
AI 把代码生成出来只是第一步,关键是怎么把它变成可以烧录到芯片里的程序。
5.1 从零创建 Keil 工程
这一步默认读者已经装好了 Keil MDK5 和芯片包,还没有环境的话先回去看前面 3.2 节。
在 Keil 中点击 Project -> New uVision Project,选择工程保存路径,然后输入工程名称。在芯片选择界面找到 STMicroelectronics -> STM32F1 Series -> STM32F103C8,选中后点击 OK。
接下来会弹出 Manage Run-Time Environment 窗口,这里不需要勾选任何组件,直接把窗口关掉。AI 生成的代码一般只需要标准外设库和核心文件,用 Keil 自带的组件管理反而容易引入版本冲突。
然后需要在工程文件里添加文件:
- 添加
main.c,放 AI 生成的主程序代码。 - 添加标准库核心文件,包括
stm32f10x_gpio.c、stm32f10x_rcc.c、stm32f10x_it.c。 - 添加启动文件
startup_stm32f10x_md.s。 - 打开工程选项,在 C/C++ 选项卡里添加宏定义
STM32F10X_MD和USE_STDPERIPH_DEVICE。
如果这一步没处理好,最常见的报错是头文件找不到,比如stm32f10x.h: No such file or directory。解决方案是:Options for Target -> C/C++ -> Include Paths 里添加标准库头文件所在目录。
5.2 编译验证
把 AI 生成的代码贴进 main.c 后,点击编译按钮。
如果代码本身没有语法问题,编译结果会显示 0 Error(s),这时可以继续下载烧录。如果编译报错,把错误信息直接复制回 AI 对话窗口,让 AI 帮忙修改。比如:
你说的代码在 Keil 中编译报错:stm32f10x.h: No such file or directory 我的工程已经添加了标准库文件,include 路径也配置好了,请检查是不是哪里写错了。这种“报错信息 + 工程状态描述”的追问方式,比单纯发“还是不行”要有效得多。AI 至少能帮你确认是不是头文件名不匹配、库文件版本问题,或者宏定义遗漏这类常见原因。
5.3 烧录运行
Keil 工程配置好烧录器之后,点击 Download 按钮,程序就会写入 STM32。
烧录成功后,如果硬件连接和代码逻辑都没有问题,可以看到 LED 按顺序依次点亮,形成流水效果。如果灯全灭或者全亮不流动,优先检查 GPIO 引脚号是不是和实际硬件一致。
排查方法很简单:拿杜邦线把 LED 的正极依次接到 PA0 到 PA7,接地端通过限流电阻接到 GND,然后看哪几个引脚能亮。这个方法比反复改代码快得多,能帮你把“代码问题”和“接线问题”快速区分开。
6. 从寄存器到库函数:让 AI 改代码风格
很多初学者在入门时纠结一个问题:到底应该学寄存器开发还是学 HAL 库开发?
借助 AI,我们可以不要在这个问题上死磕太久,直接让 AI 帮你把同一份代码翻译成不同版本,然后对比学习,效率是最高的。
6.1 让 AI 把代码改成标准库版本
直接在 AI 对话里追加:
请把上面这段代码改成标准库风格,并且使用 GPIO_WriteBit 函数实现流水灯效果,不要改变引脚定义和延时时间。AI 会很快返回一版标准库版本。
对比寄存器版本和标准库版本,最大的感受是:寄存器版本可以直接看到数值操作,比如GPIOA->ODR寄存器位操作;而标准库版本封装成了GPIO_SetBits、GPIO_ResetBits等函数,代码可读性大大提升,但学习时容易产生“黑盒”感觉。
只要把两个版本放在一起对照,很快就能理解 GPIO 初始化的底层逻辑:先开时钟,再配模式,最后设置初始状态。这个过程比死记硬背标准库函数要高效得多。
6.2 让 AI 把代码改成 HAL 库版本
继续追加:
现在请把代码改成 STM32CubeMX 生成的 HAL 库风格,初始化部分用 HAL_GPIO_Init 函数,延时用 HAL_Delay,同时补全 GPIO_InitStruct 每个字段的注释。这次 AI 返回的代码结构就不太一样了,HAL 库风格的代码里 GPIO 初始化的结构体会被初始化得特别完整:
void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3| GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET); GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3| GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); }这里想提醒一个常见坑。AI 生成的 HAL 库代码里,延时用的往往是HAL_Delay(200),但 HAL_Delay 依赖 SysTick 中断正常工作。如果你的工程里没有配置好 SysTick,直接调用HAL_Delay可能导致程序卡死。
解决办法有几种:
- 用
HAL_Init()初始化 SysTick。 - 用
HAL_GPIO_ReadPin查询电平。 - 改用自己写的循环延时函数。
7. 批量生成与代码补全
讲完了单次生成的流程,再扩展一个比较实用的技巧:利用 AI 接口批量处理代码。
如果你手上有一堆 STM32 工程文件,需要统一加注释或者把某个 GPIO 操作全部替换掉,手动一个个改会很痛苦。这时候可以通过大模型 API 做批量处理。
下面给一个通用的 Python 脚本模板,思路是读取目录下的.c文件,调用大模型 API,把文件内容和要求一起发给模型,把返回结果写回原文件。
import os import requests API_URL = "https://your-llm-api-endpoint/v1/chat/completions" API_KEY = "your-api-key" def call_llm(file_code: str) -> str: headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } payload = { "model": "your-model-name", "messages": [ {"role": "system", "content": "你是一个嵌入式代码审查助手,擅长给 STM32 代码添加注释和识别低级错误。"}, {"role": "user", "content": f"请给下面的代码补全关键注释,并检查是否有明显错误:\n\n{file_code}"} ], "temperature": 0.1 } resp = requests.post(API_URL, headers=headers, json=payload, timeout=120) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"] def process_dir(code_dir: str): for root, _, files in os.walk(code_dir): for name in files: if name.endswith((".c", ".h")): path = os.path.join(root, name) with open(path, "r", encoding="utf-8") as f: original = f.read() result = call_llm(original) with open(path.replace(".c", "_ai_annotated.c").replace(".h", "_ai_annotated.h"), "w", encoding="utf-8") as f: f.write(result) print(f"processed: {path}") if __name__ == "__main__": process_dir("./stm32_project/src")用这个脚本批量处理时要特别注意两点。第一,调用 API 时建议把temperature调低到 0.1 以下,避免 AI 天马行空地把代码逻辑改掉;第二,千万不要直接覆盖原文件,先输出成_ai_annotated.c,人工确认注释内容没问题之后再合并。
从实际测试来看,AI 在批量补注释这个场景下表现非常好,尤其适合课程设计代码、实验室交接代码、老项目维护这几个方向。
8. 资源占用与性能观察
很多刚接触 AI 辅助编程的嵌入式开发者会担心一个问题:用 AI 生成代码,会不会对电脑配置要求很高?
这里可以放心,AI 生成嵌入式的核心逻辑不在本地跑大模型,而是通过网页或 API 调用远端模型算力。本机只需要能打开浏览器、跑得动 Keil 即可,不需要独立显卡,不需要 CUDA,不需要任何 AI 推理框架。
如果你用的是本地代码补全插件(例如 Continue、Cursor 这类编辑器内置 AI),情况稍微复杂一点。本地模式下 CPU 会有一段时间的高占用,风扇会明显加速,但对开发和编译几乎没有任何影响。更稳妥的做法是优先使用云端模型接口,性能和质量都更可控。
如果你希望观察本地补全插件的资源占用情况,可以打开任务管理器,观察“内存”和“CPU”占用率波动。使用云端接口时主要占用的是网络带宽,内存占用增加并不明显。
显存方面不需要担心,这个流程全程不涉及本地 GPU 推理,所以不存在显存不足的问题。真正可能影响体验的瓶颈有两个:一是网络延迟,API 调用时每秒生成的 token 数量不够多会明显卡顿;二是 Keil 编译时的 CPU 占用,旧电脑单核性能弱的话编译会比较慢。
9. 常见问题与排查方法
用 AI 生成 STM32 代码的过程中,遇到的问题主要集中在环境配置、代码风格混搭和烧录失败这几类。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| Keil 编译报找不到 stm32f10x.h | 没有添加标准库头文件路径 | 检查 Options -> C/C++ -> Include Paths | 添加标准库头文件目录 |
| 编译报 Undefined symbol GPIO_Init | 缺少标准库 .c 文件 | 查看 Build Output 窗口中的报错符号 | 把 stm32f10x_gpio.c 加入工程 |
| 烧录时报 No target connected | ST-Link 接线错误或驱动异常 | 检查设备管理器,用 ST-Link Utility 测试连接 | 重插 ST-Link,检查 SWDIO/SWCLK/GND/3.3V 接线 |
| 流水灯全灭或全亮 | GPIO 引脚没错但电平逻辑反了 | 检查 LED 是否低电平点亮 | 把 GPIO_ResetBits 改 GPIO_SetBits |
| 程序能烧录但运行不稳定 | AI 生成的时钟配置和芯片实际不符 | 用 STM32CubeMX 生成一版参考时钟树 | 对比替换 RCC 初始化部分 |
| AI 生成的代码是别人芯片型号的 | 提示词没有写清楚型号 | 查看代码中的 RCC 时钟源设置 | 重新生成,提示词里明确写 STM32F103C8T6 |
| 代码风格混搭,一会儿寄存器一会标准库 | 大模型训练语料混杂导致 | 让 AI 限定统一的开发方式 | 重新描述要求“完全使用标准库函数” |
| HAL_Delay 卡死 | SysTick 中断没初始化 | 检查 HAL_Init 是否调用 | main 函数开头加 HAL_Init() |
如果遇到上面没有覆盖到的问题,更通用的排查路径是:先看编译输出窗口的具体报错行,再复制报错信息给 AI,描述你的工程结构和已添加的文件,让 AI 帮你定位。
10. 最佳实践与使用建议
10.1 第一次先跑最小验证
不要一上来就让 AI 生成一个巨大的工程。先从点亮一个 LED 的最小程序开始,确认编译和烧录链路是通的,再让 AI 把流水灯逻辑加进去。这样可以有效隔离问题范围,避免“代码编译不过到底是环境问题还是 AI 代码问题”这种难以判断的情况。
10.2 让 AI 输出可对比的多种版本
有条件的话,让 AI 分别输出寄存器版本、标准库版本和 HAL 库版本。同一份需求三种写法的代码放在一起对比,对理解 STM32 的学习路径非常有帮助。学习嵌入式最忌讳的就是只背一种写法,不知道为什么这么写。
10.3 保留一套最小模板工程
建议在自己的工程目录下维护一套最小可编译的 Keil 工程模板,里面包含正确配置的标准库、启动文件和头文件路径。每次让 AI 生成新代码,直接把模板复制一份,把 main.c 替换掉,编译成功率高很多。
10.4 接口调用时注意访问安全
如果通过 API 批量调用 AI 处理工程代码,涉及企业项目或含有内部信息时,注意确认数据合规性,别把敏感代码直接传第三方模型。自己学习用的代码随便玩,但涉及工作项目、实验室项目时要先问清楚数据边界。
10.5 涉及模块集成时的正确姿势
AI 生成代码最好用于学习验证和原型验证,不建议直接用到量产的工程项目里。如果要在实际产品中使用,建议把 AI 生成代码作为“参考实现”,再按照项目规范手动修改和审查。嵌入式领域一个看似无害的寄存器遗漏,就可能导致硬件异常。
10.6 版权合规提醒
如果 AI 生成的代码用于博文分享、课程设计说明或开源项目,需要注意开源许可证。很多大模型训练语料包含开源代码,生成结果可能带有 GPL 等传染性协议的内容。如果要开源或商用,务必做好代码来源审查。
11. 总结与下一步
这次这个番外篇,核心就做了一件事:把 AI 生成 STM32 流水灯代码的全流程跑通。从提示词设计到 Keil 编译验证,从寄存器版本到 HAL 库版本,从单次生成到批量补注释,都属于嵌入式开发者可以立刻上手的工作流。
最值得尝试的点是让 AI 把同一个需求翻译成三种不同开发方式的代码,这个对比学习的效率,比看十篇教程都管用。
最容易踩的坑集中在两个地方。一是 Keil 工程环境问题,很多 AI 生成代码本身没问题,是工程里缺文件、缺宏定义导致的编译失败;二是 AI 生成代码的风格混搭问题,寄存器版本里混标准库函数、标准库版本里又出现 HAL 库语句,需要人工识别和修正。
下一步大家可以尝试的方向包括:让 AI 生成 SysTick 精确延时版本、用 AI 生成按键控制流水灯方向的代码、让 AI 对比定时器中断和 DMA 方式驱动 GPIO 的区别、或者把整个 STM32 学习过程整理成一套 AI 辅助学习笔记。
建议收藏这篇文章,后面做 STM32 课程设计或者接手老项目时,照着这个流程能省不少时间。