1. 智能温控风扇系统设计概述
夏天坐在闷热的房间里,手忙脚乱找遥控器调风扇档位的经历大家都有吧?我去年做毕业设计时就想着,能不能做个能自动调节风速的智能风扇。这个基于STM32和蓝牙技术的温控风扇系统,就是为解决这个问题而生的。
这个系统最酷的地方在于它能"感知"环境温度。我用DS18B20温度传感器实时采集环境数据,STM32F103C8T6单片机根据设定阈值自动调节PWM输出,控制风扇转速。比如室温超过30℃自动调至最高档,26-30℃中档,低于26℃则自动关闭。更棒的是通过HC-05蓝牙模块,用手机APP就能远程控制,躺在床上动动手指就能调节风速。
做课程设计时发现,这个项目完美涵盖了嵌入式开发的三大核心技能:传感器数据采集(DS18B20)、无线通信(蓝牙4.0)、外设控制(PWM驱动电机)。对电子类专业的学生来说,既能巩固单片机知识,又能学到物联网设备的开发流程。我在调试过程中踩过的坑、积累的经验,都会在后续章节详细分享。
2. 硬件设计与元器件选型
2.1 核心控制器选型对比
刚开始我在STM32F103C8T6和ESP32之间犹豫不决。实测发现,虽然ESP32自带蓝牙功能,但STM32的外设资源更丰富,PWM输出更稳定。最终选择的STM32F103C8T6有:
- 72MHz主频的Cortex-M3内核
- 3个通用定时器(TIM2/3/4)支持PWM生成
- USART接口完美适配HC-05模块
- 64KB Flash完全够用
这里有个省钱小技巧:淘宝上"最小系统板"只要15元左右,比正版开发板便宜80%。不过要注意,有些廉价板的晶振精度较差,会导致蓝牙通信不稳定。我测试过,用示波器测量发现8MHz晶振实际只有7.8MHz,后来换了正品晶振才解决问题。
2.2 温度传感器方案选择
DS18B20相比常见的DHT11有三个明显优势:
- 测量范围更宽(-55℃~+125℃ vs 0℃~50℃)
- 精度更高(±0.5℃ vs ±2℃)
- 单总线协议节省IO口
接线时要注意:DS18B20的数据线需要接4.7KΩ上拉电阻。我第一次没加上拉,读到的温度值全是85℃(这是芯片的默认值)。后来在数据线和VCC之间加了电阻,数据立即正常了。
2.3 蓝牙模块配置要点
HC-05模块有六个引脚需要连接:
- VCC → 3.3V(切记不要接5V!)
- GND → GND
- TXD → STM32的PA10(USART1_RX)
- RXD → STM32的PA9(USART1_TX)
- STATE → 可接LED显示连接状态
- EN → 接高电平进入AT指令模式
调试时发现个坑:模块默认波特率是38400,而STM32的HAL库默认USART是115200。要么修改代码波特率,要么用AT指令(AT+UART=115200,0,0)调整模块波特率。建议后者,因为115200传输速度更快。
3. 系统软件设计详解
3.1 开发环境搭建
推荐使用STM32CubeIDE这个免费工具,它集成了CubeMX配置和代码编辑功能。安装时注意:
- 勾选STM32F1系列支持包
- 安装ST-Link驱动(否则无法烧录程序)
- 配置代码生成选项为"生成外设初始化代码"
新建工程时关键配置:
- SYS: Debug选Serial Wire
- RCC: HSE选择Crystal/Ceramic Resonator
- USART1: 模式Asynchronous,波特率115200
- TIM3: Clock Source选Internal Clock,Channel1选PWM Generation CH1
3.2 温度采集程序设计
DS18B20的驱动要注意时序控制。我封装了几个关键函数:
// 复位脉冲 void DS18B20_Reset(void) { SET_PIN_OUTPUT(); HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, 0); delay_us(480); HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, 1); delay_us(60); SET_PIN_INPUT(); while(HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN) == 0); delay_us(480); } // 读取温度值 float DS18B20_ReadTemp(void) { uint8_t tempL, tempH; DS18B20_Reset(); DS18B20_WriteByte(0xCC); // 跳过ROM DS18B20_WriteByte(0x44); // 启动转换 HAL_Delay(750); // 等待转换完成 DS18B20_Reset(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // 读暂存器 tempL = DS18B20_ReadByte(); tempH = DS18B20_ReadByte(); return (float)((tempH<<8)|tempL)/16.0; }实测发现,每次温度转换需要约750ms,所以采样周期不要小于1秒,否则会读到前一次的数据。
3.3 PWM调速算法实现
风扇控制采用PID算法,但实际测试发现简单的阈值控制就足够用。我的调速逻辑:
void Fan_SpeedControl(float temp) { if(temp > 30.0) { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 255); // 全速 } else if(temp > 28.0) { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 180); // 70%转速 } else if(temp > 26.0) { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 90); // 35%转速 } else { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0); // 关闭 } }TIM3的PWM配置要点:
- 预分频器(Prescaler)设为71(72MHz/(71+1)=1MHz)
- 自动重载值(Counter Period)设为999(1MHz/1000=1kHz PWM频率)
- 这样占空比1对应0.1%精度
4. 蓝牙通信与手机APP开发
4.1 HC-05 AT指令配置
要让模块能被手机发现,需要先进入AT模式(按住按键上电)配置:
AT+NAME=SmartFan // 设置设备名称 AT+PSWD=1234 // 设置配对密码 AT+UART=115200,0,0 // 设置波特率 AT+ROLE=0 // 设为从机模式有个实用技巧:在代码里添加蓝牙指令解析,实现动态调整温度阈值:
if(strstr(rxBuffer, "SETMAX:")) { sscanf(rxBuffer+7, "%f", &maxTemp); sprintf(txBuffer, "OK MAX=%.1f", maxTemp); HAL_UART_Transmit(&huart1, (uint8_t*)txBuffer, strlen(txBuffer), 100); }4.2 安卓APP开发要点
使用Android Studio开发控制APP,核心功能包括:
- 蓝牙设备扫描与连接
- 实时温度曲线显示
- 手动调速滑块控件
- 阈值设置界面
关键代码段:
// 蓝牙连接 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); BluetoothDevice device = adapter.getRemoteDevice("00:13:EF:12:34:56"); BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); socket.connect(); // 发送控制指令 OutputStream out = socket.getOutputStream(); out.write("FAN:50%".getBytes());测试发现,安卓蓝牙API在不同版本有差异,建议targetSdkVersion设为28(Android 9)兼容性最好。
5. 系统优化与调试经验
5.1 电源噪声处理
初期遇到风扇启停导致单片机复位的问题,解决方案:
- 在电机电源端并联1000μF电解电容
- 单片机电源端加0.1μF去耦电容
- 电机驱动改用光耦隔离
实测波形显示,加了滤波电容后,电源纹波从1.2V降到50mV以下。
5.2 抗干扰设计
DS18B20长距离传输时容易受干扰,改进措施:
- 使用屏蔽线
- 总线长度不超过20米
- 在数据线对地接100pF电容
曾遇到一个诡异现象:每次蓝牙传输数据时温度读数跳变。后来发现是USART1和DS18B20共用同一个GPIO组(GPIOA),通过调整DS18B20到GPIOB组解决。
5.3 低功耗优化
为延长电池供电时间,采取以下措施:
- 空闲时STM32进入STOP模式
- 通过蓝牙数据唤醒
- 温度采样间隔从1秒改为10秒(当温度变化平缓时)
- 风扇停转时关闭PWM时钟
实测电流从85mA降到15mA,2000mAh锂电池可用5天以上。