基于STM32的智能温控风扇系统:硬件设计、PWM调速与Proteus仿真
1. 这个项目解决了什么问题从风扇傻转到温度自适应做嵌入式开发的朋友大概都有过这种体验手头有个DC风扇想给功放或者机箱散热于是接个电源让它转温度高了低了它都一个转速。夏天负载上来的时候机箱里热得能煎鸡蛋风扇却不会自动加速只能手动去拨开关。又或者反过来温度已经降下来了风扇还在满转速轰鸣晚上睡觉吵得人头疼。我自己就踩过这个坑。之前做了个桌面功放末级管发热量不小随手装了个12cm机箱风扇24小时满速转噪音大不说还积灰。后来实在忍不了决定用STM32做个智能温控风扇系统把温度采集、自动调速、状态显示全都做进去顺便把代码、原理图、仿真工程整理好开出来给同样被散热问题困扰的朋友一个直接能用的参考方案。先给这个项目定个位。它是一套基于STM32F103C8T6主控的温控风扇系统核心功能是通过DHT11温湿度传感器采集环境温度也兼容DS18B20方案后面说差异根据温度阈值自动切换风扇转速档位支持PWM无级调速和档位调速两种模式用OLED显示屏实时显示温度、湿度、当前转速百分比和工作模式支持按键手动干预切模式、调阈值、开关风扇附带Proteus仿真工程没有实物板子也能把逻辑跑通电路用立创EDA绘制源工程和Gerber文件一并开源这套方案最实用的场景是电脑机箱散热改造、功放/胆机散热、3D打印机热端散热、智能家居温控节点。甚至你把它改巴改巴把DHT11换成DS18B20探头塞到水里就能当鱼缸水温控制器的原型。我选择STM32F103C8T6而不是Arduino或ESP32理由有三条第一F103C8T6是入门级ARM芯片里资料最全、价格最低、生态最成熟的型号之一某宝几块钱一片最小系统板十几块就能买到。开源出去别人想复现的成本很低。第二这个项目要讲PWM、定时器、ADC、I2C、GPIO中断F103C8T6的片上资源刚好全覆盖非常适合作为学习案例。做完这个项目你对STM32外设的掌握会上一个台阶。第三Proteus对F103系列的支持已经很完善仿真模型可以直接用不需要额外装第三方库。这点在做开源项目时很重要——别人下载你的工程拖进去就能跑不需要折腾环境。适合谁来参考如果你是刚学完STM32基础外设、想做点有完整功能的小项目的学生或者想把手头散热设备改造成智能控制的电子爱好者这个项目正好在你能力圈和兴趣圈的交叉点上。如果你只是想抄个作业、快速搞定一个温控风扇那更简单代码和原理图都是现成的照着焊就行。2. 硬件设计与原理图拆解为什么选这些芯片、这些引脚2.1 系统整体架构整机电路分为五个模块电源、主控、传感、执行、交互。我用一张表格把各部分核心器件和选型理由列出来然后逐个拆解。模块核心器件选型理由电源AMS1117-3.3 5V输入输入范围宽电路简单够用且便宜主控STM32F103C8T6生态成熟外设齐全Proteus有现成模型传感DHT11温湿度传感器单总线协议简单入门友好够用执行2N2222三极管 12V风扇小功率风扇用三极管开关/PWM足够成本低交互0.96寸OLED(I2C) 按键×3I2C省引脚OLED显示内容丰富3个按键够操作2.2 电源电路别在电源上省钱省事电源是整个系统的地基。我见过太多新手项目死在电源上——主控芯片供电不稳程序跑飞传感器读数跳动查半天找不到原因。这个项目支持两类供电方式USB 5V供电适合调试和仿真阶段直接给STM32最小系统的5V引脚供电经AMS1117降到3.3V给芯片和OLED用DC 5.5mm接口 / 接线端子12V供电适合实际驱动风扇时使用因为很多机箱风扇和功放散热风扇都是12V规格电源电路设计要点5V/12V输入 ── 100uF电解电容(滤低频纹波) ── AMS1117-3.3 ── 100nF瓷片电容(滤高频噪声) ── 3.3V电解电容和瓷片电容一个都不能省。电解电容负责吸收输入电源的低频纹波瓷片电容放在AMS1117输出端滤掉高频开关噪声。没有这两个电容AMS1117的输出波形是带毛刺的ADC采样温度时会莫名其妙跳数字OLED也可能显示花屏。还有一点容易被忽略风扇电机是感性负载启停瞬间会产生反向电动势。所以给风扇供电的12V输出端我并联了一个1N5819肖特基二极管做续流保护方向是反接的。这个二极管可以把反向尖峰钳位掉防止它倒灌进主控电路、把STM32的GPIO打坏。2.3 主控最小系统比最小系统多做的两件事STM32F103C8T6最小系统包含芯片本体、8MHz晶振、两个20pF负载电容、复位电路10k上拉100nF电容按键、BOOT0和BOOT1配置电阻、3.3V去耦电容。晶振的负载电容取值有个经验公式CL (C1×C2)/(C1C2) Cstray。对于8MHz晶振典型负载电容是12~20pF实际我用两个20pF串联加上引脚分布电容约3~5pF等效负载约13~14pF在常见晶振的负载电容范围内。如果你要精调需要查具体晶振型号的数据手册找到CL值再反推C1和C2。比常规最小系统多做的两件事第一VBAT引脚接了3.3V而不是悬空。这样RTC后备区域有供电以后如果你扩展了RTC功能时间不会因为主电源断电而丢失。这个引脚画原理图时很容易漏漏了就是隐患。第二每个电源引脚旁边都放了一个100nF去耦电容并且紧贴引脚布局。STM32F103C8T6虽然已经是老芯片了但内部数字电路翻转时的瞬态电流依然不能忽视。去耦电容的作用是就近提供一个低阻抗的电荷池让芯片取用瞬态电流时不至于把电源电压拉垮。这个在原理图上只是一颗小电容但在实际PCB布局时位置很关键我会在第4节详细说。2.4 DHT11接口电路一个上拉电阻的事DHT11是单总线协议数据线只有一根既要输出又要输入。它的总线空闲状态是高电平所以数据线上必须接一个4.7k~10k的上拉电阻到3.3V。这里有个容易踩的坑DHT11的供电范围是3.3V~5V但如果供电是5V它的数据输出高电平也是接近5V的直接接STM32的GPIO容忍3.3V但推荐值3.6V以下有潜在风险。绝大多数时候它能跑因为DHT11的数据输出驱动能力不强还有上拉电阻分压但严谨的设计应该这样处理方案ADHT11也用3.3V供电。实测DHT11在3.3V下能正常工作只是温湿度测量精度会略有下降手册指标是在5V下标定的方案BDHT11用5V供电数据线上串一个330欧电阻再用一个3.3V稳压管或BAT54S等二极管做电平钳位方案C换成DS18B20数据线同样需要4.7k上拉但它本身的逻辑电平就是3.3V兼容的我在开源工程里选的是方案ADHT11供电直接用3.3V。原因很简单省一颗电平转换芯片电路简化而且这个项目是温控风扇场景温度精度偏高1度低1度不影响实际使用。如果你要做的是精密温控设备建议换DS18B20或者SHT30这些传感器本身就是3.3V器件精度也更高。2.5 风扇驱动电路三极管、MOS管还是ULN2003这是整个原理图里最值得展开讲的部分因为风扇驱动选型直接决定系统能带动多大功率的风扇。先说结论这个项目默认采用2N2222三极管 12V风扇的方案同时原理图预留了MOS管驱动的替换位。三极管方案的原理是这样的STM32 PA1引脚 ── 1kΩ限流电阻 ── 2N2222基极 12V ── 风扇正极 风扇负极 ── 2N2222集电极 2N2222发射极 ── GNDNPN三极管用作低边开关基极由STM32的GPIO通过1k电阻驱动。当PA1输出高电平时基极电流约 (3.3V - 0.7V) / 1k ≈ 2.6mA2N2222进入饱和导通集电极-发射极压降Vce(sat)约0.3V风扇得到约11.7V电压正常旋转。当PA1输出低电平时三极管截止风扇停转。同时风扇两端并联一个1N5819二极管方向是从GND指向12V反接。风扇停转瞬间其内部线圈会试图维持原来方向的电流产生一个反向感应电动势这个二极管给反向电流提供一个泄放回路保护三极管不被击穿。那为什么不直接用STM32 GPIO驱动风扇因为GPIO的灌电流/拉电流能力典型值只有8mA左右而一个12V的电脑风扇正常工作电流少说200mA启动瞬间电流更大。直接用GPIO驱动轻则发热降不住重则烧毁引脚。为什么不选ULN2003 ULN2003是达林顿阵列集电极开路输出单路电流能力500mA驱动小功率风扇完全够用。但它有两个问题一是达林顿管的饱和压降较高典型值1V~1.6V风扇实际得到的电压会偏低转速受影响二是它不能直接输出PWM信号做调速准确说是它能做但开关特性不如MOS管干脆高速PWM下发热更严重。为什么不直接上MOS管MOS管如AO3400饱和导通电阻只有几十毫欧压降几乎可以忽略非常适合PWM调速。但MOS管需要栅极驱动电压AO3400是逻辑电平MOS管3.3V栅压能完全导通这个没问题。不过MOS管的栅极电容较大如果GPIO直接驱动PWM频率高了会有振铃需要加栅极电阻。对于这个项目12V小风扇用三极管已经够了MOS管作为进阶替代方案在原理图里画了但默认不焊。2.6 交互与显示OLED和按键的引脚分配0.96寸OLED用的I2C接口SCL接PB6SDA接PB7这是STM32F103的硬件I2C1引脚。供电3.3VI2C上拉电阻选4.7k。OLED模块一般自带3.3V稳压和上拉所以你买的模块上往往已经有上拉电阻了原理图上可以不再画但为了严谨我还是在PCB上预留了焊盘万一买的模块没有上拉可以自己补。三个按键分别接PA0、PA1、PA2都配置为GPIO输入上拉模式。按键另一端接地按下去时引脚读到低电平。为什么不直接配置下拉、按键接3.3V因为STM32内部上拉电阻默认是使能的省外部电阻而且按键接地在单片机系统里是更常规的做法——断电状态下按键两端不悬空抗干扰能力更好。这里有个复用问题PA1既接三极管驱动风扇又接按键。我在项目里作了如下安排引脚功能备注PA0按键1模式切换上拉输入按键接地PA1风扇PWM输出复用为TIM2_CH2输出PWMPA2按键2阈值上拉输入PA3按键3阈值-上拉输入PB6I2C1_SCL连接OLEDPB7I2C1_SDA连接OLEDPB4DHT11数据开漏输出外部上拉如果你要扫描按键的同时还要PWM输出PA1会冲突。所以我实际是把按键2和按键3放在PA2和PA3上PA1纯粹做PWM输出。看到这里你可能问那按键1为什么放PA0因为PA0同时也是WKUP引脚但我不用待机唤醒功能只做普通输入没问题。2.7 原理图绘制中的几个细节用立创EDA画原理图时这几个细节值得留意第一电源标号的层次关系。VCC_5V、VCC_3V3、VCC_12V分开命名不要都用VCC。否则DRC检查会通过但PCB布线时你很难区分哪个网络是哪个电源域板子画到一半容易乱。第二地在原理图上分模拟地和数字地。这个项目虽然简单但DHT11的模拟信号和PWM的数字开关信号如果共用地线数字噪声容易耦合进传感器信号。我的做法是DHT11的地和电源退耦电容的地走一段单独的地网络AGND在电源入口处通过0欧电阻或直接单点连接到GND。Protel/立创EDA都支持网络标号画起来不麻烦。第三预留测试点。我在PA1、PB6、PB7、3V3、GND这五个网络上加了测试焊盘。调试时示波器探头直接夹上去就能量波形不用拿着镊子去扎芯片引脚。这个习惯强烈建议培养省下的调试时间远超画图多花的五分钟。3. 软件实现状态机、PWM与DHT11时序的完整逻辑硬件只是骨架温控风扇的灵魂在固件逻辑里。这个项目的软件框架不算复杂但有几个关键点必须处理好DHT11的单总线时序、PWM调速策略、按键消抖与长按处理、OLED刷新策略。3.1 整体软件架构我把固件分成三个层次驱动层dht11.c、oled.c、pwm.c、key.c每个文件只负责一个外设的底层驱动业务层temperature.c、fan_control.c处理温度读取后的控制决策应用层main.c维护一个主状态机调度各模块运行代码组织清晰的好处是别人拿到工程后想改温度阈值、换PWM频率、改显示布局都知道去哪个文件改。开源项目好不好用代码结构占一半。主循环的逻辑我用一个很朴素的方式实现while (1) { 读取DHT11温湿度 按键扫描消抖处理 根据当前模式计算目标PWM占空比 更新OLED显示 延时50ms }这个系统对实时性要求不高50ms的循环周期足够让温度显示看起来平滑也不会因为DHT11的慢速采样而卡顿。不采用定时器中断驱动主循环的原因是DHT11单总线时序要求微秒级的精确延时如果用main循环做读到一半被中断打断会导致时序错乱。我的策略是DHT11的读时序放在main循环里执行屏蔽中断临界区保护其他模块通过简单的状态标志交替运行。3.2 DHT11驱动单总线时序的微妙之处DHT11是老熟人但它的时序恰恰是新手最容易翻车的地方。核心问题是DHT11的数据脚是开漏输出高电平依赖上拉电阻所以主机在读取时必须精准控制每个电平的持续时间。完整的读时序分五步主机拉低数据线至少保持18ms建议20ms这是起始信号主机释放数据线上拉电阻把电平拉高延时20~40usDHT11响应拉低80us再拉高80us表示准备好了接下来DHT11输出40位数据8位湿度整数、8位湿度小数、8位温度整数、8位温度小数、8位校验和每个数据位的宽度差异很大50us低电平26~28us高电平表示050us低电平70us高电平表示1我在代码里用的是微秒级延时函数基于SysTick实现。为什么不用普通的for循环空转延时因为空转延时受编译器优化等级影响Debug和Release下延时会差好几微秒时序就崩了。SysTick是硬件定时器精确且稳定。数据校验是个容易被忽视但很重要的环节。DHT11输出的校验和是前四个字节之和的低8位。比如湿度整数40、湿度小数0、温度整数26、温度小数0校验和就是40026066。如果校验不对这一帧数据直接丢弃绝不使用。这样能防住偶发的传感器数据错误。还有个经验DHT11的采样间隔必须大于1秒。数据手册明确写了这个是慢速器件你连续读它会得到不变的假数据。我在代码里做了个简单的时间戳判断距离上次成功读取不足1秒就直接返回上次缓存值不发起新的读取流程。3.3 PWM调速怎么调、调多少、频率选多少风扇调速的本质是调节电机的平均电压。我用STM32的TIM2_CH2输出PWM频率设定为25kHz。这里有一个重要的选型理由人耳对20kHz以下的声音比较敏感PWM频率如果设在几百Hz到几kHz区间风扇线圈会因为电流的脉动发出可闻的啸叫声。25kHz超出了人耳听觉上限听起来就是安静的风声而不是电机的吱吱声。MOS管或三极管的开关损耗在这个频率下也还在可接受范围。占空比映射策略我采用的是两段式温度低于下限阈值默认25°C占空比20%风扇低速运转保证基础风量温度在上限和下限之间25°C~40°C占空比线性插值从20%到100%温度高于上限阈值默认40°C占空比100%全速运转pwm_duty 20 (temp - TEMP_LOW) * 80 / (TEMP_HIGH - TEMP_LOW);这段线性插值代码很直观温度在下限时右边分子为0输出20%温度在上限时输出2080100%。中间按比例变化。为什么不用完整的PID控制因为风扇散热是一个大惯性、慢响应的系统温度变化速率远小于风扇转速响应的速率。PID在这种场景下容易引起转速的振荡——温度稍高就猛加速吹冷了又猛减速循环往复。而且要手动调三个PID参数对用户不友好。线性映射虽然简单但胜在稳定、可预期、容易调试。如果确实想加PID可以在代码的映射函数里替换把温度误差作为输入、占空比作为输出控制框架我已经留好了接口。3.4 按键处理消抖、短按与长按的完整方案按键是这个项目唯一的输入手段处理不好体验会很差。我用的方案是状态扫描防抖延时长短按区分扫描周期20ms连续两次读到相同电平才认为状态有效消抖短按按下时间小于800ms触发模式切换、阈值加减长按按下时间大于800ms触发开关风扇的紧急启停消抖的原理简单说就是机械按键的簧片在按下的瞬间会产生5~10ms的振荡如果你不消抖直接读电平一次按键会被程序误读成好几次。20ms的消抖延时能可靠地跨过这个振荡期。长短按的区分我用了计数法在主循环里维护一个key_press_counter每次扫描到按下就加1释放时判断计数器的值。按20ms一次扫描计算800ms约等于40次扫描所以判断阈值设在40。这个参数我用宏定义想调灵敏度直接改宏就行。3.5 OLED显示什么时候刷新、显示什么OLED虽小但能显示的内容其实不少。我的屏幕布局分三行第一行Temp: 28.5C Humi:45% 第二行Fan: 65% Mode: AUTO 第三行TH: 25C/40C (*SYS*)第一行是温湿度第二行是风扇占空比和当前模式AUTO/MANUAL第三行是当前阈值和系统状态。刷新策略上我做了个简单的脏数据标志只有当温度变化超过0.5°C、或按键状态变化、或模式切换时才调用OLED刷新函数。因为OLED模块内部是SSD1306控制器即使显示内容没变重写整帧屏约耗时20~30msI2C时钟400kHz频繁刷新不仅浪费CPU还可能在刷新过程中和DHT11采样抢总线。实测下来这个优化让主循环的稳定性明显提升。3.6 代码工程结构一览仓库目录结构如下每个目录的职责一目了然SmartFan_STM32/ ├── Core/ # 启动文件、system_stm32f10x.c ├── HAL/ # STM32标准外设库或HAL库 ├── BSP/ # 板级驱动dht11.c, oled.c, key.c, pwm.c ├── App/ # 业务逻辑fan_control.c, display.c ├── MDK-ARM/ # Keil5工程文件 └── Hardware/ # 原理图源文件、PDF、Gerber4. 仿真工程搭建没有实物也能完整跑通逻辑这个项目我特意做了Proteus仿真工程原因很实在很多关注开源项目的人还没买齐硬件或者担心照原理图焊完万一不工作怎么办。仿真可以零成本地把核心逻辑先验证一遍。4.1 Proteus仿真准备工作Proteus 8.6以上的版本自带STM32F103C8T6模型不需要额外装第三方库。但我第一次使用Proteus仿真STM32时还是栽了个跟头默认的芯片模型没有内部Flash加载HEX文件的入口。解决办法是双击芯片在Program File的弹窗里把Keil编译出来的hex文件路径填进去然后点OK仿真时芯片会自动加载这个固件。另一个容易踩的坑是Proteus里的晶振设置和代码里的系统时钟不一致。我工程里配置的是外部8MHz晶振、72MHz主频但如果你在Proteus里把芯片属性页的Crystal Frequency设成默认的4MHz那程序里的延时全部会变成两倍多DHT11时序直接乱掉。仿真图里右下角有一个CRYSTAL元件模型我把它的频率属性改成8MHz并确认代码里RCC配置为HSEPLL倍频到72MHz时序才恢复正常。所以这里有个仿真调测的技巧如果仿真时风扇的PWM输出频率明显不对先查芯片模型的晶振频率设置再查代码里的时钟初始化。这两个地方任何一个不匹配都会导致外设时序异常而且这种异常在仿真里比实物更难排查——因为示波器看波形频率你不确定是代码问题还是模型配置问题。4.2 仿真工程的元件清单与连接Proteus仿真工程的元件清单和硬件几乎一一对应Proteus元件对应硬件参数/型号STM32F103C8T6主控晶振8MHzDHT11温湿度传感器默认模型OLED0.96寸OLEDI2C地址0x3CMOTOR-DC12V直流风扇用直流电机模型代替Resistors限流/上拉电阻1k, 4.7k, 10kBUTTON按键×3默认模型LED电源指示灯绿色LED220Ω限流注意Proteus里没有风扇模型我用直流电机模型MOTOR-DC代替并在电机两端并联了一个反向二极管模拟实际风扇的感性负载特性。这样仿真时能直观看到PWM占空比不同、电机转速不同同时也能验证续流二极管的保护逻辑在仿真层面是否正确。DHT11的Proteus模型用起来有个细节它默认输出的是一个固定值你需要在仿真运行时点击传感器模型在弹出的窗口里手动调整温度和湿度值。仿真的意义在于验证你的读取时序、校验逻辑、控制策略是否正确而不是验证传感器本身准不准。所以每次修改温度后观察风扇PWM和OLED显示是否随之变化这就是仿真该干的事。4.3 仿真调试中我遇到的三类问题第一类DHT11读不到数据OLED一直显示ERR。排查下来是Proteus模型的上拉电阻没加。模型本身不带内置上拉数据线浮空时序读出来全是乱码。加上4.7k上拉后正常。第二类按键仿真时触发了两次动作。这是因为Proteus里的模型没有机械抖动但我的代码是默认有消抖的。消抖逻辑在实物上没问题在仿真里反而被消出问题了——因为仿真里按键按下是瞬间稳定电平20ms的消抖延时导致读到两次。后来我把消抖逻辑改成边沿触发延时确认仿真和实物都没问题了。第三类OLED花屏或显示残缺。这个问题的根因是I2C时序不匹配。Proteus的OLED模型对I2C时序要求比较严我当时代码里I2C时钟设成400kHz仿真模型的时序跟不太上。把I2C时钟降到100kHz标准模式花屏问题消失。实物用400kHz完全没问题这个就是仿真模型的局限了。4.4 仿真到实物的过渡提醒仿真通过不代表实物一定一次成功。我在这套系统上从仿真到实物的过程中有三处和仿真不一致的体感仿真的DHT11是理想化的读取时序任何微秒级偏差都能容忍实物的DHT11对时序更敏感特别是起始信号的18ms低电平、数据位的60~70us高电平判断差一点就超时或误判。我的建议是代码里用SysTick延时别用for循环空转。仿真里的直流电机模型是理想负载没有启动瞬间的浪涌电流实物风扇启动瞬间电流可能是额定电流的3~5倍。所以实物电路里12V供电线上我加了一个470uF电解电容做储能缓冲否则电源适配器可能被拉垮保护。仿真里电源是理想源没有压降实物用USB供电时线材电阻和接触电阻会产生压降STM32GPI O高电平可能低于3.3V标称值。所以实物上我测过PA1引脚在驱动三极管时的实际电平确认还能稳定拉高到2.8V以上2N2222的Vbe只需要0.7V所以这个电平完全够用这才放心。5. 从编译到下载排雷Keil、固件库与下载器的实战经验这一节写给第一次接触STM32开发、或者在自己的电脑上重新搭建环境的朋友。整个BSP工程我基于STM32标准外设库V3.5编写虽然HAL库已经很流行了但我选标准库的原因是这个项目的控制逻辑不依赖复杂的CubeMX初始化——外设少、配置简单标准库代码更直白读起来更好懂。5.1 工程编译的正确打开方式用Keil5打开MDK-ARM目录下的工程文件后第一件事不是点编译而是检查三个配置芯片型号工程里的芯片默认就是STM32F103C8但如果你用的Keil版本不一致芯片型号可能被重置需要去Device选项卡确认选择的是STM32F103C8C/C选项卡里的Define需要包含USE_STDPERIPH_DRIVER,STM32F10X_MD。前者告诉编译器编译标准外设库的驱动代码后者告诉编译器芯片是中等容量产品64KB或128KB Flash这个头文件的宏定义会影响启动文件里中断向量表的大小配置下载器配置如果你用的是ST-Link V2在Utilities选项卡里选择ST-Link Debugger并设置Flash Download里的编程算法为STM32F10x Med-density Flash 64K我遇到过最诡异的问题代码编译零错误警告但下载后芯片完全无反应全速运行也不会进主循环。排查到最后发现是启动文件选错了。proteus工程里用的是startup_stm32f10x_md.s中等容量但有人在MDK里默认生成的是startup_stm32f10x_hd.s高密度两者的中断向量表偏移不同导致芯片一上电就跑飞了。这个坑不细查根本发现不了。5.2 下载器和调试器常见报错速查我在开源说明里整理了几条常见报错这里挑最典型的展开讲。Keil提示Error: Flash Download failed - Cortex-M3大概率是编程算法没选对。在Utilities → Settings → Flash Download里勾选Reset and Run同时注意算法里地址范围要覆盖芯片的Flash大小。F103C8是64KB Flash算法选错成128KB的也能编译但下载时会报地址越界。Keil提示No STM32 Target Found这个问题在ST-Link资料下载里出现频率极高。造成原因有三种一是接线错误——SWDIO接PA13、SWCLK接PA14、GND必须共地这三根线缺一不可二是目标板供电不足——ST-Link的3.3V输出能力很弱如果目标板还有OLED和DHT11在跑ST-Link可能带不动三是目标板上电顺序有问题需要先给目标板上电再连接调试器。实话说我见过很多芯片是不是坏了的求助帖最后90%都是接线松了或者没共地。ST-Link的虚拟串口有黄色感叹号驱动装好了设备管理器里能看到STM32 STLink Virtual COM Port但带着感叹号。这个一般不是驱动问题而是你插入的ST-Link被另一个程序占用了。关掉Keil的调试会话再重新插拔即可。如果还不行去ST官网下最新的ST-Link驱动覆盖安装。5.3 如何快速定位程序烧了但没反应的问题程序下载成功、芯片也识别到了但运行起来没有任何现象。我建议按这个顺序排查用调试器单步执行到main函数入口确认有没有跑进死循环启动文件配置错误时程序根本到不了main用万用表量3.3V和GND之间电压确认AMS1117输出正常用示波器看8MHz晶振引脚有没有起振没示波器就摸芯片温度——晶振没起振时芯片基本不发热程序跑起来后芯片会有轻微温升写一个最简单的GPIO翻转程序让PB0引脚交替输出高电平和低电平用LED验证最小系统是否工作第4步是我强烈推荐的最小系统验证法。不带外设、不跑复杂逻辑单独验证主控能不能跑、GPIO能不能翻转。这个测试程序如果都跑不起来问题多半在硬件最小系统跑起来了说明主控没问题问题在某个外设的初始化或接线。5.4 用VS Code开发STM32可以但没必要现阶段我注意到VSCode开发STM32的教程最近热度很高确实可以用EIDE插件或者PlatformIO都能把工程搭起来。但如果你是这个项目的新手用户我建议老老实实用Keil5。原因很实在这个开源工程是Keil的工程结构用VS Code打开需要重新配置编译链、烧录器等一堆东西纯折腾STM32标准外设库的启动文件、分散加载文件这些在Keil里是默认配置好的换到VS Code环境都要手动配Keil的调试器界面虽然古老但寄存器查看、外设查看的完整度对初学者理解芯片状态有很大帮助VS Code的优势在代码阅读和git管理上等你把这个项目跑通了、想二次开发或者重构成自己的代码风格那时候再折腾VS Code不迟。6. 开源仓库说明与二次开发方向这套代码还能怎么玩6.1 仓库文件清单开源仓库里包含的文件如下别人下载后能直接复现整个项目文件/目录说明MDK-ARM/SmartFan.uvprojxKeil5工程文件双击打开即可编译Hardware/SmartFan_Sch.pdf原理图PDF版本没装EDA软件也能看Hardware/SmartFan_PCB.pdfPCB布线图PDFHardware/gerber/Gerber文件可直接发给板厂打样Simulation/SmartFan.pdsprjProteus仿真工程Doc/使用说明.md接线说明、按键操作说明、阈值修改教程README.md项目概述、硬件清单、视频演示链接强调一下原理图和PCB源文件我用的是立创EDA专业版工程文件是Hardware/SmartFan_LCEDA.json导入立创EDA即可编辑。为什么选立创EDA而不是Altium Designer因为开源项目的宗旨是降低复现门槛——立创EDA免费、免安装、浏览器就能打开别人想改原理图不需要去装十几个G的AD。6.2 二次开发方向这部分是我最想对拿到代码的朋友说的。直接抄作业固然能用但改成适合自己的才有意思。我给几个具体的方向方向一换DS18B20提升精度。DHT11的温度精度是±2°CDS18B20是±0.5°C。换传感器后只需要重写读取函数和数据处理函数控制逻辑完全不用动。DS18B20支持单总线上挂多个如果你想做多路测温机箱前部、后部、CPU周边这个扩展很自然。方向二加蓝牙/串口远程监控。F103C8T6有多个UART我预留了USART1的引脚PA9/PA10没占用。接一个HC-05蓝牙模块把温湿度和风扇转速通过串口发到手机就是一个小型的物联网温度监控节点。方向三改造成无级调光器。把DHT11换成光敏电阻用ADC采集风扇换成LED灯打开代码里注释掉的光照控制段落这个系统立刻变身智能夜灯——环境光暗了自动亮灯亮了自动灭灯。同样的PWM输出逻辑改一下传感器和映射函数而已。方向四加过热报警。用PWM输出的同一路GPIO加一个蜂鸣器驱动当温度超过上限阈值且持续10秒以上时蜂鸣器响、OLED闪烁显示报警标志。相当于给系统加了一个保护机制适合做设备散热监控。6.3 开源协作的注意事项既然选择了开源我建议你遵守几个惯例协议声明仓库里我放了MIT License别人可以自由使用、修改、分发但要保留版权声明。你在二次开发后重新开源也建议用同样的协议保持生态的一致性。README里写清楚硬件清单包括每一项的链接或型号、数量、大概成本。这决定了别人会不会愿意动手复现。我这份清单列得比较细买齐一套大概也就三四十块。上传视频演示我录了一段10秒钟的演示视频从常温环境把热风枪靠近DHT11可以看到风扇转速随之改变、OLED显示同步更新。视频链接放在README里。一个演示视频比一万字说明都更能说明这个项目能不能跑起来。6.4 写在最后的小经验这个项目从画原理图到仿真、打样、调试、写文档前后花了我大概两周的业余时间。真正让我耗时最多的不是代码也不是电路而是调试DHT11时序在不同环境下的稳定性——同一份代码在我自己的开发板上跑得好好的换到另一块板子上就偶发读取失败。后来定位到是两块板子的上拉电阻阻值不同导致的一块4.7k一块10k。这个案例给我最大的教训是传感器电路的上拉电阻不是随便选的要根据总线上挂的器件数量和走线长度综合决定。另一条经验是做开源项目文档和代码同样重要。我这个仓库的README写了将近两千字把每个关键的选型理由、调试心得都记录在案。原因很简单代码只能告诉你怎么做文档才能告诉别人为什么这样做。很多开源项目代码写得很好但README只有一句话本项目实现xxx功能下载者看不懂复现不了项目就失去了开源的初衷。如果你照着这个项目做出了自己的温控风扇或者把它改造成了别的什么非常欢迎在仓库的Issues区留言交流。我自己也还在考虑要不要把ESP8266版本做出来——同样是温控逻辑但多一个WiFi远程监控。那就看这个项目的反馈情况了。