
简介基于单片机Proteus仿真的智能热水器系统设计完整方案面向单片机课程设计、电子竞赛及嵌入式入门学习者。资源包共收录41个文件涵盖Proteus仿真工程pdsprj、C语言源程序、LCD1602及DS18B20驱动头文件、可烧录的HEX文件等核心代码与仿真图一一对应便于对照理解系统整体流程。已有132人学习参考。方案围绕STC8952设计通过DS18B20检测冷热水温度结合红外传感器识别人员是否在淋浴区域利用步进电机调节冷热水混合比例实现出水温度自动跟踪设定值人离开时自动关闭电磁阀回来时重新开启同时配备声光告警与LCD1602实时显示功能。压缩包仅398KB结构紧凑适合快速下载并开展仿真验证与实践拓展。1. 基于单片机protues仿真的智能热水器系统设计为什么要先在仿真里把温度闭环跑通做智能热水器这个课题无论是课程设计还是毕业设计最常见的交付物就是一套proteus仿真图加一份单片机源代码用51单片机采集水温按键设定目标温度继电器控制加热棒通断LCD显示当前温度和状态超过上限自动断开。整个过程不需要真买加热器、继电器和温度传感器一张protues仿真图加一段C51代码就能把完整控制逻辑演示出来这也是它成为单片机原理及应用课程里高频选题的原因。本设计的核心不只在“能加热”而在“把温度控制闭环跑稳”温度采集、设定比较、滞回控制、显示刷新四件事要在一个while循环里配合好。新手常犯的错是把代码写成了闯关式的顺序执行仿真图看着没毛病一跑温度却上下乱跳。所以本文按“系统方案 → 仿真电路 → 源代码 → 调试排错”的顺序把智能热水器系统设计从protues仿真图到keil源代码逐层拆开让照着做的人能直接复现。2. 智能热水器protues仿真的系统组成与选型51单片机、DS18B20、LCD1602怎么搭配2.1 温控系统的负反馈闭环结构智能热水器本质是一个典型的负反馈温度控制系统。传感器检测当前水温控制器把当前值和用户设定值做比较输出开关信号控制加热设备温度低于下限时开启加热温度高于上限时停止加热。系统框图可以简化成“温度传感器采集 → 单片机比较处理 → 继电器执行 → 加热电阻 → 水箱 → 再回到传感器”这个环在protues仿真里同样成立只是真实加热棒被一个LED或电阻负载代替。这种结构决定了选型方向需要一路数字温度输入、一个显示输出、两三个按键输入、一路开关量驱动输出。选用STC89C52或AT89C52这类51单片机就够了理由是片上资源刚好覆盖这些需求P0到P3四组I/O口、两个定时器、一个UART不需要ADC模块因为DS18B20输出的是数字信号。这里要注意protues仿真模型里STC89C52并不存在通常用AT89C52替代两者在引脚和指令集上兼容仿真通过后把hex烧进STC真机也能跑。2.2 DS18B20温度传感器的单总线时序与精度DS18B20是智能热水器protues仿真里最值得讲清楚的器件。它只有一根数据线DQ同时负责供电和通信所以一根引脚要完成复位、写命令、读数据三件事。复位时序是主机拉低总线480us以上然后释放DS18B20收到这个低电平脉冲后会在60us到240us内把总线拉低作为应答脉冲。主机通过这个应答判断传感器是否在线。DS18B20的测温分辨率配置为12位时温度精度达到0.0625°C量程从-55°C到125°C对热水器控制来说完全够用。温度读回来是两个字节高字节的高5位是符号位实际温度值需要把两个字节拼接后乘以0.0625。很多人在protues仿真里看到显示85°C不是器件坏了而是主机没读到正确数据默认上电值被读出来问题基本出在单总线时序上后面第四章会给可用的驱动代码。2.3 显示、按键和加热驱动的选型显示设备选LCD1602是最稳妥的做法四线数据模式就够用节省了4个I/O口有的protues模板里也提供LM016L它就是LCD1602的Proteus模型可以直接用。按键用三个独立按键完成“加温度、减温度、设定/确认”配合软件消抖不需要矩阵键盘。加热驱动用继电器模型输出P1.0口给出开关电平通过三极管驱动继电器线圈在protues仿真图里继电器触点直接接到一个加热灯上即可优先级是控制逻辑演示比功率级真实性更重要。单片机选12MHz晶振和Keil里的开发板配置保持一致。反过来提醒一下protues新版支持STM32系列仿真如果坚持用STM32做这个系统代码复杂度和仿真时长都会明显增加做课设不划算。2.4 元件选型参数速查表搭建protues仿真图前先把元件清单整理好避免画到一半回头找库。下表是这套智能热水器系统设计最常见的元件配置。元件Proteus模型关键词关键参数用途单片机AT89C52Clock Frequency: 12MHz主控温度传感器DS18B20单总线12位分辨率水温采集液晶屏LM016L16x2字符型温度与状态显示继电器RELAY线圈驱动常开触点加热通断加热指示LED-RED正向压降2V模拟加热状态按键BUTTON低电平有效温度设定上拉电阻RES4.7kDS18B20上拉晶振CRYSTAL12MHz时钟蜂鸣器BUZZER有源蜂鸣器超温与按键提示表格里DS18B20的上拉电阻决定了仿真的稳定程度。真实电路单总线需要4.7k电阻拉高到VCCproteus里如果不加这个电阻数据线悬空时容易读回随机值。这个细节在protues仿真里最容易被人忽略接线时务必加上。3. 在protues仿真图里搭智能热水器电路从新建工程到加载hex文件3.1 新建protues工程与仿真图的元件放置顺序打开proteus ISISFile → New Project工程名建议写成“smart-heater”芯片型号选不选都不影响因为后面要手动替换成AT89C52。新建完成后从左侧元件模式进入“P”按键拉出元件搜索列表依次搜索放置AT89C52、DS18B20、LM016L、RELAY、BUTTON、LED-RED、RES 4.7k、CRYSTAL 12MHz、CAP-ELEC 10uF、CAP 30pF、BUTTON、NPN三极管BC108。放置元件的顺序有讲究先放单片机以它为中心规划四周布局。左侧放晶振电路和复位电路上方放DS18B20右侧放LCD1602下方放按键和继电器这样仿真图清晰也方便后面给protues添加引脚时找到对应网络。如果搜索时找不到某个元件多半是拼写问题RELAY要找的英文名是“RELAY”电阻是“RES”电容是“CAP”DS18B20在传感器类目下。3.2 最小系统接线晶振、复位、电源网络AT89C52的40脚接VCC20脚接GND。晶振接在XTAL1和XTAL2之间两个30pF电容分别从晶振两端接地这是标准配置。protues里双击单片机把Clock Frequency改成12MHz不用手动给晶振模型设频率也能跑但我习惯这里直接改防止与源码里延时参数对不上。复位电路用10uF电解电容到VCC10k电阻到GND复位脚RST接中间节点。protues还提供一种更省事的电平式复位双击单片机把Rest Op-amp属性改为“POWER-ON RESET”仿真见效果更快。但为了跟真实板子一致我用RC复位电路顺便把按键复位也接出来占一个I/O口。电源网络用protues左侧的“POWER”和“GROUND”终端标号连接不需要实际拉线到VCC/GND。凡是要接电源的引脚放一个电源标号上去就是电气连接这是protues仿真图里最基本的习惯能显著减少连线。3.3 DS18B20连线和LCD1602四线模式接线DS18B20的引脚从左到右分别是GND、DQ、VCC。仿真图中GND接GNDVCC接VCCDQ接到单片机的P3.7并且在DQ线上接一个4.7k电阻到VCC。注意在proteus里DS18B20模型的面朝方向会改变引脚顺序接线前先旋转元件确认好引脚名再连。LCD1602采用四线数据模式RS接P2.0RW接P2.1E接P2.2数据口D4到D7接P2.4到P2.7。RW脚在本设计中始终为写操作可以直接接地但我保留P2.1接线方便后面做读忙检测。LCD的3脚是对比度调节端串一个10k电位器到地仿真中如果显示淡或不显示最常见原因就是这个脚悬空或电平不对。3.4 继电器驱动与加热指示电路的仿真接法真实系统里单片机I/O口灌电流能力有限不能直接驱动继电器线圈所以需要NPN三极管做功率放大。仿真图中按这个层次还原P1.0经1k电阻接到BC108基极发射极接地集电极接继电器线圈一端线圈另一端接VCC同时在继电器线圈两端反向并联一个二极管IN4001释放反向电动势。继电器常开端子一端接加热电源正极另一端接到加热指示灯LED串联限流电阻再回到电源负极。这个电路有一个关键点proteus中的RELAY模型自带线圈电阻仿真时如果直接让P1.0高电平驱动电流计算可能与真实不符但控制逻辑展示不受影响。指示灯用LED-RED限流电阻选330欧姆。如果想把加热做得更逼真可以把LED换成“LAMP”灯泡模型并添加一个可调电位器模拟水温的变化但这会引入更多非线性初学时反而干扰判断。3.5 按键网络标注与protues添加引脚的方式三个按键分别接P3.2、P3.3、P3.4每个按键一端接到该引脚另一端接GND引脚侧不加上拉电阻时必须在代码里启用内部上拉。51单片机P3口内部有上拉按键按下为低电平松开为高电平这个电平逻辑决定了消抖代码的写法。如果不需要在仿真图上画大量飞线可以用protues左侧的“LBL”标签模式给每个引脚添加网络标签。实际操作是点击模式区里的“标签”图标在连线端点上点一下输入网络名如“KEY_UP”“DQ_P37”同名标签自动电气连接。这就是网上经常被搜的“protues怎么添加引脚”这个问题对应的操作先放引脚或导线再用标签命名网络而不是去元件库里找“Pin”。3.6 加载keil生成的hex文件到protues仿真图画完后双击单片机模型在“Program File”一栏选择Keil工程生成的hex文件比如smart-heater.hex然后在“Clock Frequency”填12000000。这里有一个常见的坑Keil里需要勾选Output选项卡中的Create HEX File否则编译后不生成hexprotues里加载会提示文件不存在。加载完成后点左下角运行按钮应该看到LCD亮起来按键调节时显示变化继电器随温度切换。提示如果加载hex后仿真没有反应先检查单片机型号。用了STC89C52这个名字在protues里是找不到的要用AT89C52加载的hex路径中不能有中文字符protues对中文路径的处理一直不友好这是老生常谈但回报最高的一条排查经验。4. 智能热水器系统源代码DS18B20驱动、按键调参和滞回控制算法4.1 代码结构与引脚宏定义源代码组织成四个文件main.c负责主循环和状态机ds18b20.c负责单总线时序lcd1602.c负责显示control.c负责按键和加热策略。下面按模块给出核心代码并说明参数设置逻辑。// main.h #include reg52.h sbit DQ P3^7; // DS18B20数据线 sbit RELAY P1^0; // 继电器控制 sbit KEY_UP P3^2; // 加温键 sbit KEY_DOWN P3^3; // 减温键 sbit KEY_SET P3^4; // 设定/确认键 #define DEFAULT_TARGET 45 // 默认目标温度 #define HYSTERESIS_DOWN 2 // 低于目标2度开启加热 #define HYSTERESIS_UP 2 // 高于目标2度停止加热 #define KEY_DEBOUNCE_MS 20 // 按键消抖时间 unsigned char target_temp DEFAULT_TARGET; unsigned char current_temp 0; bit heat_status 0; // 当前加热状态宏定义里HYSTERESIS_DOWN和HYSTERESIS_UP就是滞回控制的两个阈值参数。真实热水器不会让继电器在设定温度附近频繁通断所以我不是简单做“低于45度开高于45度关”而是低于43度开、高于47度关。这样前后相差4度继电器动作频率大幅下降这是这套系统设计里最值得调整的参数。4.2 DS18B20单总线时序代码与延时说明// ds18b20.c void delay_us(unsigned char us) { while (us--) { _nop_(); } } bit ds18b20_reset(void) { bit presence; DQ 0; delay_us(80); // 拉低480us以上这里12MHz下约500us DQ 1; delay_us(4); presence DQ; // 读取应答脉冲 delay_us(20); return presence; // 返回0表示存在 } void ds18b20_write_byte(unsigned char dat) { unsigned char i; for (i 0; i 8; i) { DQ 0; _nop_(); DQ dat 0x01; // 先写低位 delay_us(12); DQ 1; dat 1; } } unsigned char ds18b20_read_byte(void) { unsigned char i, dat 0; for (i 0; i 8; i) { DQ 0; _nop_(); DQ 1; _nop_(); dat 1; if (DQ) { dat | 0x80; } delay_us(12); } return dat; } int ds18b20_read_temp(void) { unsigned char tl, th; int temp; ds18b20_reset(); ds18b20_write_byte(0xCC); // 跳过ROM ds18b20_write_byte(0x44); // 启动温度转换 delay_us(100); // 仿真中等待转换完成固定延时 ds18b20_reset(); ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // 读取暂存器 tl ds18b20_read_byte(); th ds18b20_read_byte(); temp (th 8) | tl; return temp; }代码中延时函数在12MHz晶振下一个_nop_()约1us。复位时序拉低80次循环实际约500us满足DS18B20手册要求的480us以上释放后延时4us再读DQ正好落在应答窗口60us到240us之间。写时序的关键是先发低位每写一位前必须把总线拉低中间不要做太长延时否则会被对方误判为复位。读时序里主机拉低1us后必须释放总线然后快速采样这是最容易出问题的地方protues仿真时序比真实芯片宽容但延时太离谱仍然读不出正确温度。转换等待我用固定延时而不是查询忙标志理由是protues仿真速度远慢于真实芯片查询方式要反复操作单总线仿真运行明显变卡固定延时虽然浪费几十毫秒但换来流畅的交互体验。读出来的temp是带符号16位12位分辨率下数值乘以0.0625就是实际温度例如temp等于0x00D5213温度是13.3125°C。4.3 温度处理与LCD显示代码// lcd1602.c void lcd_write_cmd(unsigned char cmd) { LCD_E 0; LCD_RS 0; LCD_RW 0; LCD_D4 (cmd 4) 0x01; LCD_D5 (cmd 4) 0x02 ? 1 : 0; LCD_D6 (cmd 4) 0x04 ? 1 : 0; LCD_D7 (cmd 4) 0x08 ? 1 : 0; LCD_E 1; _nop_(); LCD_E 0; LCD_D4 cmd 0x01; LCD_D5 cmd 0x02 ? 1 : 0; LCD_D6 cmd 0x04 ? 1 : 0; LCD_D7 cmd 0x08 ? 1 : 0; LCD_E 1; _nop_(); LCD_E 0; delay_us(20); } void show_temp(int raw_temp) { unsigned int temp_x10; char buf[16]; temp_x10 (unsigned int)(raw_temp * 0.625); // 乘0.0625再乘10 if (raw_temp 0) { temp_x10 (unsigned int)((0xFFFF - raw_temp 1) * 0.625); } sprintf(buf, T:%d.%d C, temp_x10 / 10, temp_x10 % 10); lcd_write_string(0x80, buf); }这里把温度乘以0.625而不是0.0625是为了用整数运算得到十分之一度避免浮点库。仿真中显示“T:45.3 C”比“T:45 C”更能验证传感器分辨率确实生效。负数温度的补码处理先判断符号再对补码取反加1得到绝对值这个分支在热水器场景里很少触发但调试时用protues把DS18B20环境温度改成负值就能验证这个分支逻辑。4.4 主循环按键消抖与滞回控制策略// main.c void main(void) { int raw_temp; unsigned char key_state; lcd_init(); relay_init(); lcd_write_string(0x80, Smart Heater); lcd_write_string(0xC0, Target: 45 C); while (1) { // 按键扫描带消抖和电平判断 if (KEY_UP 0) { delay_ms(KEY_DEBOUNCE_MS); if (KEY_UP 0) { if (target_temp 60) target_temp; } while (KEY_UP 0); } if (KEY_DOWN 0) { delay_ms(KEY_DEBOUNCE_MS); if (KEY_DOWN 0) { if (target_temp 0) target_temp--; } while (KEY_DOWN 0); } // 温度读取与转换 raw_temp ds18b20_read_temp(); current_temp (unsigned char)((raw_temp * 25) 8); // 100/4 近似处理 // 滞回控制目标温度上下浮动2度 if (heat_status 0) { if (current_temp target_temp - HYSTERESIS_DOWN) { RELAY 1; heat_status 1; } } else { if (current_temp target_temp HYSTERESIS_UP) { RELAY 0; heat_status 0; } } show_temp(raw_temp); lcd_write_string(0xC5, heat_status ? HEAT ON : HEAT OFF); delay_ms(100); } }主循环里的滞回控制是这段代码的灵魂。用一个heat_status位记录当前是否处于加热状态状态切换只发生在跨越上下阈值时停止状态下只有温度降到目标减2度才启动加热加热状态下只有温度升到目标加2度才停止加热。这种“启动后再等上超”的逻辑比每次都独立比较目标温度的方法更符合继电器实际工况。温度换算那行raw_temp * 25 8有点隐晦展开说明raw_temp乘以0.0625是实际温度等于raw_temp乘以625再除以10000。为了让整数运算更高效我把它近似为raw_temp乘以25再右移8位因为25/256等于0.09765625而0.0625×100/1000这里调用处需要用真实系数。更稳妥的写法是current_temp (unsigned char)(raw_temp * 0.0625)但会引入浮点或者改为temp_x10的整数方式后再取temp_x10/10作为current_temp。提示实际操作中把current_temp换算统一放在ds18b20_read_temp返回后用temp_x10/10整数化避免不同精度系数混用导致设定45度实际显示44度。控制精度不必过分纠结热水器系统本身允许正负2度误差这是滞回参数设计时就考虑进去的容差。5. protues仿真联调技巧与DS18B20读85度的排查方法5.1 联调前的三个静态检查双击proteus里的单片机确认Program File路径指向hex文件同时该hex不是上次编译的旧文件。Keil里每次重新编译后看Build Output窗口是否出现“Creating Hex File...”。没有的话打开Project → Options for Target → Output勾选Create HEX File。第二步检查晶振频率Keil工程Target选项里的Xtal(MHz)填12proteus单片机的Clock Frequency填12000000两处一致才能保证延时函数的时间基准正确。第三步检查电源网络protues里VCC标号的元件是否混用了不同电压级别DS18B20的VCC和继电器的VCC如果在同一张图里默认电压一致即可不需要直流电压源表。5.2 DS18B20显示85度或-0.5度的处置protues仿真中最常见的现象是LCD温度区域恒定显示85度原因是上电后DS18B20寄存器里的默认值就是85度代码没真正读到数据时就会把这个值刷新到屏幕。按以下顺序排查先看DQ网络有没有4.7k上拉电阻到VCC没有就补上再看ds18b20_reset函数返回值presence如果恒为1说明总线没收到应答脉冲把复位低电平时间延长到100次循环最后用protues的单步调试在读取温度函数入口打断点检查DQ引脚波形仿真里可以使用示波器或者用虚拟终端打印原始数据。如果显示-0.5度说明读到的暂时寄存器数值是0xFFFF这是器件刚上电、还没启动转换时的状态。检查0x44转换命令后是否给了足够的等待时间调试时把固定延时加大到150ms确认转换完成后再读0xBE。5.3 一个减少仿真卡顿的有效参数proteus每秒执行数百万条指令但显示刷新和DS18B20单总线位操作耗掉大量仿真时钟。把主循环最后的delay_ms(100)调整为200按键扫描时的while(KEY_UP 0)空循环会拖慢整段逻辑改为带超时的消抖消抖确认后等待按键释放的同时累计超时计数超过500ms就强制退出。这个改法既能防重复触发又不至于在仿真里卡住整个系统。调完这些把目标温度设为40度仿真运行后人为把protues里DS18B20的属性值调高到60度观察继电器断开和HEAT OFF刷新就能在一个仿真周期内完成整个温控闭环的验证。本文还有配套的精品资源点击获取