基于ESP32与PWM的智能风扇调速系统设计与实现
1. 项目概述一个可交互的桌面智能风扇夏天一到桌面上的小风扇就成了刚需。但市面上大多数USB风扇只有固定的几档风速要么风太小不够凉快要么风太大噪音恼人总感觉差了点什么。作为一个喜欢折腾硬件的开发者我一直在想能不能自己动手做一个风速无极可调、还能实时看到档位、外观又足够小巧精致的智能风扇这个想法促使我完成了今天要分享的这个项目一个基于M5StickC ESP32开发板和L9110电机驱动模块的智能风扇调速系统。它的核心功能非常简单直观通过M5StickC机身上的一个橙色按键你可以像调节音量一样从0到10级无级调节风扇的转速并且当前的档位会实时显示在它那块小巧的彩色屏幕上。整个系统硬件连接只有3根线软件部分则使用了图形化的Visuino工具进行开发即使你是嵌入式开发的新手也能在半小时内完成从零到一的搭建。为什么选择这套方案首先M5StickC本身集成了ESP32主控、彩色屏幕、按键、电池和丰富的GPIO几乎是一个“开箱即用”的完整设备省去了大量外围电路搭建的麻烦。其次L9110模块是一个经典的H桥电机驱动芯片专门用于驱动小型直流电机它接口简单只需要一个PWM信号就能实现电机的正反转和调速非常适合本项目。最后Visuino这种“拖拽式”编程工具让我们可以专注于系统逻辑的设计而无需陷入复杂的代码语法中极大地降低了开发门槛。这个项目麻雀虽小五脏俱全。它涵盖了嵌入式开发的几个核心环节硬件选型与电路连接、PWM信号生成与控制、人机交互按键与显示设计以及可视化编程工具的使用。无论你是想学习ESP32开发、深入了解PWM电机控制还是单纯想做一个有趣又实用的桌面小工具这个项目都是一个绝佳的起点。接下来我将从设计思路、硬件解析、软件实现到调试心得为你完整拆解这个智能风扇的诞生过程。2. 核心硬件选型与电路设计解析一套稳定可靠的硬件是项目成功的基石。在这个风扇项目中硬件的核心就是“控制大脑”和“动力执行机构”的选型与连接。我的选择基于几个原则集成度高以减少连线、驱动能力匹配负载需求、开发工具友好以提升效率。2.1 主控单元为什么是M5StickC ESP32在众多ESP32开发板中我最终选择了M5StickC主要基于以下几点考量高度集成即拿即用M5StickC在比U盘略大的体积内集成了ESP32-PICO-D4芯片、0.96英寸彩色IPS屏幕、红外发射器、麦克风、六轴传感器IMU、按键、蜂鸣器、电池管理电路以及一个可充电的锂电池。这意味着我们不需要额外为系统准备显示模块、电源或输入设备大大简化了硬件结构。对于本项目我们主要利用其ESP32主控、屏幕和机身侧面的橙色按键M5 Button。充足的GPIO与PWM能力ESP32本身支持多达16个独立的PWM通道精度高达16位。M5StickC通过其GROVE接口和内部引脚映射将部分GPIO引出。其中GPIO0对应板载的G0引脚就是一个可以输出PWM信号的引脚完全满足我们驱动L9110进行调速的需求。便携供电与美观外形内置的锂电池使得风扇可以脱离USB线独立运行成为一个真正的无线设备。其一体化的设计和精致的外观也让最终成品看起来不像一个“开发板实验”而更像一个完整的消费电子产品。注意M5StickC有多个版本如StickC、StickC Plus其引脚定义可能略有不同。本项目基于最基础的M5StickC非Plus版本进行其GROVE接口的引脚对应关系为G0对应GPIO0G26对应GPIO265V和GND为电源。务必确认你的板子型号。2.2 驱动模块L9110电机驱动模块详解风扇电机是感性负载启动和堵转时会产生远大于额定电流的冲击电流直接用MCU的GPIO口驱动极易烧毁芯片。因此一个专用的电机驱动模块必不可少。L9110S是一款为控制和驱动小型直流电机设计的H桥集成电路。L9110模块工作原理浅析 你可以把L9110内部想象成一个由四个电子开关MOSFET组成的“桥”。通过控制这四个开关的导通与关断组合可以改变电流流经电机的方向从而实现电机的正转和反转。对于我们的风扇通常只需单向转动我们只使用其中的一半桥臂。模块上通常有四个引脚VCC电源正极接5V。GND电源地。INAA通道输入控制线1。INBA通道输入控制线2本例中未使用。对于单向调速我们只需使用INA一个引脚。向其输入PWM信号L9110内部电路会根据PWM的占空比线性地控制输出到电机两端的平均电压从而实现调速。占空比越高高电平时间占比越长平均电压越高电机转速越快。选型匹配性检查电压匹配L9110模块的驱动电压VCC范围通常是2.5V-12V而M5StickC的GROVE接口提供了5V输出完美匹配。电流匹配L9110S芯片的持续输出电流约为800mA。常见的小型5V USB风扇电机工作电流通常在100-300mA之间完全在L9110的驱动能力范围内留有充足余量运行起来会更加稳定、发热小。2.3 电路连接极简的三线制硬件连接是整个项目中最简单的部分但正确的连接是后续一切工作的基础。请严格按照以下步骤操作准备材料确保你手头有M5StickC、L9110模块、一个小型5V直流风扇通常可从旧的USB风扇上拆下以及三根公对母的杜邦线。连接电源取一根杜邦线将M5StickC GROVE接口或侧边引脚上的5V引脚连接到L9110模块的VCC引脚。这为驱动模块提供了工作电能。共地连接取第二根杜邦线将M5StickC的GND引脚连接到L9110模块的GND引脚。建立共同的参考地电位是所有电路正常通信的前提这一步绝对不能省略。连接控制信号取第三根杜邦线将M5StickC的G0引脚即GPIO0连接到L9110模块的INA引脚。这根线将承载我们产生的PWM调速信号。连接电机将风扇电机的两根线连接到L9110模块的电机输出端子通常标记为A和A-。如果风扇不转可以尝试对调这两根线这只会改变转动方向不影响调速功能。至此硬件连接就完成了。你可以看到我们并没有使用L9110的INB引脚因为我们不需要反转功能。这种极简的连接方式最大程度降低了出错概率也使得整个系统非常简洁。3. 软件开发环境搭建与Visuino基础对于习惯了写代码的开发者来说图形化编程工具可能显得有些“玩具化”。但在实际体验了Visuino之后我发现它在快速原型开发、逻辑可视化以及教育演示方面有着独特的优势。它让你能像绘制流程图一样设计程序特别适合逻辑控制型项目。3.1 为什么选择Visuino而非Arduino IDE本项目原文采用了Visuino我沿用了这一选择并认为对于此项目而言它有几个显著优点直观的逻辑构建PWM信号生成、按键检测、数值转换、显示控制这些功能在Visuino中都被封装成了一个个可视化的“组件”。你只需要从工具箱拖拽出来然后用“线”连接它们就完成了逻辑的搭建。这个过程非常直观尤其适合描述信号流和数据流。隐藏底层复杂性例如配置ESP32的PWM通道包括设置频率、分辨率、绑定引脚在代码中需要好几行配置而在Visuino中你只需要将某个组件的输出“引脚”连接到M5StickC的“Analog PWM”引脚底层配置就自动完成了。快速迭代与调试图形化界面让你对程序结构一目了然。修改参数如PWM频率、计数范围只需在属性窗口中点击即可无需在代码中查找和修改。当然这并不意味着要放弃代码。Visuino最终也会生成标准的Arduino代码你可以查看和学习。这对于从图形化过渡到文本编程的学习者来说是一个很好的桥梁。3.2 Visuino安装与M5StickC环境配置下载与安装前往Visuino官网下载适合你操作系统Windows/macOS/Linux的安装包。安装过程是常规的向导式操作没有特别需要注意的地方。启动与主界面熟悉启动Visuino后你会看到一个中间是设计画布左侧是组件工具箱右侧是对象属性窗口的界面。关键一步选择正确的开发板这是后续一切工作的前提。点击画布左侧的“工具箱”图标找到“Boards”分类将其展开。然后找到“M5Stack”系列将其下的“M5 Stack Stick C”组件拖拽到设计画布上。这时右侧属性窗口会显示该板卡的所有可配置项。配置板卡显示方向可选但重要M5StickC的屏幕默认是竖向的但为了显示“FAN SPEED”文字和较大的数字横向显示更合适。在属性窗口中找到Modules - Display ST7735 - Orientation将其值从默认的goUp改为goRight。这样屏幕就旋转了90度变成了横向模式。完成以上步骤你的Visuino开发环境就针对M5StickC准备就绪了。接下来我们就可以开始构建这个风扇调速系统的核心逻辑。4. 控制系统逻辑设计与Visuino实现整个风扇调速系统的逻辑可以清晰地分为三个部分输入按键检测、处理速度逻辑计算、输出PWM生成与显示。在Visuino中我们将用不同的组件来代表这些功能块。4.1 输入环节按键与边缘检测我们的输入设备是M5StickC机身上的橙色按键硬件映射为GPIO37。但我们需要的是“每按一次速度加一档”的行为而不是“按住不放速度连续增加”。这就要求我们检测按键的“按下”这个动作而不是按键的“状态”。在Visuino中我们使用“Detect Edge”组件来实现。它的作用是检测输入信号的上升沿或下降沿。当按键被按下时GPIO的电平会从高变低具体取决于内部上拉配置我们检测这个下降沿每检测到一次就产生一个脉冲信号作为计数器加一的触发信号。操作步骤从工具箱的“Logic”分类中找到“Edge Detector”组件拖拽到画布上。从左侧的M5 Stick C板卡组件上找到代表橙色按键的引脚通常名为Button A (M5)或类似。用鼠标从这个引脚拖出一条线连接到“DetectEdge1”组件的“In”引脚。在“DetectEdge1”的属性窗口中确保“Edge”属性设置为“Falling”。这表示我们检测下降沿即按键被按下的瞬间。4.2 处理环节计数器与数值转换接下来我们需要一个“速度档位”的概念并且这个档位会在每次按键时增加达到最大值后循环回零。这正好是“计数器”组件的功能。添加并配置计数器从工具箱“Math”分类中找到“Counter”组件拖入画布。在它的属性窗口中我们需要设置两个关键值Min - Value: 设置为0。这是速度的最低档风扇停止。Max - Value: 设置为10。这是速度的最高档。这意味着我们有0-10共11个档位。Roll Over属性通常保持默认的True这样当计数器加到10之后下一次触发就会自动回到0实现循环调速。连接触发信号将“DetectEdge1”组件的“Out”引脚连接到“Counter1”组件的“In”引脚。这样每次按下按键计数器就会加1。数值转换——从整数到模拟量计数器输出的是整数0,1,2...10但PWM接收的是一个模拟量0.0到1.0之间的占空比值。我们需要进行映射转换。这里有一个关键的设计考量如何将0-10的整数档位映射到0%-100%的PWM占空比最直接的想法是线性映射0档对应0%10档对应100%。但实际测试中我发现很多小型直流电机存在一个“启动电压阈值”当PWM占空比太低时例如低于20%产生的平均电压不足以克服静摩擦力电机无法启动会出现“嗡嗡”声但不转的情况。因此我采用了非线性映射来优化体验让0档对应0%停止1档就对应一个足以启动电机的占空比例如10%然后2-10档再均匀分布。在Visuino中这可以通过“Integer To Analog”组件配合缩放因子来实现。配置整数到模拟转换器从工具箱“Math”分类找到“Integer To Analog”组件拖入画布。将“Counter1”的“Out”引脚连接到“IntegerToAnalog1”的“In”引脚。选中“IntegerToAnalog1”在属性窗口中找到“Scale”属性。这是缩放因子。如果我们希望10档对应100%占空比那么每个整数档位应贡献10%的占空比即0.1。所以这里设置为0.1。此时如果计数器输出是5经过转换器后输出的模拟值就是 5 * 0.1 0.5即50%占空比。处理偏移量启动阈值为了引入启动阈值我们需要在转换后的值上再加一个基础偏移量。Visuino提供了“Subtract From Analog Value”组件但它本质上是进行Output Value - Input的运算。我们可以巧妙地利用它来实现加法如果我们设置其Value属性为1那么Output 1 - Input。这看起来是减法但我们的目的不是这个。实际上为了实现“输出 输入 偏移量”更直观的方法是使用“Add Analog Value”组件。但原教程使用了“Subtract From Value”我们分析其意图假设我们想要在转换值上增加一个0.1的偏移我们可以设置Value为1.1那么Output 1.1 - Input这逻辑不对。经过思考我认为原教程此处可能存在笔误或逻辑设置不同。更合理的流程是计数器 - 整数转模拟Scale0.1 - 输出PWM。如果要处理启动死区应该在计数器环节做文章比如设置最小值为1或者使用一个“映射表”组件。为了简化并遵循主要逻辑我们暂时采用线性映射。在实际操作中如果你发现1档10%占空比无法启动电机可以回到这里将“IntegerToAnalog1”的Scale改为0.09并额外添加一个“Add Analog Value”组件设置其加数为0.1这样0档输出0.110%10档输出1.0100%。为了与原教程步骤大致对应我们暂且按原步骤连接将“IntegerToAnalog1”的“Out”连接到“SubtractFromValue1”的“In”并将“SubtractFromValue1”的Value属性设为1。但请注意这会导致输出是反向的计数器越大输出越小。这可能需要后续在PWM输出端进行反向处理。这是一个需要关注的调试点。4.3 输出环节PWM生成与屏幕显示处理完速度逻辑我们需要将结果同时输出到两个地方电机通过PWM和屏幕。生成PWM信号找到M5 Stick C板卡组件上代表GPIO0的引脚它可能被标记为“GPIO[0]”或“Pin G0”。在其引脚上通常有一个子选项叫“Analog PWM”。将“SubtractFromValue1”组件的“Out”引脚连接到“GPIO[0]”的“Analog PWM”引脚上。Visuino会自动将这个模拟量0.0-1.0转换为对应占空比的PWM信号并通过GPIO0引脚输出给L9110模块。在屏幕上显示档位首先需要设计屏幕布局。选中画布上的M5 Stick C板卡组件在属性窗口中找到Modules - Display ST7735 - Elements点击旁边的“...”按钮会弹出屏幕元素编辑器。在编辑器中从左侧工具箱拖拽一个“Draw Text”元素到画布。在右侧属性窗口设置其Text为“FAN SPEED”Size可以设置为2使其作为标题显示。再拖拽一个“Text Field”元素到画布。这个元素用于动态显示变化的数字。将其放在“FAN SPEED”下方在属性窗口中设置Size为3大一些Y坐标设为30使其向下偏移不与标题重叠。关闭元素编辑器。回到主设计画布你会发现在M5 Stick C组件上多出了两个引脚例如“Text Field1”的“In”引脚。将“Counter1”的“Out”引脚连接到这个“In”引脚上。这样计数器的当前值就会实时显示在屏幕的文本区域了。至此所有逻辑连接完毕。你的Visuino设计画布应该呈现出清晰的信号流按键 - 边沿检测 - 计数器 - 整数转模拟 - 运算处理- PWM输出 屏幕显示。5. 代码生成、编译上传与物理调试图形化设计完成后Visuino需要将其“翻译”成Arduino能够理解的C代码并上传到M5StickC中运行。5.1 生成代码与编译上传切换到代码生成视图点击Visuino底部的“Build”标签页。选择端口确保你的M5StickC通过USB线连接到电脑并在“Port”下拉菜单中选择正确的串行端口在Windows设备管理器中查看端口号如COM3在macOS/Linux下通常是/dev/cu.usbserial-XXXX。编译与上传点击“Compile/Build and Upload”按钮。Visuino会依次执行以下动作生成代码根据你的图形化设计生成完整的Arduino项目代码。编译调用Arduino编译器将代码编译成ESP32可执行的机器码。这个过程会在下方日志窗口显示进度和任何错误信息。上传通过串口将编译好的程序烧录到M5StickC的闪存中。上传成功后M5StickC会自动重启。你应该能看到屏幕亮起显示“FAN SPEED”和一个数字初始应为0。按下橙色按键数字应该会从0到10循环变化。5.2 系统调试与功能验证上传成功只是第一步真正的乐趣和挑战在于调试让系统按照预期工作。基础功能验证观察屏幕按下按键观察屏幕上的数字是否按0-1-2...-10-0的顺序循环变化。这是验证按键检测和计数器逻辑是否正常的最直接方法。聆听风扇当数字从0变为1时仔细听风扇是否有启动的声音或开始转动。如果风扇没反应请进入下一步排查。PWM信号与电机驱动排查检查硬件连接这是最常出问题的地方。再次确认三根线5V, GND, G0-INA是否连接牢固没有虚接。确认风扇电机线是否正确连接在L9110的输出端。验证PWM输出如果你有一个示波器或者逻辑分析仪可以测量GPIO0G0引脚上的波形。当档位变化时你应该能看到一个频率固定通常为1kHz或5kHz由Visuino默认设置、占空比变化的方波信号。如果没有仪器可以用一个简单的办法将一个小型有源蜂鸣器注意是那种需要PWM驱动的有源蜂鸣器不是无源的或一个LED加限流电阻接到G0和GND之间。当改变档位时蜂鸣器的音调或LED的亮度应该随之变化。这能证明PWM信号确实在正确输出。排查L9110模块用万用表测量L9110模块的VCC和GND之间是否有5V电压。测量电机输出端A和A-之间的电压当档位提高时其平均电压应随之升高。如果输入PWM正常但输出无电压可能是L9110模块损坏或接线错误。电机启动问题如果高档位能转低档位不转这就是前述的“启动电压阈值”问题。你需要返回Visuino调整速度映射逻辑。例如修改“IntegerToAnalog1”的Scale为0.09并添加一个“Add”组件设置偏移量为0.1确保最低档位输出的占空比也能让电机启动。Visuino逻辑复查如果屏幕显示正常但PWM输出不对例如风扇转速变化规律与档位显示相反很可能是“SubtractFromValue1”组件导致的信号反转。尝试将其Value属性改为0或者直接将其从链路中移除将“IntegerToAnalog1”的输出直接连接到PWM引脚看看问题是否解决。这需要你理解每个组件在链路中的作用并勇于调整和测试。实操心得在嵌入式开发中“分而治之”的调试策略非常有效。不要试图一次性让整个系统完美运行。先确保输入按键、屏幕显示部分工作正常再单独测试输出PWM信号部分最后将两者整合。Visuino的可视化特性在这里很有帮助你可以通过临时添加一些“Debug”组件如将中间值输出到串口监视器来观察数据流精准定位问题所在。6. 项目优化与扩展思路一个基础版本完成后我们可以从稳定性、用户体验和功能扩展三个方面来思考如何让它变得更好。6.1 稳定性优化抗干扰与软件去抖目前的设计中按键检测使用的是简单的边沿检测。在实际物理世界中机械按键在按下和释放的瞬间会产生一系列快速的、不稳定的通断信号称为“抖动”。这可能导致一次按键被误判为多次造成档位连跳。软件去抖实现 在Visuino中我们可以使用“Delay”或“Filter”组件来实现简单的软件去抖。一个常见的方法是在“DetectEdge”组件之前添加一个“Debounce Filter”组件在“Filters”工具箱分类中。将这个滤波器连接到按键引脚和边沿检测器之间并设置一个合理的延迟时间如50毫秒。这样只有稳定超过50ms的电平变化才会被传递有效滤除抖动。6.2 用户体验提升更直观的交互与显示增加视觉反馈除了数字我们可以在屏幕上增加一个进度条或者一组LED样式的图标来直观表示风速。在Visuino的屏幕元素编辑器中可以使用“Draw Rectangle”元素根据计数器值动态改变其宽度模拟进度条效果。增加声音反馈M5StickC内置了蜂鸣器。可以在每次切换档位时让蜂鸣器发出一个简短的“嘀”声提供触觉之外的确认反馈。这可以通过在计数器输出后连接一个“Pulse Generator”组件再连接到板卡的Buzzer引脚来实现。记忆档位目前每次断电重启后风扇都会复位到0档。我们可以利用ESP32的Preferences库在Visuino中可能有对应组件或需要通过自定义代码实现将当前的档位值保存到非易失性存储NVS中。下次上电时先读取保存的值并设置为计数器初始值从而实现档位记忆功能。6.3 功能扩展迈向真正的“物联网风扇”ESP32的核心优势是其Wi-Fi和蓝牙连接能力。在此基础上我们可以轻松地将这个本地控制的风扇升级为物联网设备。手机APP遥控利用ESP32的蓝牙功能可以创建一个简单的BLE服务定义一个用于接收速度值的特征。然后手机端使用LightBlue、BLE调试助手等APP或者自己编写一个简单的Flutter/React Native应用通过蓝牙连接M5StickC并发送0-10的数值来控制风扇速度。在Visuino中可能需要添加“BLE”相关组件并配置服务。Web服务器远程控制让M5StickC连接本地Wi-Fi并启动一个微型Web服务器。在同一个局域网内的任何设备手机、电脑通过浏览器访问M5StickC的IP地址就能看到一个简单的网页上面有一个滑块或按钮可以远程控制风扇开关和调速。这需要用到Wi-Fi和Web Server组件并设计一个简单的HTML页面。语音控制结合M5StickC内置的麦克风可以尝试集成一些简单的语音识别库如ESP32-SR识别“加速”、“减速”、“关闭”等指令实现语音控制。或者通过Wi-Fi连接到家庭智能语音助手如天猫精灵、Google Assistant的IFTTT实现更强大的语音交互。环境联动接入温湿度传感器如DHT11让风扇转速能够根据环境温度自动调节。例如设置一个温度阈值超过阈值后风扇自动开启并且温度越高转速自动调得越快。这需要添加传感器组件并在Visuino中设计一个简单的闭环控制逻辑。从一个小小的按键调速风扇出发通过不断叠加想法和技术它可以演变成一个充满个性的智能设备。这个项目就像一颗种子它所涉及的硬件连接、PWM控制、人机交互和物联网连接是嵌入式世界中最基础也最重要的养分。希望你在完成这个项目后不仅能享受自己创造的清凉更能收获探索和创造的乐趣。