1. 项目概述
这个基于STM32的温控风扇项目,是我去年为一个工业设备散热需求开发的解决方案。当时客户需要一套能够根据环境温度自动调节转速的风扇系统,要求控制精度在±1℃以内,响应时间不超过3秒。经过多次迭代,最终方案不仅满足了客户需求,还实现了低于50元的BOM成本。
温控风扇的核心原理其实很简单:通过温度传感器采集环境数据,STM32微控制器处理数据后输出PWM信号控制风扇转速。但真正做起来,从传感器选型到PID算法调参,每个环节都有不少门道。下面我就把整个开发过程中的关键技术和实操经验完整分享出来。
2. 硬件设计解析
2.1 核心器件选型
主控芯片我选择了STM32F103C8T6,这款Cortex-M3内核的MCU性价比极高(零售价约8元),具有:
- 72MHz主频
- 64KB Flash
- 20KB RAM
- 3个通用定时器(TIM2/3/4)
- 2个ADC(12位精度)
温度传感器对比了三种方案:
- DS18B20(数字输出,±0.5℃精度)
- NTC热敏电阻(需ADC采样,成本低)
- DHT11(温湿度一体,但精度仅±2℃)
最终选用10K NTC(MF52型)配合1%精度分压电阻,实测温度曲线拟合后精度可达±0.3℃,成本仅0.3元。虽然需要软件做非线性补偿,但考虑到项目预算,这个方案最具性价比。
2.2 电路设计要点
风扇驱动电路采用经典的MOSFET方案:
- IRF540N MOSFET(33A/100V)
- 1N4148续流二极管
- 10Ω栅极电阻
特别注意:PWM频率建议设置在20-25kHz之间,这个频段既高于人耳听觉范围(避免噪音),又不会因频率过高导致MOSFET开关损耗过大。
电源部分做了两级处理:
- LM7805给MCU供电
- 直接取12V给风扇供电
实测整机待机电流仅15mA,满载时不超过500mA。
3. 软件实现细节
3.1 温度采集处理
NTC的ADC采样值需要经过三步处理:
- 中值滤波(连续采样5次取中间值)
- Steinhart-Hart方程转换:
c复制float Temp_Calculate(uint32_t adc_val) { float Rt = 10000.0 * (4095.0/adc_val - 1); // 10K分压 float log_Rt = log(Rt); return 1.0/(A + B*log_Rt + C*pow(log_Rt,3)) - 273.15; // ABC为校准系数 } - 滑动平均滤波(窗口大小=10)
实测这种处理方式在20-80℃范围内,温度波动能控制在±0.2℃以内。
3.2 PID控制算法
采用位置式PID算法,关键参数:
c复制typedef struct {
float Kp; // 比例系数
float Ki; // 积分系数
float Kd; // 微分系数
float i_max; // 积分限幅
float out_max; // 输出限幅
} PID_Param;
float PID_Calculate(PID_Param *p, float set, float now)
{
static float err_last = 0;
static float i_term = 0;
float err = set - now;
i_term += p->Ki * err;
i_term = constrain(i_term, -p->i_max, p->i_max);
float d_term = p->Kd * (err - err_last);
err_last = err;
float output = p->Kp*err + i_term + d_term;
return constrain(output, 0, p->out_max);
}
参数整定经验:
- 先设Ki=0,Kd=0,逐步增大Kp直到系统出现等幅振荡
- 取振荡时Kp值的60%作为最终Kp
- Ki设为0.5*Kp/Ti(Ti为系统响应时间)
- Kd设为0.125KpTd(Td为微分时间)
3.3 PWM输出配置
使用TIM3 CH2输出PWM,关键配置:
c复制void PWM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// PB5 as TIM3 CH2
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// 24kHz PWM
TIM_TimeBaseStruct.TIM_Period = 999; // ARR
TIM_TimeBaseStruct.TIM_Prescaler = 71; // 72MHz/(71+1)=1MHz
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0; // 初始占空比0%
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_OCInitStruct);
TIM_Cmd(TIM3, ENABLE);
}
4. 系统调优经验
4.1 温度采样抗干扰
遇到最棘手的问题是电机启停导致ADC采样异常。解决方案:
- 在NTC两端并联0.1μF电容
- ADC采样期间短暂关闭PWM输出
- 软件上增加采样异常值剔除逻辑
4.2 风扇启动策略
直接给停转的风扇加100%占空比可能导致启动失败。优化方案:
- 启动时先给80%占空比(持续300ms)
- 然后降至目标值
- 加入转速反馈检测(霍尔传感器或反电动势检测)
4.3 参数自适应
针对不同环境温度自动调节PID参数:
c复制void PID_Adaptive(PID_Param *p, float temp)
{
if(temp < 30) {
p->Kp = 50.0;
p->Ki = 0.5;
}
else if(temp < 50) {
p->Kp = 40.0;
p->Ki = 0.3;
}
else {
p->Kp = 30.0;
p->Ki = 0.2;
}
}
5. 完整工程要点
项目资料包含:
- 原理图(Altium Designer格式)
- PCB文件(双面板,尺寸40x60mm)
- 固件源码(Keil MDK工程)
- 上位机调试工具(C#编写)
- BOM清单(含供应商信息)
关键调试技巧:
- 通过串口实时输出温度/PWM数据
- 使用电位器模拟温度变化快速测试
- 用热风枪和红外测温仪校准传感器
这个项目最让我自豪的是在成本控制上的突破:最终BOM成本仅46.5元(小批量),比市面同类产品低60%以上。其中最大的节省来自NTC方案替代数字温度传感器,虽然增加了软件复杂度,但换来了可观的成本优势。