
1. 项目概述从零打造一个智能热水器监控系统最近在整理工作室的旧项目翻出了一个几年前做的智能热水器控制器原型。当时市面上带远程控制的热水器要么价格昂贵要么功能单一就想着自己动手做一个把水温、水位、加热控制、手机监控和报警这些功能都集成到一块STM32单片机上。这个项目麻雀虽小五脏俱全涵盖了嵌入式开发从硬件选型、电路设计、软件编程到无线通信和手机端开发的完整链路非常适合想深入嵌入式物联网领域的朋友练手。这个系统的核心目标很简单让一个传统的储水式热水器变得“聪明”起来。它能实时监测水箱内的温度和水位根据你设定的温度自动启停加热棒还能通过蓝牙把你的手机变成遥控器和仪表盘随时随地查看状态一旦水温异常或水箱缺水手机立刻就能收到报警。整个过程涉及STM32单片机编程、传感器电路设计、无线通信协议、手机APP开发以及系统联调是一个综合性很强的实战项目。无论你是电子爱好者、自动化专业的学生还是想转行嵌入式开发的工程师跟着这个项目走一遍对理解一个完整的产品开发流程会非常有帮助。2. 系统核心架构与硬件选型思路做一个稳定的智能控制器硬件是地基。这个项目的硬件架构可以分解为几个核心模块主控单元、感知单元、执行单元、通信单元和供电单元。选型时我主要考虑的是稳定性、成本、开发便利性以及最终的扩展性。2.1 主控芯片为什么是STM32F103C8T6主控我选择了经典的STM32F103C8T6也就是常说的“蓝莓派”最小系统板的核心芯片。这几乎是一个性价比和生态的完美平衡点。首先性能足够。它基于ARM Cortex-M3内核主频72MHz对于处理温度采集ADC、水位判断、控制逻辑、蓝牙数据打包发送这些任务绰绰有余。其内置的多个定时器可以方便地生成PWM信号用于控制加热棒的功率如果做调功的话或者用于软件定时采集传感器数据。其次资源丰富。它拥有64KB Flash和20KB RAM足以容纳我们这个项目的所有代码包括蓝牙协议栈和变量。更重要的是它具备多路12位ADC可以同时采集温度传感器和水位传感器的模拟信号无需外部ADC芯片简化了设计。USART串口用于和蓝牙模块通信GPIO口用于控制继电器和状态指示灯这些资源它都具备。最后生态与成本。STM32的HAL库和标准库资料浩如烟海遇到问题几乎都能找到解决方案。基于这颗芯片的开发板价格低廉降低了学习和试错成本。虽然现在有更多高性能的M4、M7内核芯片但对于热水器控制这种对实时性要求并非极端苛刻的应用F103系列依然是最务实的选择。2.2 感知单元温度与水位传感器的取舍感知单元负责获取热水器的“身体状况”主要是温度和水位。温度传感器DS18B20 vs NTC热敏电阻这是一个经典的选型问题。我最终选择了DS18B20数字温度传感器放弃了更常见的NTC热敏电阻模拟方案。原因如下精度与免校准DS18B20出厂已校准精度可达±0.5°C且直接输出数字信号无需复杂的ADC采样和查表计算软件处理更简单也避免了因ADC参考电压波动带来的误差。抗干扰能力强单总线数字传输比模拟信号NTCADC更不容易受到热水器内部电磁干扰尤其是继电器、加热棒启停时的影响。布线方便单总线只需一根数据线加上电源和地可以轻松实现较远距离数十米的测温方便将传感器探头安装在水箱的测温盲管内。 当然DS18B20的成本略高于NTC且驱动代码需要处理严格的时序。但对于一个追求稳定和易用的产品化设计来说这点成本增加和代码复杂度是值得的。水位检测干簧管浮球开关的可靠性之道水位检测我采用了最机械、也是最可靠的方案干簧管浮球开关。它由一个内部封装了干簧管的浮球和一个磁环组成。当水位上升浮球带动磁环靠近干簧管干簧管触点闭合水位下降触点断开。单片机通过一个GPIO口检测这个开关量信号即可。 为什么不选用更“高科技”的超声波或电容式水位传感器核心原因是热水器内部环境恶劣高温、水垢、蒸汽。超声波传感器对安装位置和表面水垢非常敏感电容式则容易受到水质变化的影响。干簧管浮球开关结构简单、无源、耐高温、基本不受水质影响虽然只能提供“高水位”和“低水位”两个开关量点通过安装不同高度的多个浮球可以实现多点检测但对于防干烧保护这个核心需求来说完全足够且极其可靠。2.3 执行单元继电器的选型与驱动电路设计执行单元的核心是一个继电器用于控制220V交流电的通断从而控制加热棒的工作。这里的安全性和可靠性是第一位。我选用的是宏发HFD系列的一常开触点继电器线圈电压5V触点容量为10A/250VAC。选型要点触点容量必须留有余量。家用热水器加热棒功率通常在1500W-3000W对应电流约7A-14A220V下。选择10A的继电器是临界值为了更安全和使用寿命建议选择16A或以上的型号。线圈电压与单片机系统电压匹配5V或3.3V。注意单片机GPIO口通常不能直接驱动继电器线圈需要几十mA电流必须使用三极管如S8050或MOS管进行驱动。驱动电路设计这是关键。我采用了经典的三极管驱动电路。单片机GPIO输出高电平通过一个限流电阻如1kΩ驱动三极管基极三极管饱和导通继电器线圈得电吸合。必须在继电器线圈两端反向并联一个续流二极管如1N4148用于吸收线圈断电时产生的反向电动势防止高压击穿三极管或单片机IO口。这是一个必须遵守的硬件设计准则。2.4 通信单元蓝牙模块的选型与协议规划为了实现手机监控无线通信模块我选择了HC-05蓝牙串口模块。这是一个非常成熟的方案它本质上是一个蓝牙到串口的透传模块。单片机通过USART以固定的波特率如9600或115200向HC-05发送数据HC-05就会通过蓝牙将数据发送给已连接的手机APP反之手机APP发送的数据也会通过串口传给单片机。选型时注意区分主从模式。HC-05可以设置为主机或从机。在这个项目中我们将它配置为从机模式等待手机主机来连接。这样更符合“手机主动控制设备”的应用场景。通信协议设计虽然模块是透传的但我们需要自己定义一套简单的应用层协议让单片机和APP能相互理解。我设计了一个基于字符ASCII的指令集格式为[指令头][数据][校验和][结束符]。 例如单片机上报数据TEMP:45.6#LEVEL:H#\n温度45.6度水位高手机发送控制指令SET:50#\n设置目标温度为50度手机查询指令GET?\n这种文本协议的好处是直观在APP端和单片机端都易于解析和调试通过串口助手就能模拟通信过程。3. 电路设计详解从原理图到PCB的实战要点有了清晰的模块划分和选型下一步就是把它们连接起来画出可靠的电路。这部分是硬件成败的关键很多初期不稳定现象都源于电路设计缺陷。3.1 核心控制电路与电源设计主控电路围绕STM32F103C8T6最小系统搭建。除了基本的晶振、复位电路和Boot模式选择电路外有几点需要特别注意去耦电容在每个芯片的电源引脚VDD/VSS附近必须放置一个0.1uF的陶瓷电容用于滤除高频噪声。对于STM32通常在每组电源引脚都放置并且尽可能靠近引脚。主电源输入端如5V输入还需要并联一个10uF或更大的电解电容用于缓冲低频波动。模拟部分供电如果使用了芯片内部的ADC且对采样精度要求高建议将ADC的参考电压引脚VDDA通过一个磁珠或0Ω电阻从数字电源VDD隔离出来并增加额外的LC滤波电路确保参考电压干净稳定。电源电路是整个系统的心脏。我们的输入可能是220V交流电通过适配器或一个12V直流电源。系统需要两种电压5V给继电器、蓝牙模块、部分传感器供电和3.3V给STM32内核供电。 我采用的方案是外部输入12V DC - LM7805线性稳压芯片 - 5V - AMS1117-3.3线性稳压芯片 - 3.3V。LM7805将12V降至5V需注意其压差和功耗。输入12V输出5V压差7V如果5V电路总电流为200mA那么7805上的功耗就是7V * 0.2A 1.4W发热会比较大必须加装足够面积的散热片。AMS1117-3.3将5V降至3.3V给单片机供电。同样要注意散热。注意如果系统整体功耗较大或者追求高效率可以考虑使用DC-DC开关稳压芯片如MP1584替代LM7805但其电路稍复杂噪声也更大布局布线时需要特别小心。3.2 传感器与执行器接口电路DS18B20接口电路非常简单数据线DQ连接单片机的一个GPIO如PA0同时通过一个4.7kΩ的上拉电阻连接到3.3V电源。这个上拉电阻对于单总线通信是必须的。为了增强抗干扰能力可以在数据线和地之间并联一个几十pF的小电容。水位开关接口电路干簧管浮球开关一端接地另一端连接一个10kΩ的上拉电阻到3.3V中间点连接到单片机的另一个GPIO如PA1作为输入。当水位高时开关闭合GPIO读到低电平水位低时开关断开GPIO读到高电平。这种电路避免了悬空输入状态明确。继电器驱动电路如前所述单片机GPIO如PA2 - 1kΩ限流电阻 - S8050三极管基极。三极管发射极接地集电极接继电器线圈一端。继电器线圈另一端接5V电源。在线圈两端并联续流二极管阴极接5V阳极接三极管集电极。继电器常开触点一端接220V火线输入另一端接加热棒。3.3 PCB布局布线经验与教训画PCB不是简单的连线游戏好的布局布线能极大提升系统的抗干扰能力和稳定性。这是我踩过坑后总结的几点模块化布局将原理图中功能相关的元件在PCB上就近摆放。例如电源稳压芯片、输入输出滤波电容应集中在一起单片机及其晶振、复位电路、去耦电容应紧凑布局继电器、驱动三极管、接线端子等大功率部分应放在板子一侧与弱电部分保持距离。电源走线优先电源线尤其是5V和3.3V要尽量宽、短减少压降和寄生电感。可以先走电源线和地线再走信号线。地平面与单点接地对于双层板尽量在底层保留一个完整的地平面Ground Plane为信号提供良好的回流路径。对于数字地和模拟地如果用了独立的ADC参考电源建议在电源入口处通过一个0Ω电阻或磁珠单点连接防止数字噪声串扰到模拟部分。大电流路径继电器控制加热棒的220V交流回路走线要足够宽间距要足够大根据安规要求避免爬电距离不足。这个回路要远离单片机等敏感信号线。信号完整性晶振电路要紧贴单片机引脚走线尽量短且粗下方不要走其他信号线最好用地平面包围。高速信号线虽然本项目没有特别高速的避免走直角使用钝角或圆弧。第一次打样时我曾把继电器的控制走线从单片机下方穿过结果继电器一吸合单片机偶尔会复位。后来在PCB改版时将这条线绕开核心区域并加强了电源滤波问题就消失了。这就是布局不当导致电磁干扰的典型案例。4. 嵌入式软件设计状态机与通信协议解析硬件是躯体软件是灵魂。热水器控制逻辑看似简单但要写得稳定、健壮需要考虑各种边界条件和异常处理。我的软件整体架构基于一个主循环和定时器中断核心是状态机。4.1 系统主循环与状态机设计系统上电后进行硬件初始化时钟、GPIO、ADC、定时器、串口等然后进入主循环。主循环中不进行延时等待所有需要定时执行的任务如采集温度、检查水位、控制逻辑、发送数据都通过标志位在中断中触发在主循环中执行。控制逻辑的核心是一个状态机状态包括待机状态系统上电初始状态加热继电器断开。加热状态当当前水温低于设定温度-回差例如设定50度回差2度即低于48度且水位为高时进入此状态闭合继电器开始加热。保温状态当水温达到设定温度时进入此状态断开继电器停止加热。故障状态当检测到水位低干烧风险或温度传感器故障时强制进入此状态断开继电器并通过蓝牙发送报警信息。状态迁移的条件需要仔细定义。例如从“加热状态”到“保温状态”的条件是温度 设定温度从“保温状态”到“加热状态”的条件是温度 (设定温度 - 回差)。引入回差是为了防止继电器在临界点频繁跳动称为“继电器抖动”这会缩短继电器寿命并产生干扰。4.2 关键外设驱动DS18B20与ADCDS18B20驱动它的通信时序要求非常严格必须用微秒级的延时。我通常用一个硬件定时器如SysTick来提供精准的微秒延时函数。驱动代码要严格按照数据手册的时序图编写复位、写位、读位操作。一个完整的温度读取流程是初始化-跳过ROM命令如果总线上只有一个器件-启动温度转换命令-等待转换完成DS18B20需要最多750ms-初始化-发送读暂存器命令-读取9个字节的温度数据。读取的数据是16位补码形式需要转换成实际的温度值。ADC采集用于采集备用模拟传感器如预留的NTC接口或电源电压监控。STM32的ADC配置需要注意采样周期和校准。上电后最好执行一次ADC校准。对于水温这种变化缓慢的信号可以采用定时器触发ADC转换转换完成后在DMA或中断中读取结果并做简单的软件滤波比如连续采样10次然后取中值或平均值以消除偶然干扰。4.3 蓝牙数据收发与协议解析蓝牙通信基于串口中断。我将串口配置为接收中断使能。当HC-05模块收到手机发来的数据后会通过串口TX线发送给STM32的RX引脚触发串口接收中断。在中断服务函数中我将接收到的每一个字节存入一个环形缓冲区Ring Buffer并设置一个“新数据到达”标志。绝对禁止在中断中进行复杂的数据解析这会导致中断时间过长影响其他任务。在主循环中检查“新数据到达”标志如果有效则从环形缓冲区中读取数据并进行协议解析。解析器是一个简单的状态机逐字节判断是否是指令头如S,E,T,:然后提取数据部分直到遇到结束符\n最后计算校验和如简单的字节累加和并与接收到的校验和比对一致则认为指令有效。对于发送数据我同样定义了一个发送缓冲区。当需要上报温度或报警时将格式化好的字符串如ALARM:LOW_LEVEL#放入发送缓冲区然后启动串口发送通常使用DMA或查询方式。为了保证通信的实时性上报数据不宜过于频繁可以定时如每5秒或当状态发生变化时发送。4.4 报警逻辑与系统看门狗报警是安全底线。我设计了多级报警水位低报警最高优先级只要水位开关检测到低水位立即断开加热继电器并持续发送报警信息给手机直到水位恢复。超温报警如果水温超过一个安全阈值如75度无论处于何种状态都断开加热并发送报警。传感器故障报警如果DS18B20读取失败返回85度或-127度等特定值则认为传感器断开或故障进入故障状态并报警。为了防止程序跑飞导致控制失灵必须启用STM32的内部独立看门狗IWDG。在主循环的合适位置定期“喂狗”。如果程序陷入死循环或某个任务阻塞超时看门狗将复位整个系统虽然会导致一次重启但避免了加热棒一直通电干烧这种危险情况的发生。5. 手机APP开发安卓端监控界面实现手机APP是用户交互的窗口。对于这个项目我选择用Android Studio进行开发核心功能是连接蓝牙、收发数据、显示状态和设置参数。这里的关键是蓝牙通信和界面更新。5.1 蓝牙连接与通信基础安卓系统提供了标准的Bluetooth API。主要步骤如下权限申请在AndroidManifest.xml中声明蓝牙相关权限如BLUETOOTH,BLUETOOTH_ADMIN以及对于Android 6.0以上还需要在运行时申请位置权限因为蓝牙扫描需要。设备发现与配对使用BluetoothAdapter启动设备发现通过广播接收器监听找到的设备筛选出我们的HC-05模块通常以“HC-05”为名称前缀。用户选择设备后发起配对连接。建立Socket连接配对成功后使用设备的MAC地址创建BluetoothSocket连接类型选择RFCOMM串口仿真协议这是HC-05使用的协议。连接成功后通过socket.getInputStream()和getOutputStream()获取数据流。数据收发线程网络操作不能在主线程UI线程进行必须开启单独的线程来循环读取输入流中的数据并按照我们定义的协议进行解析。发送数据时将指令字符串写入输出流。5.2 用户界面设计与数据绑定APP界面相对简单主要包含连接界面显示搜索到的蓝牙设备列表点击连接。主监控界面一个大圆圈显示当前水温动态效果一个水位指示灯高/低当前设定温度显示以及加热状态指示灯红色加热/绿色停止。控制区一个滑块或输入框用于设置目标温度一个按钮用于手动强制加热/停止。报警信息显示区当有报警时以醒目方式如弹出对话框或顶部横幅显示。数据更新涉及线程间通信。蓝牙数据接收线程在解析出有效数据如TEMP:45.6后不能直接更新UI需要通过Handler或runOnUiThread方法将数据发送到主线程再由主线程更新对应的UI控件如TextView、ProgressBar。同样用户点击设置按钮时主线程将设定值组装成指令字符串交给发送线程发出。5.3 数据持久化与用户体验优化为了提升体验可以加入一些简单功能自动重连记录上次成功连接的设备MAC地址APP启动时自动尝试重连。设定温度保存将用户设置的目标温度使用SharedPreferences保存在本地下次打开APP时自动载入。历史记录可以定期如每分钟记录一次温度和状态到SQLite数据库并提供一个简单的曲线图界面来查看水温变化趋势。后台服务与通知即使APP退到后台也保持蓝牙连接和数据监听当发生报警时通过系统通知栏发出提醒确保用户能及时知晓。6. 系统联调与常见问题排查所有模块单独测试通过后最挑战也最有成就感的阶段就是联调。问题往往出现在模块之间的交互上。6.1 上电顺序与电源稳定性测试首先不接加热棒只连接控制器、传感器和手机。用万用表监测5V和3.3V电源轨的电压。在系统运行、蓝牙通信、继电器吸合空载等不同状态下观察电压是否有大幅跌落或毛刺。特别是继电器吸合瞬间由于线圈电感的存在会对电源造成一个瞬时冲击。如果电源设计余量不足或滤波不好这个跌落可能导致单片机复位。解决方法是在继电器线圈的电源入口处增加一个大容量电解电容如470uF进行储能缓冲。6.2 蓝牙通信不稳定问题现象手机APP时而能连接时而断开或数据收发断续。排查1电源干扰。这是最常见的原因。用示波器观察给HC-05模块供电的5V或3.3V电源线在继电器动作时是否有噪声。如果有需要在模块电源入口增加π型滤波如一个10uF电解电容并联一个0.1uF陶瓷电容。排查2串口波特率不匹配。确保STM32程序里配置的串口波特率如9600与HC-05模块用AT命令设置的波特率完全一致。甚至数据位、停止位、校验位也要一致。排查3缓冲区溢出。检查STM32端的串口接收缓冲区是否够大解析程序是否及时取走了数据。如果接收中断太快而主循环解析太慢会导致数据被覆盖。增大环形缓冲区大小或提高主循环执行频率。排查4协议错误。用USB转TTL工具将STM32的串口TX/RX引出来连接到电脑串口助手同时HC-05也连接单片机。这样可以在电脑上同时看到单片机发出的原始数据和手机通过蓝牙发来的数据便于逐字节分析协议是否正确。6.3 温度测量不准或跳动大现象DS18B20读数与温度计对比有偏差或数值不稳定。排查1时序问题。DS18B20对时序极其敏感。检查你的微秒延时函数是否准确。最好用逻辑分析仪或示波器抓取DQ线的波形对照数据手册的时序图看复位脉冲、读写时序的宽度是否符合要求。通常问题出在延时不够精确上。排查2总线冲突。确保总线上只有一个DS18B20或者你正确实现了ROM匹配协议。在调试阶段建议使用“跳过ROM”命令只接一个传感器。排查3电源噪声。和蓝牙模块类似电源噪声会影响DS18B20的内部转换。尝试在DS18B20的VDD和GND之间并联一个0.1uF的陶瓷电容并确保其位置靠近传感器引脚。排查4物理安装传感器探头是否与水箱内胆接触良好是否使用了导热硅脂填充空隙安装位置是否远离加热棒直接加热区域以免测量到局部过热6.4 继电器误动作或粘连现象单片机未输出控制信号时继电器自己吸合或断开后实际触点未分开。排查1驱动三极管漏电流。GPIO初始化时应设置为推挽输出并默认输出低电平。如果GPIO处于高阻输入状态可能会因干扰导致电平漂移使三极管轻微导通。确保程序初始化时GPIO状态明确。排查2续流二极管接反或损坏。续流二极管接反等于短路一上电就可能烧毁驱动电路。务必确认二极管方向正确阴极接电源正极。排查3触点粘连烧蚀。如果继电器负载电流接近或超过其额定值在断开感性负载如电机、加热棒冷态电阻小时触点间容易产生电弧长期使用会导致触点熔化粘连。务必选择触点容量留有足够余量的继电器并且避免在电流过零点切换负载对于交流可以用过零检测电路实现固态继电器的过零触发但机械继电器难以精确控制。整个联调过程就是不断假设、验证、排除的过程。我的习惯是准备一个“调试工具箱”万用表、示波器、逻辑分析仪、串口助手、各种杜邦线。先根据现象锁定可能出问题的模块再用工具逐级测量从电源、信号到逻辑一步步缩小范围。记录下每一个问题和解决方案这些积累就是最宝贵的经验。