前面发文说自然编程语言时代,不要一上来死磕C语言,有人质疑,今天这篇算回应一下:
先说独创的学习培养方法:以做实际项目为目标,通过项目目标牵引学习,用什么学什么,指挥AI实现功能,指挥AI进行知识梳理,结合传统的单一知识点教学视频增强基础。最关键的是,学完以后,因为是做项目,你的知识是成体系化的。
整个过程是无痛学习,功能需求AI拆解,实现技术路径AI规划,测试标准AI定义,代码AI写,最后AI还给你90%进行注释,还一对一的对你进行辅导。

过去很多零基础想学嵌入式,一上来就懵:C 语言、电路、寄存器、时序...... 一堆名词,不知道从哪下手。传统方式,先啃半年理论,再碰硬件,枯燥又劝退,坚持下来的没几个。
其实核心问题很简单:以前没工具,只能先把所有知识学完,才能动手做东西;现在不一样了,完全可以直接从一个看得见、用得上的小项目开始,边做边学、缺啥补啥。
直接上干货,AI太吓人了。
我先让他分解了需求,再让它写代码,后面有详细的需求分解,每一步的知识点。

代码交付计划
将创建以下文件(共约 13 个文件)
D:\开发板课程\教学理念\code\
├── platformio.ini # 项目配置(统一)
├── lib/
│ ├── oled/
│ │ ├── ssd1306.h # OLED驱动头文件
│ │ └── ssd1306.c # OLED驱动实现
│ ├── sensor/
│ │ ├── ntc_thermistor.h # NTC温度换算
│ │ └── ntc_thermistor.c
│ ├── control/
│ │ ├── pid.h # PID控制器
│ │ └── pid.c
│ └── ui/
│ ├── key_input.h # 按键状态机
│ └── key_input.c
└── src/
├── main_step1.c # 第1步:GPIO LED闪烁
├── main_step2.c # 第2步:按键+LED
├── main_step3.c # 第3步:串口printf
├── main_step4.c # 第4步:ADC测温
├── main_step5.c # 第5步:PWM呼吸灯
├── main_step6.c # 第6步:I2C OLED
├── main_step7.c # 第7步:按键交互UI
├── main_step8.c # 第8步:PWM加热
├── main_step9.c # 第9步:PID温控
└── main_step10.c # 第10步:完整集成
每一步包含
-
完整可编译运行的
main.c -
硬件接线说明(代码注释顶部)
-
AI对话提示词(注释标注,知道怎么让AI帮你写和改)
-
验证步骤(注释标注验收标准)
-
关键概念注解(为什么这样做)
代码风格
-
基于 STM32 HAL 库(PlatformIO 框架)
-
从步骤4开始逐步模块化,提取可复用库
-
每步代码独立可运行,用户只需改
src/main.c即可跳步
这是我给AI最初规划学习的提示词:
以"做一个 STM32 控制的智能恒温杯垫,带温度设定、实时测温、自动恒温功能,用 PWM 调加热功率。"的项目为牵引,让零基础学习嵌入式开发。把需求进行拆解,每一步的软件和硬件,应用到的MCU模块,每一步的验证标准都需要明确。

