ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于51单片机和DS18B20的水温控制系统Proteus仿真设计

基于51单片机和DS18B20的水温控制系统Proteus仿真设计 简介面向单片机课程设计与电子竞赛初学者的水温控制系统仿真设计以单片机为核心实现温度实时采集、数码管显示、按键设定上下限、超限报警及继电器控制加热。系统低于下限自动加热高于上限声音提示完整呈现典型闭环控制逻辑。压缩包共18个文件主要包含C语言源码、头文件、Keil工程文件、Proteus仿真图纸及hex烧录文件资源整体仅52KB便于快速下载与本地运行验证。已有324人学习浏览适合作为水温测控类项目的参考模板。借助源码与仿真可直观梳理温度传感器读取、按键处理、数码管动态扫描和继电器驱动等模块的编写思路也可直接在此基础上扩展PID控制或人机交互功能。1. 水温控制系统的仿真设计绕不开的滞回控制在Proteus里跑一套水温控制看起来只是把DS18B20读出来的数值和上下限比较然后点亮继电器可真按这个思路写完你会发现温度在上限附近来回跳继电器吸合声比散热风扇转得还勤。原因很简单直接用单阈值做开关控制传感器噪声和加热余温会把系统推向临界点抖动。这个项目正好把问题处理得比较完整。压缩包里包含温度传感器.DSN仿真工程、temp.hex固件和wendu.c、main.c源码。主控采用51单片机配DS18B20采集温度按键调整上限和下限温度低于下限时报警并持续加热至接近上限高于上限时再次报警数码管实时显示当前温度。对做课程设计、玩单片机仿真设计、想从点灯进阶到闭环控制的读者都适用。2. 系统方案与器件选型DS18B20单总线与继电器控制链路老式的温度控制系统大多用热敏电阻加ADC实现DS18B20在这个设计中之所以能站住脚是因为它把温度直接转成数字量省掉了模拟调理电路也省掉了比较器。分析这套仿真先看信号流DS18B20采集温度发送给51单片机单片机比较上下限之后输出到继电器和蜂鸣器同时把温度刷到数码管上。所有逻辑都围绕这条链路展开。2.1 51单片机如何串起这些外设从main.c的代码结构看主控没有采用复杂的中断嵌套而是主循环轮询加定时器扫描的组合。水温是一个大惯性被控对象温度变化以秒甚至分钟为单位而DS18B20单总线通信本身要求微秒级延时其他任务对实时性的要求并不苛刻轮询调度完全够用。wendu.h里把端口定义集中管理是这套源码里比较规范的写法。比如数码管段码接P0、位选接P2按键接P1口DS18B20数据引脚接P3.7继电器与蜂鸣器分别接独立I/O口。硬件改动时只需要改头文件不用去各处源码里找宏定义。仿真的好处就在这里改完端口之后点一下运行立即看到结果不用焊板子。2.2 DS18B20单总线选型理由与接线细节热敏电阻方案的痛点有两个一是B值一致性差换一个传感器就要重新标定上下限二是模拟信号经过导线容易耦合继电器的开合干扰。DS18B20把测温探头、A/D转换和单总线协议做在同一个封装里直接用数字电平通信抗干扰能力强不少12位精度模式下分辨率为0.0625摄氏度在40到90摄氏度的热水区间里完全够用。接线方面DS18B20只有三条引脚VCC接5V、GND接地中间的数据引脚接单片机P3.7。单总线是漏极开路结构必须在数据线上对VCC接一颗4.7k欧姆上拉电阻高电平全靠这颗电阻保持。Proteus里经常有人忘了放上拉结果读到的温度恒等于85摄氏度或者跳变到-55度。wendu.c里的时序读取函数对电平变化很敏感上拉缺失时整个复位应答波形都会变形。2.3 三极管驱动继电器与数码管显示分配51单片机的I/O口驱动能力有限P1口虽然可以输出几毫安但继电器线圈通常需要几十毫安所以必须加一级三极管放大。常见做法是用NPN型三极管8050基极串1k欧姆电阻接单片机集电极接继电器线圈线圈两端反向并联一颗1N4148二极管吸收关断时的反向电动势。很多人在Proteus里省略续流二极管仿真不会立刻报错但实物板子上继电器每动作一次三极管就承受一次高压尖峰损坏率明显上升。链路主要器件关键参数作用温度采集DS18B20单总线、12位精度数字温度采样人机交互独立按键低电平有效设置上、下限阈值显示4位数码管动态扫描显示当前温度执行继电器线圈5V驱动控制加热设备报警蜂鸣器有源蜂鸣器上下限越界提示数码管是动态扫描方式P0口输出段码P2口轮流选通位选端。动态扫描的原理是让每一位轮流点亮利用人眼视觉暂留形成“同时显示”的错觉。刷新频率一般取50到100Hz太快会占用CPU时间太慢会有明显闪烁。源码头文件里如果段码表顺序是共阴数码管从0到9接线也要对应共阴否则显示会乱码。3. 源码实现温度采集、按键上下限与继电器阈值比较拿到wendu.c、main.c和wendu.h建议先从主循环看起。整个程序没有使用实时操作系统主循环就是调度核心。读一遍之后你会注意到所有耗时操作都被切成了小块DS18B20转换期间让数码管继续扫描这样显示才不会在温度更新时闪一下。3.1 主循环的轮询调度框架我在整理这类源码时会把主循环归纳成“读取温度、按键扫描、阈值比较、显示刷新”四个步骤。参考实现如下while (1) { current_temp read_temperature(); // 读取DS18B20当前的温度值 key_scan(); // 扫描设置键、加键、减键 if (current_temp temp_lower) { relay_on(); // 低于下限继电器吸合加热 buzzer_alarm(); // 同时给出报警提示 } else if (current_temp temp_upper) { relay_off(); // 高于上限停止加热 buzzer_alarm(); // 超温报警提示人工处理 } else { relay_off(); // 在上下限之间不加热不报警 buzzer_mute(); } display_temp(current_temp); // 数码管显示当前温度 }这段代码看起来简单但没有把read_temperature()放在显示之后因为温度采集和阈值比较是控制回路的闭环环节显示只是人机接口。如果把显示放在前面控制周期会被动态扫描拖长继电器动作的实时性就变差。temp_lower和temp_upper是全局变量按键可以直接修改复位后可以重新上电恢复默认值。3.2 DS18B20时序读取与CRC校验DS18B20是单总线协议关键就是严格遵循时隙。wendu.c中至少需要实现五个基础操作复位脉冲、存在应答、写时序、读时序、转换并读取温度。常见实现如下unsigned int read_temperature(void) { unsigned char low_byte, high_byte; unsigned int temp_value; ds18b20_reset(); // 主机拉低480us再释放等待DS18B20应答 ds18b20_write_byte(0xCC); // 跳过ROM指令适合总线上只有一个传感器 ds18b20_write_byte(0x44); // 启动温度转换指令 delay_ms(100); // 等待转换12位精度最长需750ms ds18b20_reset(); ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // 读暂存器指令读取2字节温度寄存器 low_byte ds18b20_read_byte(); high_byte ds18b20_read_byte(); temp_value (high_byte 8) | low_byte; if (temp_value 0xF800) { temp_value ~temp_value 1; // 负温度转成正数后取负水温场景较少用 } return temp_value; }这里0xCC跳过ROM编码意味着总线上只能挂一个DS18B20如果挂了多个必须改做ROM匹配指令。0x44启动转换后芯片会把温度寄存器刷新转换期间芯片处于忙碌状态此时读RST信号会读到低电平。0xBE读取暂存器的前两个字节分别对应温度的低温字节和高温字节。需要特别提醒12位分辨率下转换时间最长是750ms代码里的delay_ms(100)在实际工程中是不够的。常见做法是启动转换后不傻等而是让主循环顺手处理数码管扫描之后再次读取时先检查转换完成标志。Proteus仿真里的DS18B20模型通常比实物快容易掩盖这个时序问题这也是仿真跑通了、板子却不工作的典型坑。3.3 按键调整上下限与防抖处理按键直接连P1口按下为低电平。源代码里的按键扫描通常包含软件消抖和处理“下限大于上限”的边界保护。参考逻辑如下void key_scan(void) { if (key_set 0) { delay_ms(10); // 按下延时10ms避开机械抖动 if (key_set 0) { setting_mode !setting_mode; // 切换设置态继续按加减键调整 while (key_set 0); // 等待按键释放防止连触 } } if (setting_mode 1) { if (key_up 0) { delay_ms(10); if (key_up 0) { temp_upper; while (key_up 0); } } if (key_down 0) { delay_ms(10); if (key_down 0) { temp_lower--; while (key_down 0); } } if (temp_lower temp_upper) { temp_lower temp_upper - 2; // 强制保持2度以上的回差 } } }这段代码的边界保护很关键。如果用户把下限调到等于上限系统会在同一温度点上反复切换继电器进入所谓的继电器抖动。强制让下限低于上限至少2度相当于人为构造了一个滞回窗口。滞回控制的意义就在于此温度从低到高时以上限作为切除条件从高到低时以下限作为投入条件。两条线之间形成死区从而规避临界点振荡。3.4 蜂鸣器报警策略的两种状态再看一下报警低于下限时报警此时继电器同时吸合加热高于上限时也报警但继电器关断。两次报警的意义完全不同。低于下限时报警是告知加热系统已经投入温度正在回升高于上限时报警是提示操作人员水温超限需要人工介入或者等待自然冷却。许多初学者会把这两个状态简单合并成一个“越界报警”这样操作人员在温度从高回落穿过上限时容易被误报干扰。源码里蜂鸣器如果采用有源蜂鸣器只需要给高低电平就能发声不需要额外提供方波信号。单片机端口输出低电平驱动时蜂鸣器另一端接VCC考虑到端口电流有限建议也串一个限流电阻。4. Proteus仿真HEX文件烧录、连线检查与在线调试Proteus项目由温度传感器.DSN提供默认加载了完整的原理图。芯片、数码管、按键、继电器、DS18B20之间都已经连线打开后第一件事不是点运行而是检查单片机里是否加载了正确的temp.hex文件。4.1 Keil编译到Proteus加载HEX的完整操作Keil工程文件是temp_uvproj双击打开后先确认Target里的芯片型号。在Proteus中与原理图里的元件型号保持一致通常都是AT89C52或类似51内核。编译通过后会生成temp.hex路径一般在工程目录的OBJ文件夹下压缩包里的temp.hex可以直接使用。在Proteus中加载HEX的步骤非常固定双击原理图上的单片机元件在Edit Component对话框中找到Program File属性点击文件夹图标选择temp.hex。同时把Crystal Frequence设置为12MHz这个频率要和Keil代码里的延时函数匹配。如果代码里用了定时器做波特率或者毫秒延时时钟频率不同会造成延时偏差数码管可能闪烁或者DS18B20时序读不出来。# 命令行方式打开Proteus工程适用于反复回归验证 proteus 温度传感器.DSN4.2 用Proteus虚拟仪表定位时序问题点运行之后双击DS18B20芯片可以查看实时温度值。想验证单总线时序不用额外接仪器直接右键选择调试并打开波形窗口数据引脚的波形就能显示出来。正常的单总线复位波形包含一个480us以上的低电平脉冲随后芯片拉低60us作为存在应答。如果Proteus中的DS18B20读数异常我先看两个位置一是数据线上是否有4.7k欧姆上拉电阻二是单片机程序加载是否成功。程序没有加载时点击单片机不会看到绿点高亮数码管也不会有任何输出。还有一种情况是仿真速度被拉得太慢单总线延时函数在模型里按毫秒级执行如果仿真步长设置不合理温度更新会非常迟钝看起来像“卡死”。4.3 数码管乱码与继电器频繁吸合的排查方向数码管乱码多数时候不是代码问题而是段码表与数码管型号不匹配。Proteus里的数码管如果默认是共阴但代码里的段码表是共阳P0口输出的段码就全部取反了此时显示的内容必然是乱码。遇到这类问题先暂停运行查看数码管的Common属性确认阴极还是阳极再对应调整段码表。继电器频繁吸合则要区分两种情况一种是没有设置上下限默认的下限上限差值太小另一种是温度传感器读取值在临界点来回跳。把temp_upper - temp_lower的差值拉大到3到5度同时观察波形窗口看温度数值是否稳定。这一步把滞回窗口调好之后继电器动作次数会肉眼可见地减少。现象可能原因处理方式温度显示85DS18B20上拉电阻缺失数据线对VCC接4.7k电阻数码管全乱共阴共阳段码不匹配按Proteus元件属性修改段码表数码管不亮HEX文件未加载重新指定 temp.hex继电器高频跳动上下限差值太小调整 temp_upper 与 temp_lower温度变化极慢仿真步长过慢降低Proteus仿真速度或调大步长5. 进阶手法看门狗与Modbus帧接收数据程序的水温扩展把仿真稳定跑通之后这个项目还有两个明显可以往工业现场靠的改进方向一是给裸机循环加看门狗防止单片机死机后加热器一直工作二是把本地阈值信息通过Modbus协议送出让上位机可以远程读取当前水温和上下限设定值。5.1 看门狗喂狗位置与继电器安全兜底很多51内核的单片机片内已经有看门狗但默认关闭。开启看门狗之后程序就必须在溢出时间之内喂狗一次。放在主循环末尾是一种常见做法但前提是主循环里的阻塞延时不能超过看门狗溢出时间。我一般会把喂狗放在温度比较完成之后void main_loop(void) { while (1) { current_temp read_temperature(); key_scan(); threshold_control(); // 上下限比较并控制继电器 display_temp(current_temp); wdt_feed(); // 看门狗喂狗确保主循环通畅 } }看门狗的溢出时间要仔细算。DS18B20转换等待如果采用阻塞延时750ms而看门狗时间只有2.1秒主循环内单次温度读取就用掉三分之一窗口再加上数码管扫描和按键防抖风险其实不小。更稳妥的做法是把温度转换等待改成非阻塞延时利用定时器或者循环计数完成转换等待这样主循环轮询速度更快喂狗窗口也更宽裕。5.2 扩展Modbus单片机帧接收数据程序与上位机对接如果之前写过Modbus单片机帧接收数据程序现在只需要把水温上下限和当前温度映射到保持寄存器。串口初始化为9600bps或115200bpsModbus RTU从站地址设为1功能码0x03用于读保持寄存器0x06用于写单个寄存器。串口接收中断里按帧处理状态机完整帧通常是8字节从站地址、功能码、寄存器地址高字节、低字节、数据高字节、低字节、CRC低字节、CRC高字节。void uart_isr() interrupt 4 { if (RI) { RI 0; rx_buf[rx_len] SBUF; if (rx_len 1 rx_buf[0] ! 0x01) { rx_len 0; // 从站地址不匹配直接丢弃 } if (rx_len 8) { if (crc16_check(rx_buf, 8) 1) { parse_modbus_frame(rx_buf); // 解析寄存器地址与数据 } rx_len 0; } } }这段代码里rx_buf是串口接收缓冲区CRC校验通过之后才调用解析函数避免干扰信号造成误动作。上下限设定值经过Modbus写入后按键仍然可以本地修改两条路径都走同一个全局变量不会互相冲突。上位机在数据采集的同时也能看到继电器当前的吸合状态这就是把仿真资源扩展成远程监控节点的方法。5.3 仿真与实物移植的最后检查最终从仿真进入实物时重点检查三处一是DS18B20数据线上的上拉电阻必须存在实物上省略它会得到飘忽不定的温度值二是继电器线圈两端续流二极管不要因为仿真里没有影响就省略实物没有二极管会反向击穿三极管三是晶振频率要和Proteus配置一致否则串口波特率和延时全部偏移。验证方法上先不接加热设备用一个电位器或温度源缓慢调整DS18B20感知的温度观察继电器在上下限处的动作是否干脆再从低于下限的方向和高于上限的方向分别逼近阈值确认滞回窗口的存在。把这组数据记录在实验表格里就能准确判断报警响应时间是否满足要求。本文还有配套的精品资源点击获取
返回列表