
这次我们来看一个基于 STM32F103C8 微控制器和 Proteus 仿真软件实现的“无叶风扇台灯”项目。这个项目将两种常见的家用电器功能——风扇和照明——集成在一个虚拟设备中并通过 OLED 显示屏和蓝牙模块实现状态显示与远程控制。对于学习嵌入式开发、单片机编程以及电路仿真的朋友来说这是一个非常典型的综合实践案例。项目的核心在于利用 Proteus 这一强大的电子设计自动化软件在电脑上搭建一个完整的虚拟硬件系统包括 MCU、外围驱动电路、显示模块和通信模块。你不需要购买任何实体元器件就能完成从电路设计、程序编写到功能调试的全过程。这极大地降低了学习门槛和试错成本尤其适合在校学生和嵌入式初学者进行项目演练。本文将带你从零开始完成这个仿真项目的环境搭建、电路绘制、程序编写与功能测试。你会了解到如何配置 STM32 的 GPIO、PWM、I2C 和 USART 等外设如何驱动 OLED 显示状态信息以及如何通过蓝牙实现手机 APP 对风扇和灯光的控制。整个过程完全在软件中完成但涉及的开发思路和调试方法与真实硬件项目高度一致。1. 核心能力速览能力项说明核心控制器STM32F103C8ARM Cortex-M3 内核仿真平台Proteus 8 Professional或更高版本开发环境Keil uVision 5 / STM32CubeIDE主要功能1. 无叶风扇模拟多档风速控制2. LED 台灯模拟多档亮度调节3. OLED 显示当前工作模式与参数4. 蓝牙远程控制开关、档位切换关键外设GPIO按键输入、LED输出、PWM风扇/灯光驱动、I2COLED、USART蓝牙硬件门槛仅需一台普通电脑无需实体开发板与元器件适合场景嵌入式系统学习、单片机课程设计、Proteus 仿真练习、物联网控制原型验证2. 适用场景与使用边界这个仿真项目主要适用于以下几类人群和场景嵌入式初学者希望通过一个完整项目学习 STM32 外设GPIO、定时器、I2C、串口的综合应用。高校学生用于完成单片机原理、嵌入式系统等课程的课程设计或毕业设计提供完整的仿真方案和代码参考。电子爱好者在动手焊接实物前先用仿真验证电路设计和程序逻辑的可行性避免硬件损坏。物联网原型验证快速验证“设备状态显示OLED 无线控制蓝牙”这一经典物联网终端架构。使用边界与注意事项仿真与实物的差异Proteus 仿真模型是理想化的其时序、电气特性与真实元器件存在差异。仿真成功不保证实物一次成功但能排除大部分逻辑错误。性能极限测试仿真难以模拟复杂的电源噪声、电磁干扰以及 MCU 在高负载下的真实发热情况。外设模型限制Proteus 的某些高级外设模型或特定型号芯片可能不支持需要确认元件库是否包含所需模型如特定的蓝牙模块型号。仅供学习研究本项目仿真的是一个概念产品其电路和控制逻辑为教学目的设计不涉及真实的空气动力学和光学设计。3. 环境准备与前置条件在开始之前请确保你的电脑已安装以下软件这是项目运行的基础。Proteus 8 Professional或更新版本作用用于绘制电路原理图并进行交互式仿真。说明务必安装 Professional 版本它包含了丰富的微控制器模型和高级仿真功能。安装后需要加载 STM32 系列芯片的仿真模型库通常安装包已包含。Keil uVision 5 MDK-ARM 或 STM32CubeIDE作用用于编写、编译和调试 STM32 的 C 语言程序。Keil需要安装对应的 STM32F1 系列设备支持包Device Family Pack。STM32CubeIDEST 官方免费集成开发环境集成了 CubeMX 配置工具更适合新手。STM32 程序烧录/调试驱动作用在 Proteus 中我们需要将编译好的程序文件.hex 或 .elf加载到虚拟 MCU 中。说明使用 Keil 编译会生成.hex文件使用 CubeIDE 编译可配置生成.hex或.elf文件。Proteus 支持直接加载这些文件。串口调试助手如 SSCOM、XCOM作用用于模拟手机 APP通过虚拟串口与仿真电路中的蓝牙模块进行通信发送控制指令。系统环境操作系统Windows 7/10/11Proteus 主要支持 Windows 平台。磁盘空间预留至少 2GB 空间用于安装软件和存储项目文件。权限确保有权限安装软件并在 C 盘创建文件。4. 电路设计与 Proteus 工程搭建这是项目的硬件基础。我们将在 Proteus 中绘制出整个系统的原理图。4.1 新建 Proteus 工程打开 Proteus ISIS。点击File-New Project。设置工程名称如Bladeless_Fan_Lamp和存储路径。在创建原理图步骤中选择DEFAULT模板即可。在 PCB 设计步骤选择No我们只做仿真。在固件步骤选择No我们将在 Keil/CubeIDE 中单独编写程序。4.2 放置并连接核心元器件点击左侧工具栏的P按钮从元件库中搜索并放置以下关键元件微控制器STM32F103C8晶体振荡器CRYSTAL(8MHz)用于提供系统主时钟。负载电容CAP(22pF)连接在晶振两端。复位电路RES(10kΩ 上拉电阻) 和BUTTON(复位按键)。电源POWER和GROUND。风扇驱动用一个DC MOTOR直流电机模型来模拟无叶风扇的电机通过一个NPN三极管如 2N2222或MOSFET驱动由 MCU 的 PWM 引脚控制。台灯驱动用多个LED发光二极管并联来模拟灯条同样通过一个三极管驱动由另一个 PWM 引脚控制。可以添加一个RES如 220Ω作为限流电阻。显示模块OLED(128x64)选择 I2C 接口的模型如OLED12864-I2C。蓝牙模块常用模型是HC-05或HC-06。在 Proteus 中可能直接搜索BLUETOOTH或使用COMPIM物理接口映射组件配合虚拟串口来模拟。控制按键放置几个BUTTON用于本地手动控制风扇和灯的档位。4.3 关键电路连接示意图以下是核心连接的逻辑说明具体引脚号需在程序中定义一致STM32 最小系统连接 8M 晶振、复位电路、电源和地。风扇驱动电路STM32 的一个 PWM 引脚如 PA0 - 三极管基极电阻 - NPN 三极管基极。三极管集电极接DC MOTOR和电源发射极接地。台灯驱动电路STM32 的另一个 PWM 引脚如 PA1 - 三极管基极电阻 - 另一个 NPN 三极管基极。三极管集电极接LED阳极和电源LED 阴极通过限流电阻接地。OLED 显示STM32 的 I2C1 引脚PB6: SCL, PB7: SDA 连接至 OLED 模型的对应引脚。蓝牙模块STM32 的一个 USART 引脚如 PA9: TX, PA10: RX 连接至HC-05模型的RXD和TXD。HC-05的VCC和GND接电源和地。本地按键连接几个 GPIO 到BUTTON另一端接地配置为上拉输入模式按键按下时为低电平。绘制完成后你的原理图应包含一个能独立运行的虚拟硬件系统。务必使用Net Label功能标注关键网络使图纸清晰易读。5. 固件开发STM32 程序编写接下来我们为 STM32F103C8 编写控制程序。这里以 Keil uVision 5 为例简述关键步骤。5.1 创建 Keil 工程并配置外设打开 Keil创建新工程选择设备STM32F103C8。在Manage Run-Time Environment窗口中添加必要的软件组件如Device中的Startup以及CMSIS和Device下的标准外设库。使用STM32CubeMX工具进行图形化引脚配置是一个更高效的方法即使最终用 Keil 编译。在 CubeMX 中选择 MCU 型号STM32F103C8Tx。配置时钟树选择外部高速晶振HSE将系统时钟设置为 72MHz。引脚配置将 PA0、PA1 配置为TIM2_CH1和TIM2_CH2生成 PWM。将 PB6、PB7 配置为I2C1_SCL和I2C1_SDA。将 PA9、PA10 配置为USART1_TX和USART1_RX模式为异步通信。将连接按键的引脚如 PA2、PA3配置为GPIO_Input上拉模式。生成代码选择 MDK-ARM V5 作为工具链。5.2 核心功能代码实现将生成的代码导入 Keil 工程。在主循环 (main.c的while(1)中你需要实现以下逻辑// 伪代码逻辑示例 #include main.h #include stdio.h // 用于 sprintf #include string.h // 用于 strcmp #include oled.h // 假设有 OLED 驱动库 #include motor.h // 风扇控制函数 #include light.h // 灯光控制函数 UART_HandleTypeDef huart1; TIM_HandleTypeDef htim2; I2C_HandleTypeDef hi2c1; uint8_t uart_rx_buffer[10]; uint8_t uart_rx_len 0; char cmd_buffer[20]; // 风扇和灯的状态变量 uint8_t fan_speed 0; // 0:关, 1:低速, 2:中速, 3:高速 uint8_t light_level 0; // 0:关, 1:低亮, 2:中亮, 3:高亮 int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_I2C1_Init(); MX_TIM2_Init(); HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); // 启动风扇 PWM 通道 HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_2); // 启动灯光 PWM 通道 OLED_Init(); // 初始化 OLED OLED_Clear(); OLED_ShowString(0, 0, Fan:OFF Light:OFF); // 开启串口接收中断 HAL_UART_Receive_IT(huart1, uart_rx_buffer, 1); while (1) { // 1. 扫描本地按键 if(HAL_GPIO_ReadPin(KEY_FAN_GPIO_Port, KEY_FAN_Pin) GPIO_PIN_RESET){ HAL_Delay(50); // 消抖 fan_speed (fan_speed 1) % 4; // 循环切换 0~3 set_fan_speed(fan_speed); // 设置 PWM 占空比 update_display(); } // 类似处理灯光按键... // 2. 主循环中可添加其他任务 HAL_Delay(10); } } // 串口接收中断回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart-Instance USART1){ if(uart_rx_buffer[0] \n){ // 假设指令以换行符结束 cmd_buffer[uart_rx_len] \0; // 字符串终结 process_bluetooth_cmd(cmd_buffer); // 处理蓝牙指令 uart_rx_len 0; } else { cmd_buffer[uart_rx_len] uart_rx_buffer[0]; } // 重新开启接收中断 HAL_UART_Receive_IT(huart1, uart_rx_buffer, 1); } } // 处理蓝牙指令函数 void process_bluetooth_cmd(char* cmd){ if(strcmp(cmd, FAN_ON_1) 0){ fan_speed 1; } else if(strcmp(cmd, FAN_ON_2) 0){ fan_speed 2; } else if(strcmp(cmd, FAN_OFF) 0){ fan_speed 0; } else if(strcmp(cmd, LIGHT_ON_1) 0){ light_level 1; } else if(strcmp(cmd, LIGHT_ON_3) 0){ light_level 3; } else if(strcmp(cmd, LIGHT_OFF) 0){ light_level 0; } // ... 其他指令 set_fan_speed(fan_speed); set_light_level(light_level); update_display(); } // 更新 OLED 显示函数 void update_display(){ char str[32]; OLED_Clear(); sprintf(str, Fan:%s, (fan_speed0)?OFF:(fan_speed1)?LOW:(fan_speed2)?MID:HIGH); OLED_ShowString(0, 0, str); sprintf(str, Light:%s, (light_level0)?OFF:(light_level1)?LOW:(light_level2)?MID:HIGH); OLED_ShowString(0, 2, str); // 第二行显示 }5.3 编译与生成烧录文件在 Keil 中配置好编译选项确保没有错误。点击Build(F7) 编译工程。编译成功后在工程目录的Objects文件夹下会生成.hex文件。记下这个文件的路径。6. 仿真联调与功能测试这是最关键的步骤我们将把程序“烧录”到 Proteus 的虚拟芯片中并观察整个系统是否按预期工作。6.1 加载程序文件到 Proteus回到 Proteus双击原理图中的STM32F103C8芯片打开属性编辑框。在Program File一栏点击文件夹图标浏览并选择你在 Keil 中生成的.hex文件。在Clock Frequency一栏输入72MHz与程序中的系统时钟配置一致。点击OK保存。6.2 启动仿真与基础测试点击 Proteus 界面左下角的Play(运行) 按钮启动仿真。观察最小系统查看晶振引脚是否有波形复位电路电压是否正常。测试本地按键用鼠标点击原理图中的按键模拟按下动作。此时你应该能看到对应的 LED风扇/灯光指示亮度发生变化PWM 效果在仿真中可能表现为亮度渐变或闪烁频率变化电机模型可能表现为转速变化。OLED 屏幕上显示的文字内容随之更新例如从 “Fan:OFF” 变为 “Fan:LOW”。测试 PWM 输出可以右键点击控制风扇或灯光的 PWM 引脚选择Place Voltage Probe放置一个电压探针。再次运行仿真观察探针处的电压波形应能看到脉宽变化的方波。6.3 蓝牙通信功能测试测试蓝牙功能需要虚拟串口工具。我们使用Virtual Serial Port Driver(如 VSPD) 创建一对虚拟 COM 口让 Proteus 和串口调试助手通过它们通信。创建虚拟串口对打开 VSPD添加一对新的虚拟串口例如COM3和COM4。配置 Proteus 中的蓝牙/串口模型如果你使用的是COMPIM组件双击它在属性中设置Physical Port为COM3假设波特率设置为9600需与程序中的huart1.Init.BaudRate一致。如果你使用的是HC-05模型它可能内置了串口连接属性同样需要设置对应的 COM 口和波特率。配置串口调试助手打开 SSCOM 等工具选择串口号为COM4与 Proteus 配对的另一个口。设置相同的波特率9600、数据位8、停止位1、无校验位。进行通信测试在 Proteus 中启动仿真。在串口调试助手的发送区输入你在程序中定义的指令例如FAN_ON_1然后点击发送。注意指令格式如是否需要加回车换行符需与程序中的判断逻辑 (\n) 匹配。观察仿真系统风扇指示 LED 应变亮或电机开始转动OLED 显示应更新为 “Fan:LOW”。尝试发送LIGHT_OFF、FAN_ON_3等指令验证所有控制功能。7. 资源占用与性能观察仿真视角在仿真环境中“性能”主要指程序逻辑的正确性和系统资源的虚拟占用情况。CPU 负载观察Proteus 在仿真时电脑的实际 CPU 使用率会升高。你可以通过 Windows 任务管理器观察Proteus.exe进程的 CPU 占用。一个简单的 STM32 程序通常不会造成过高负载。如果仿真运行极其缓慢可能是电路存在逻辑错误导致仿真计算复杂如短路、振荡电路未起振。内存与 Flash 占用在 Keil 的编译输出窗口可以看到程序代码大小 (Code) 和内存占用 (RO-data,RW-data,ZI-data)。对于 STM32F103C864KB Flash, 20KB RAM本项目代码通常只占用一小部分远未达到芯片极限。外设冲突排查在仿真中如果某个功能不正常如 OLED 不显示、PWM 无输出应重点检查引脚复用冲突在 CubeMX 中检查是否有同一个引脚被重复配置为不同功能。外设时钟未使能在代码中确认相关外设的时钟__HAL_RCC_xxx_CLK_ENABLE()已开启。初始化顺序确保外设初始化如HAL_TIM_PWM_Init在启动 PWMHAL_TIM_PWM_Start之前完成。仿真速度点击 Proteus 左下角的仿真控制按钮可以调整仿真速度。对于包含数字和模拟混合的电路全速运行可能较慢可以适当提高仿真速度或只运行关键部分进行调试。8. 常见问题与排查方法问题现象可能原因排查方式解决方案Proteus 仿真无法启动或立即停止1. MCU 程序文件 (.hex) 路径错误或损坏。2. 晶振电路连接错误或频率设置不对。3. 电源网络未全局连接。1. 双击 MCU确认 Program File 路径正确。2. 检查晶振两端是否接有负载电容MCU 属性中 Clock Frequency 是否设置。3. 检查原理图中是否所有VCC和GND都正确连接。1. 重新编译生成 .hex 文件并加载。2. 修正晶振电路确保频率与代码一致。3. 使用电源端口 (POWER) 和地端口 (GROUND) 连接所有需要供电的元件。按键控制无反应1. GPIO 引脚配置模式错误应为输入上拉。2. 按键电路连接错误应一端接 GPIO一端接地。3. 程序消抖处理不当或扫描逻辑有误。1. 在 CubeMX 或代码中检查按键引脚配置。2. 用电压探针测量按键按下/释放时引脚电平变化。3. 在 Keil 中使用软件仿真或 Proteus 中单步调试观察按键处理函数是否被触发。1. 重新配置 GPIO 为GPIO_MODE_INPUT和GPIO_PULLUP。2. 修正电路连接。3. 优化按键扫描代码确保能稳定检测到边沿变化。OLED 屏幕无显示1. I2C 引脚 (SCL/SDA) 接反或未连接。2. I2C 初始化失败时钟未使能、速率过高。3. OLED 驱动代码有误或初始化序列不对。1. 检查原理图连接。2. 在代码中检查HAL_I2C_Init的返回值或添加HAL_I2C_MspInit中的时钟使能代码。3. 使用逻辑分析仪Proteus 中有抓取 I2C 总线波形看是否有起始信号、地址和数据传输。1. 交换 SCL 和 SDA 线连接。2. 降低 I2C 时钟速度如 100kHz确保上拉电阻已连接仿真中有时需在引脚加外部上拉电阻模型。3. 核对 OLED 型号的驱动芯片如 SSD1306数据手册修正初始化命令。蓝牙指令无法控制1. 虚拟串口未正确配对或占用。2. 串口波特率、数据格式不匹配。3. 程序串口接收中断未正确开启或数据处理逻辑错误。4. 指令格式如结尾符不匹配。1. 确认 VSPD 创建的 COM 口对且未被其他程序占用。2. 对比 Proteus 中 COMPIM/HC-05 属性与代码中huart1.Init的配置。3. 在串口中断回调函数HAL_UART_RxCpltCallback中设置断点或发送调试信息。4. 用串口调试助手以十六进制发送查看实际接收到的字节。1. 关闭可能占用 COM 口的程序重新创建虚拟串口对。2. 统一配置波特率为 9600, 8N1。3. 确保在主函数中调用了HAL_UART_Receive_IT启动接收中断。4. 调整程序中的指令解析逻辑使其与调试助手发送的格式完全一致。PWM 输出无变化1. 定时器时钟未使能或配置错误。2. PWM 输出通道未正确配置或未启动。3. 控制 PWM 占空比的函数未生效。1. 检查 CubeMX 中定时器如 TIM2的配置预分频器、自动重载值是否设置。2. 确认代码中调用了HAL_TIM_PWM_Start。3. 单步调试查看修改CCR寄存器或调用__HAL_TIM_SET_COMPARE的函数是否被执行。1. 在 CubeMX 中重新配置定时器生成代码。2. 在main函数中确保在while(1)之前启动了 PWM。3. 使用电压探针观察 PWM 引脚波形验证占空比是否随控制变量改变。9. 项目扩展与最佳实践完成基础功能后你可以尝试以下扩展让项目更完善增加温度传感器添加一个 DS18B20 或 DHT11 模型在 OLED 上显示环境温度/湿度并实现温度过高自动开启风扇的简单智能逻辑。实现定时功能利用 STM32 的 RTC 或 SysTick 定时器为风扇和灯光增加定时关闭功能并通过蓝牙设置定时时间。优化功耗仿真虽然 Proteus 对功耗仿真有限但你可以通过代码控制不用的外设时钟关闭进入睡眠模式等学习低功耗编程思想。设计更友好的 UI优化 OLED 显示内容增加图标、进度条来直观显示风速和亮度。移植到真实硬件这是最终目标。根据仿真成功的电路图采购 STM32 最小系统板、OLED 屏、HC-05 模块、电机驱动模块如 L298N、LED 灯珠和 MOS 管等将程序下载到实物进行调试。实物调试需额外考虑电源设计、信号干扰、PCB 布局等问题。最佳实践建议版本管理使用 Git 对代码和 Proteus 工程文件进行版本控制每次重大修改前提交一次。模块化编程将风扇控制、灯光控制、OLED 驱动、蓝牙处理分别写成独立的.c/.h文件提高代码可读性和可移植性。仿真与实物并进在仿真中主要验证逻辑和算法复杂的驱动如无刷电机和通信协议如蓝牙配对仍需以实物测试为准。文档记录保存好电路图、程序流程图、引脚分配表和遇到的问题及解决方案形成完整的项目文档。通过这个“无叶风扇台灯仿真”项目你不仅掌握了 Proteus 和 STM32 联合开发的基本流程更实践了嵌入式系统从需求分析、硬件设计、软件编程到调试测试的全过程。这套方法可以迁移到绝大多数基于 MCU 的电子产品开发中是嵌入式工程师的核心技能。建议你以此为蓝本尝试改造和创造属于自己的智能设备仿真项目。