AI输出的结果:
好的,这个项目选得好------硬件简单、功能完整、涵盖嵌入式核心模块。以下是以项目为牵引、逐层递进的完整学习方案。
项目:智能恒温杯垫 ------ 零基础嵌入式学习路线
项目总览
┌──────────────────────────────────────────┐
│ 智能恒温杯垫 系统框图 │
│ │
│ [按钮 +/-] ──→ GPIO输入 │
│ [NTC热敏] ──→ ADC采样 ──→ 温度计算 │
│ [OLED屏] ←── I2C通信 ──→ 显示温/设定 │
│ [加热片] ←── PWM(TIM) ──→ MOSFET驱动 │
│ [LED指示] ←── GPIO输出 │
│ [串口] ←── USART ──→ PC调试监控 │
│ │
│ 核心逻辑:PID温控循环(TIM定时触发) │
└──────────────────────────────────────────┘
十步学习路径
每一步都按 「需求 → 涉及模块 → AI怎么帮 → 软件实现 → 硬件连接 → 验证标准」 展开。
每步涉及的MCU模块汇总
| 步骤 | GPIO | ADC | TIM | USART | I2C | SysTick | PID |
|---|---|---|---|---|---|---|---|
| 0 建环境 | |||||||
| 1 LED | ✓ | ||||||
| 2 按键 | ✓ | ||||||
| 3 串口 | ✓ | ✓ | |||||
| 4 测温 | ✓ | ||||||
| 5 PWM | ✓ | ||||||
| 6 OLED | ✓ | ||||||
| 7 交互 | ✓ | ✓ | |||||
| 8 加热 | ✓ | ||||||
| 9 PID | ✓ | ✓ | ✓ | ✓ | |||
| 10 集成 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
学习时间估算
| 步骤 | 预计时间 | 难度 |
|---|---|---|
| 0 环境搭建 | 半天 | ⭐ |
| 1 GPIO输出 | 半天 | ⭐ |
| 2 GPIO输入 | 半天 | ⭐ |
| 3 串口 | 1天 | ⭐⭐ |
| 4 ADC测温 | 1-2天 | ⭐⭐ |
| 5 PWM | 1天 | ⭐⭐ |
| 6 OLED | 1-2天 | ⭐⭐⭐ |
| 7 交互 | 1天 | ⭐⭐⭐ |
| 8 加热驱动 | 1天 | ⭐⭐⭐ |
| 9 PID控制 | 2-3天 | ⭐⭐⭐⭐ |
| 10 集成打磨 | 2-3天 | ⭐⭐⭐⭐⭐ |
总计:约 2-3 周(每天投入 2-3 小时)
传统教程教你一行行写C代码、一页页翻数据手册。这份教程假定你身边有一个AI助手(你的主要工作是:
-
理解要做什么
--- 看懂每步的目标和原理
-
向AI描述需求
--- 用自然语言告诉AI你要什么
-
审查AI输出
--- 判断代码对不对、安不安全
-
在硬件上验证
--- 用示波器、串口、万用表确认
-
追问"为什么"
--- 每个现象背后的原理,这是学习发生的时刻
你的角色 :系统设计师 + 审阅者 + 验证工程师
AI的角色:代码生成器 + 知识库 + 调试助手
项目最终形态
┌─────────────────────────────────────────────┐
│ │
│ OLED 显示 │
│ ┌─────────────────────┐ │
│ │ 当前: 55.2°C │ │
│ │ 目标: 55°C ████░ │ ← 加热功率条 │
│ │ 加热中... PWM:72% │ │
│ └─────────────────────┘ │
│ [SET] [UP] [DOWN] │
│ │
│ ┌──────┐ ┌──────────┐ │
│ │ NTC │ ────→ │ STM32 │──→ 加热片 │
│ │ 探头 │ ADC │ F103 │ PWM │
│ └──────┘ │ │ │
│ └──────────┘ │
│ │ │
│ ├─→ OLED (I2C) │
│ ├─→ 串口 (USART) │
│ └─→ LED 状态指示 │
│ │
└─────────────────────────────────────────────┘
功能清单:
-
实时测温(NTC + ADC),精度 ±1°C
-
OLED显示当前温度、目标温度、加热功率
-
三个按键:设定 / 加 / 减
-
PID闭环自动恒温控制
-
PWM调节加热功率
-
串口实时数据输出(可画温度曲线)
-
安全保护:NTC开路检测、过热保护、看门狗
第一步:环境搭建 ------ 让芯片跑起来
目标
工具链就绪 + AI助手上线 + 第一个程序烧录成功。
硬件连接
STM32 Blue Pill ST-Link V2
┌──────────────┐ ┌──────────┐
│ SWDIO ───────┼────────┤ SWDIO │
│ SWCLK ───────┼────────┤ SWCLK │
│ GND ───────┼────────┤ GND │
│ 3.3V ───────┼────────┤ 3.3V │
└──────────────┘ └────┬─────┘
│
┌────────┴─────┐
│ USB → PC │
└──────────────┘
软件安装
| 方案 | 工具 | 适合 |
|---|---|---|
| 方案A | STM32CubeIDE(官方IDE) | 稳,但AI支持一般 |
| 方案B(推荐) | VSCode + PlatformIO + Claude/Cursor | AI原生工作流 |
推荐方案B的安装步骤:
-
安装 VSCode
-
安装 PlatformIO 插件
-
配置 AI 助手(Cursor 或 Claude Desktop)
AI对话例
你: "PlatformIO新建STM32F103C8T6项目,让PC13脚LED闪烁500ms,生成完整代码"
AI: [生成 platformio.ini + main.c]
你: "解释一下:RCC_APB2ENR是什么?为什么操作GPIO前要先操作它?"
AI: [解释时钟使能的原理]
你: "GPIO_BSRR和GPIO_ODR有什么区别?什么时候用哪个?"
AI: [解释位操作 vs 读写操作,原子性问题]
验证标准
-
编译通过,0错误0警告
-
ST-Link识别到芯片
-
烧录成功
-
板载LED(PC13)稳定闪烁,周期1秒
-
你用万用表测PC13电压,高电平≈3.3V,低电平≈0V
-
你能用自己的话解释:这段代码从main()开始到LED亮灭,芯片内部发生了什么
关键概念
| 概念 | 一句话解释 |
|---|---|
| GPIO | 芯片的"手脚",可以输出高低电平或读取外部信号 |
| 寄存器 | 芯片内部的"开关",写1/0控制芯片行为,每个寄存器有固定地址 |
| 时钟 | 芯片的"心跳",每个外设用之前必须先给它"开钟" |
| 推挽输出 | 能主动输出高电平和低电平,驱动能力强 |
| volatile | 告诉编译器"别优化这个变量,每次都要真的读硬件" |
第二步:GPIO输入 ------ 按下按钮,点亮LED
目标
理解数字输入、上下拉电阻、机械消抖。
硬件连接
3.3V
│
├── 内部上拉(约40KΩ)
│
PB0 ────┼────[按钮]──── GND
│
└── 读取IDR寄存器
重要:按钮接在PB0和GND之间。按下 = 读到0,松开 = 读到1(因为有内部上拉)。 你也可以外接10KΩ上拉电阻到3.3V,两者等效。
AI对话例
你: "PB0接一个按钮(按下接GND,松开上拉到3.3V),按下时PA0的LED翻转。加20ms消抖。"
AI: [生成带消抖的按钮检测代码]
你: "消抖为什么要延时?20ms这个值怎么来的?"
你: "如果我不用内部上拉,浮空输入会有什么问题?"
代码骨架(AI生成,你审查)
// AI会生成类似这样的代码 ------ 你要能看懂每行,而不是复制粘贴
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) {
HAL_Delay(20); // 消抖 ------ 为什么要等?
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); // 翻转LED
while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET); // 等释放
}
}
验证标准
-
按一次按钮 → LED状态翻转一次(不会一次按出多次翻转)
-
用万用表测PB0:松开=3.3V,按下=0V
-
你能解释:把按钮接在PB0和3.3V之间(去掉GND),需要改成下拉模式------代码要改什么?
第三步:USART串口 ------ 让芯片开口说话
目标
建立调试通道。后续每一步的数据可视化全靠它。
硬件连接
STM32 USB-TTL (CH340)
PA9 (TX) ──────────── RX
PA10 (RX) ──────────── TX
GND ──────────── GND
│
USB → PC
PC端:打开串口助手,波特率115200
注意:TX接RX,RX接TX,GND必须共地。
AI对话例
你: "在PlatformIO STM32F103上把printf重定向到USART1,波特率115200。PA9=TX PA10=RX"
AI: [生成 USART 初始化 + fputc重定向代码]
你: "为什么PA9和PA10要配置成GPIO_MODE_AF_PP?AF是什么意思?"
你: "波特率115200是怎么算出来的?72000000/16/115200 等于多少?"
验证标准
-
PC串口助手收到 "Hello from STM32!\r\n"
-
按下按钮时,串口打印 "Button Pressed! Count: N"
-
每隔1秒打印一次 "Tick: N"(用HAL_GetTick())
-
你能解释:为什么STM32输出的是TTL电平,而电脑USB口需要CH340模块转换?
从这一步开始养成习惯
以后所有调试,打开串口助手看数据。不要猜!
第四步:ADC测温 ------ 把温度变成数字
目标
理解模拟采样、ADC量化、电压→物理量换算。
硬件连接
3.3V
│
┌┴┐
│ │ NTC 10KΩ @25°C, B=3950
│ │ (温度越高,电阻越小)
└┬┘
│
├────── PA1 (ADC12_IN1)
│
┌┴┐
│ │ R_ref 10KΩ 1%
│ │
└┬┘
│
GND
工作原理:NTC和固定电阻串联分压。温度变化 → NTC阻值变化 → 分压变化 → ADC读数变化 → 温度计算。
AI对话例
你: "PA1配置ADC1,12位精度,每1秒采样一次。10KΩ B=3950 NTC,参考电阻10KΩ接GND,3.3V供电。写温度计算函数,结果用printf打印。"
AI: [生成ADC配置 + 温度换算]
你: "这个温度公式每一步在算什么?"
你: "Steinhart-Hart方程和B值简化公式有什么区别?我这个场景用哪个?"
你: "ADC读到2048对应几V?对应NTC多少Ω?对应多少度?一步步算给我看。"
温度换算公式
// ADC → 电压
float voltage = adc_value * 3.3f / 4095.0f;
// 电压 → NTC电阻(下分压电路)
float r_ntc = (3.3f - voltage) * 10000.0f / voltage;
// NTC电阻 → 温度(B值公式)
float temp = 1.0f / (logf(r_ntc / 10000.0f) / 3950.0f + 1.0f / 298.15f) - 273.15f;
验证标准
-
串口每秒打印 "ADC: 2048, R: 10000, Temp: 25.0°C"
-
用手捏NTC → 温度上升2-5°C
-
用冰水混合物(≈0°C)校准:误差 < ±2°C
-
用手边的温度计(水银/电子均可)做对比验证
-
你能从头推导一遍:给定ADC值 → 算出温度
第五步:定时器PWM ------ 让呼吸灯会呼吸
目标
理解定时器、PWM原理、频率和占空比计算。
硬件连接
PA0 (TIM2_CH1) ──→ [220Ω] ──→ LED ──→ GND
PWM原理
ARR (自动重载) = 周期
CCR (比较值) = 占空比
┌──────┐ ┌──────┐
输出 │ ON │ OFF │ ON │
┘ └────────┘ └────
← CCR →← ARR-CCR →
←────── ARR ──────────→
频率 = 定时器时钟 / (PSC+1) / (ARR+1)
占空比 = CCR / ARR
AI对话例
你: "TIM2_CH1, PA0,72MHz,输出1kHz PWM,占空比呼吸效果:0→100%→0,步进1%,每步10ms"
AI: [生成TIM2 PWM配置 + 呼吸灯代码]
你: "72M/(71+1)/(999+1)=1kHz,这71和999怎么来的?为什么PSC和ARR要+1?"
你: "如果我要100Hz呢?改哪个参数?"
你: "CCR=500在ARR=999时,占空比是多少?"
验证标准
-
LED呈现平滑呼吸效果(不是频闪)
-
用逻辑分析仪/示波器看PA0波形,验证频率=1kHz
-
占空比=50%时,波形高电平时间=0.5ms(用示波器验证)
-
你能在白板上画出:72MHz → 预分频 → 1MHz → ARR=999 → 1kHz 这条计算链
第六步:I2C OLED ------ 给芯片配一个显示器
目标
掌握I2C通信协议,理解从机地址、开漏输出、ACK机制。
硬件连接
STM32 OLED (SSD1306)
PB6 (I2C1_SCL) ──────── SCL
PB7 (I2C1_SDA) ──────── SDA
3.3V ──────── VCC
GND ──────── GND
SCL和SDA各接4.7KΩ上拉电阻到3.3V(部分模块已内置)
I2C协议速览
起始: SDA在SCL高电平时从高→低
数据: SCL低时SDA变化, SCL高时SDA稳定
应答: 第9个SCL脉冲, 从机拉低SDA = ACK
停止: SDA在SCL高电平时从低→高
帧格式: [起始] [从机地址+R/W] [ACK] [寄存器地址] [ACK] [数据] [ACK] ... [停止]
SSD1306地址: 0x3C (7bit) → 0x78 (写) / 0x79 (读)
AI对话例
你: "帮我写一个SSD1306 I2C OLED驱动,只需要三个功能:清屏、写字符串(5x7字体)、画矩形。用STM32 HAL库I2C1"
AI: [生成完整驱动]
你: "为什么要用开漏输出而不是推挽?上拉电阻的作用是什么?"
你: "如果我没接上拉电阻,I2C会怎样?帮我用示波器看看波形就知道了。"
你: "I2C的ACK是什么意思?如果从机不应答,代码怎么处理?"
验证标准
-
屏幕显示 "Hello Embedded!"
-
显示第4步的实时温度:"Temp: 25.3C"
-
用逻辑分析仪抓到I2C波形,识别出:起始条件 → 0x78 → ACK → 数据字节 → 停止条件
-
你能画出 I2C 写一个字节的完整时序图(SCL + SDA)
第七步:按键交互 ------ 设定你的目标温度
目标
状态机编程、人机交互设计、SysTick定时器。
硬件连接
PB0 (SET) ── [按钮] ── GND (启用内部上拉)
PB1 (UP) ── [按钮] ── GND
PB10(DOWN) ── [按钮] ── GND
按键逻辑
状态机:
[正常模式] ───SET按下───→ [设定模式,数字闪烁]
│
UP/DOWN ←───────┤ 目标温度 ±1
│
5秒无操作或再按SET ──→ [正常模式]
AI对话例
你: "设计一个三按键温度设定UI:SET键切换模式,UP/DOWN调节目标温度30-80°C。设定模式下数字闪烁,5秒超时退出。非阻塞实现,用状态机。"
AI: [生成按键状态机代码]
你: "这个状态机有哪些状态?每个状态之间转移的条件是什么?"
你: "为什么不用while(HAL_GPIO_ReadPin(...))这种阻塞方式?阻塞会带来什么问题?"
验证标准
-
OLED显示两行:当前温度(大字) + 目标温度(如 "SV: 55C")
-
按SET进入设定,目标温度数字闪烁(500ms周期)
-
UP/DOWN调整目标温度,范围30-80°C
-
再按SET 或 5秒超时退出设定
-
串口打印每次设定变更:"Setpoint: 55°C"
-
按键响应不阻塞温度读取和显示更新
第八步:PWM功率驱动 ------ 让加热片热起来
目标
PWM控制大电流负载,掌握MOSFET开关应用。
硬件连接
PA6 (TIM3_CH1) ── [1KΩ] ──┬── MOSFET Gate (IRLZ44N)
│
│ IRLZ44N 引脚:
+5V电源 ── [加热片] ────── MOSFET Drain (中间脚)
│
MOSFET Source (右脚) ── GND
续流保护:
二极管(1N5819)反向并联加热片(阴极接+5V,阳极接Drain)
为什么用IRLZ44N? 它是"逻辑电平"MOSFET,3.3V就能完全导通。普通MOSFET需要10V栅极电压,用3.3V驱动会半开半闭(发热严重)。
栅极电阻1KΩ:限制充放电电流,防止PWM边沿过冲振荡。
续流二极管:加热片是感性负载,关断时会产生反向高压,二极管提供续流回路。
AI对话例
你: "TIM3_CH1, PA6, 1kHz PWM输出控制加热片。占空比0-100%对应0-100%功率。同时把当前PWM值显示在OLED上。"
你: "为什么MOSFET栅极要串1KΩ电阻?不串会怎样?"
你: "为什么选IRLZ44N而不是IRF540N?逻辑电平MOSFET和普通MOSFET的区别是什么?"
你: "二极管为什么要反并联在加热片上?这个二极管叫什么名字?"
验证标准
-
占空比0% → 加热片不发热
-
占空比50% → 温热(用NTC贴在加热片上验证温度)
-
占空比100% → 明显发热
-
用手摸MOSFET------不烫。烫 = 栅极驱动电压不足,工作在放大区
-
串口打印:占空比(%) + NTC温度 + 对应关系合理
-
示波器看PA6波形和MOSFET Drain波形一致(PWM正常)
第九步:PID闭环控制 ------ 让温度自动停在你设定的值
目标
理解反馈控制原理、PID三参数的作用、闭环vs开环。
控制原理
┌──────────┐
目标温度(SV) ──→(+)──→ PID控制器 ──→ PWM ──→ 加热片 ──→ 实际温度(PV)
↑ - │
│ │
└─────────── NTC反馈 ───────────────────┘
误差 e = SV - PV
当 e>0 (温度不够) → 加大PWM → 加热
当 e<0 (温度过高) → 减小PWM → 自然冷却
当 e≈0 (温度正好) → PWM维持稳态
PID公式
Output = Kp × e + Ki × Σe + Kd × (e - e_prev)
P项(比例): 现在差多少? → 快速响应
I项(积分): 累积差了多少? → 消除稳态误差
D项(微分): 变化有多快? → 抑制超调, 预测趋势
调参直觉:
P太大 → 震荡 P太小 → 响应慢, 到不了目标
I太大 → 超调严重 I太小 → 有稳态误差(差几度停不下来)
D太大 → 噪声敏感 D太小 → 超调抑制不住
AI对话例
你: "帮我实现一个位置式PID控制器。输入:当前温度、目标温度;输出:PWM占空比0-100%。每秒调用一次。参数要可调。"
AI: [生成PID实现]
你: "我的温度一直震荡,帮我分析是哪个参数的问题?给出调参方向。"
你: "积分饱和是什么?我的代码里怎么防止积分饱和?"
你: "为什么控制周期(1秒)很重要?太快或太慢会有什么问题?"
PID代码骨架(AI生成,你审查)
typedef struct {
float kp, ki, kd; // PID三参数
float setpoint; // 目标温度
float integral; // 积分累积
float prev_error; // 上一次误差(D项用)
float integral_limit; // 积分限幅(防饱和)
float output_limit; // 输出限幅(0-100)
} PID_Controller;
float PID_Compute(PID_Controller *pid, float current_temp) {
float error = pid->setpoint - current_temp;
// P 项
float p_term = pid->kp * error;
// I 项 (带限幅)
pid->integral += error;
if (pid->integral > pid->integral_limit)
pid->integral = pid->integral_limit;
if (pid->integral < -pid->integral_limit)
pid->integral = -pid->integral_limit;
float i_term = pid->ki * pid->integral;
// D 项
float d_term = pid->kd * (error - pid->prev_error);
pid->prev_error = error;
// 合并且限幅
float output = p_term + i_term + d_term;
if (output > pid->output_limit) output = pid->output_limit;
if (output < 0) output = 0;
return output;
}
调参实操(最重要的学习环节)
初始值: Kp=5.0, Ki=0.1, Kd=1.0
步骤1: 先只调P(Ki=0, Kd=0)
加大Kp直到出现轻微震荡 → 取震荡Kp的60-70%
步骤2: 加I(消除稳态误差)
小幅增加Ki → 温度能稳定到目标了
步骤3: 加D(抑制超调)
增加Kd → 升温更快但不超调
把串口数据导出来画曲线!
- 横轴时间, 纵轴温度
- 观察: 上升时间、超调量、稳定时间、稳态误差
验证标准
-
设定55°C,从室温25°C加热,最终稳定在55±1°C
-
串口每秒打印:
T:25.3 SV:55.0 Err:29.7 PID:72.5 PWM:72 -
导出串口数据,用Excel/Python画出温度曲线
-
改变设定值(如55→45),观察系统跟踪新目标
-
用手摸加热片(模拟扰动如加冷水杯)→ 系统自动加大功率恢复
-
你能解释:为什么纯P控制(Ki=0, Kd=0)永远到不了目标?积分的作用是什么?
-
调Kp到很大,观察震荡 → 理解"比例带"
第十步:系统集成 ------ 从demo到产品
目标
整合所有模块、处理异常情况、打磨用户体验。
集成架构
int main(void) {
HAL_Init(); // HAL库初始化
SystemClock_Config(); // 时钟配置
GPIO_Init(); // 按键、LED
ADC_Init(); // 温度传感器
PWM_Init(); // 加热控制
UART_Init(); // 调试串口
OLED_Init(); // 显示屏
PID_Init(&pid); // PID控制器
OLED_ShowLogo(); // 开机Logo
HAL_Delay(2000);
while (1) {
// 每1秒执行一次控制循环
if (HAL_GetTick() - last_tick >= 1000) {
last_tick = HAL_GetTick();
float temp = Read_Temperature(); // ADC+NTC
float pwm = PID_Compute(&pid, temp); // PID计算
Set_PWM(pwm); // 更新加热
OLED_Update(temp, pid.setpoint, pwm); // 刷新显示
Debug_Print(temp, pid.setpoint, pwm); // 串口输出
Safety_Check(temp); // 安全检查
}
Key_Scan(); // 按键扫描(非阻塞, 每循环都跑)
}
}
异常处理
| 异常 | 检测方式 | 处理 |
|---|---|---|
| NTC开路 | ADC值≈4095(接近VCC) | 停止加热,OLED显示"ERR NTC" |
| NTC短路 | ADC值≈0 | 停止加热,OLED显示"ERR NTC" |
| 过热保护 | 温度 > 85°C | 强制PWM=0,OLED显示"OVERHEAT!" |
| 加热超时 | 加热30分钟温度不升 | 停止加热,报警 |
| 系统跑飞 | 看门狗未按时喂狗 | 自动复位 |
看门狗配置(AI生成)
你: "STM32F103配置独立看门狗IWDG,喂狗周期1秒,在main循环里喂狗。如果主循环卡死超过1秒,自动复位。"
AI: [生成IWDG配置代码]
最终验收标准
功能验收:
-
上电 → OLED显示Logo 2秒 → 进入主界面
-
主界面:当前温度(大字) + 目标温度 + 加热功率条
-
三个按键操作流畅、响应即时、不卡屏
-
恒温精度:稳态 ±1°C
-
从室温到55°C升温时间记录在案
-
串口每秒输出完整数据行
安全验收:
-
拔掉NTC → 显示 "ERR" + 停止加热
-
温度 > 85°C → 强制停止加热
-
连续运行 1 小时不崩溃
-
拔掉电源再插 → 正常运行
理解验收(对AI或面试官):
-
画出系统框图,标出所有数据流
-
说出每个外设用了MCU的什么模块
-
解释PID为什么能让温度稳定
-
说出至少3个可能导致事故的硬件故障,以及你的代码如何应对
AI协作黄金法则
✅ AI擅长的(放心用):
-
生成外设初始化代码(GPIO、UART、ADC、PWM、I2C 等)
-
生成驱动框架(SSD1306 OLED、NTC温度换算、PID控制器)
-
解释你不懂的概念("volatile是干什么的?")
-
分析bug(粘贴异常日志/现象)
-
提出优化建议("这段代码有什么问题?")
-
对比技术方案("中断 vs 轮询,什么时候用哪个?")