基于AT89C52与DS18B20的温度报警系统设计
发布时间:2026/9/11 19:08:41 作者:尧图编辑部 阅读量:1,286

简介基于AT89C52单片机的温度报警系统完整设计资源包面向单片机课程设计、电子实训及毕业设计人群解决温度实时显示与超限报警功能开发中资料琐碎、方案不闭环的问题。压缩包约21.14MB内含源码、仿真图、设计报告、原理图、开题报告、元件清单、结构框图、实物照片、元件资料、焊接注意事项、操作说明书及运行图片等12类文件形成从方案论证到实物制作的完整资料链。其中378行带注释源码便于理解程序逻辑13578字设计报告可直接参考撰写论文。功能覆盖四位数码管实时显示、三按键设置温度上下限、蜂鸣器与LED声光报警测量范围099度选用DS18B20温度模块方案典型、复现门槛低。资源包已有319人浏览学习适合需要快速搭建同类系统或完成课程设计的读者按目录检索即可获取电路连接、焊接要点、代码详解、报告模板等关键产出。1. 温度报警系统里那条 378 行代码的价值在哪里一个用 AT89C52 做的温度报警系统放在今天看性能指标算不上惊艳0 到 99 度的测量范围、四位数码管显示、三个按键设上下限、超限声光报警都是教科书级的定位。但这套资源真正值钱的是它把单片机课程设计里最容易被忽略的两件事做完整了一是 378 行带注释的代码二是 DS18B20 这颗单总线传感器在 51 平台上的时序处理。很多人在 Proteus 里仿真能过焊实物就翻车问题大多出在延时精度、按键消抖和报警阈值回差处理上。这套系统的硬件结构不复杂AT89C52 做主控DS18B20 采集温度四位数码管显示三个按键负责设置上下限蜂鸣器和 LED 做声光报警。适合正在做单片机课程设计、或者想快速搭一套温度监控原型的人。它可以用来学 DS18B20 单总线协议、学习如何用定时器做到毫秒级延时也能直接改造成热水器温控、孵化箱监测一类的小项目。2. 硬件选型为什么是 AT89C52 加 DS18B20而不是热敏电阻2.1 AT89C52 的资源够不够用AT89C52 是 51 系列里一颗非常经典的芯片8K Flash、256 字节 RAM、32 个 IO 口、3 个定时器、6 个中断源。这套温度报警系统用到的外设只有数码管、按键、蜂鸣器和单总线传感器IO 占用不多全部资源只用到了大概一半不到给了后续扩展空间。选 AT89C52 的原因主要有三个。第一它和 8051 指令集完全兼容教材、开发环境、烧录工具都成熟出问题容易查资料。第二8K 的 Flash 对于 378 行代码来说绰绰有余哪怕加上注释和调试用的冗余代码也不用担心空间。第三AT89C52 的 IO 口是准双向口驱动能力有限但接数码管段选和位选足够只需要加上拉电阻或者用 573 锁存器做驱动。这套系统里数码管用的是动态扫描方式四个位选分别接 P2.0 到 P2.3段选接 P0 口。P0 口内部没有上拉电阻必须外接上拉排阻否则段选信号无法稳定输出高电平。这个细节在 Proteus 仿真里看不出来因为仿真模型默认有上拉但实物焊接时不加上拉电阻数码管亮度会明显偏暗甚至乱码。2.2 DS18B20 的单总线协议为什么适合这套系统DS18B20 是 DALLAS 公司现 Maxim生产的单总线数字温度传感器测温范围 -55 到 125 度精度可以配置为 9 到 12 位。这套系统只测 0 到 99 度用默认的 12 位分辨率0.0625 度的最小分辨率绰绰有余。单总线协议的核心特点是只有一根数据线既传数据又传时钟所有通信都由主机发起。这意味着时序必须非常精确DS18B20 对复位脉冲、读写时隙的宽度要求以微秒为单位。AT89C52 工作在 12MHz 晶振下一个机器周期是 1 微秒用软件延时循环刚好能满足时序要求不需要额外的定时器干预。使用 DS18B20 还有一个优势是它不需要校准。模拟温度传感器如热敏电阻、PT100 都需要分压电路和 ADC 采样然后查表或者用公式换算温度每个器件之间的一致性差需要逐点校准。DS18B20 出厂前已经校准过直接读出来的就是温度值省掉了大量标定工作。2.3 电源模块和声光报警电路的注意事项这套系统标注了电源模块常见的做法是用 USB 供电 5V 或者 7805 稳压芯片将 7 到 12V 直流降到 5V。AT89C52 的工作电压是 4.0 到 5.5VDS18B20 是 3.0 到 5.5V所以 5V 供电两片都兼容。蜂鸣器部分要特别注意驱动方式。AT89C52 的 IO 口最大灌电流大约 20mA直接驱动无源蜂鸣器声音很小通常需要用三极管扩流。常见做法是 PNP 三极管基极接 IO 口发射极接 VCC集电极接蜂鸣器负极蜂鸣器正极接 VCCIO 输出低电平导通。LED 报警灯串联一个 330 欧姆限流电阻接到 IO 口和 GND 之间即可。声光报警的设计意图是温度超过上限或者低于下限时蜂鸣器响、LED 亮形成同步报警。这块的代码实现不复杂但要注意回差处理后面第 4 章会详细讲。3. DS18B20 驱动代码的完整拆解时序、延时和读温逻辑3.1 单总线时序的三个关键阶段DS18B20 的单总线协议可以分为三层初始化复位脉冲、ROM 命令、功能命令。温度采集的实际流程是先复位然后发送跳过 ROM 命令 0xCC再发送温度转换命令 0x44等待转换完成后再复位跳过 ROM发读取暂存器命令 0xBE最后连续读取两个字节得到温度值。写这一层驱动时最关键的是位操作时序。写 1 时隙和写 0 时隙的区别在于拉低数据线的时间长度读时隙则是主机拉低后释放总线在延时 1 到 2 微秒后采样电平。用 12MHz 晶振的 AT89C52 实现时通常用空的 for 循环做微秒级延时。以复位脉冲为例代码实现大致如下// 复位 DS18B20返回 1 表示存在0 表示无响应 unsigned char ds18b20_reset(void) { unsigned char presence; DS18B20_IO 0; // 拉低总线 delay_us(480); // 维持 480us 以上 DS18B20_IO 1; // 释放总线 delay_us(60); // 等待从机响应 presence DS18B20_IO; // 读从机应答脉冲 delay_us(420); // 剩余时间片 return presence; }这个复位过程看似简单但有两个容易踩的坑。第一delay_us(480)的延时要在 480 到 960 微秒之间过长会认为设备不存在过短则从机没有进入复位状态。第二读取应答脉冲时必须在释放总线后的 60 到 240 微秒窗口内采样早读晚读都可能读到高电平导致误判。写时隙的代码是另一个容易出问题的点具体如下// 写一个字节到 DS18B20 void ds18b20_write_byte(unsigned char data) { unsigned char i; for (i 0; i 8; i) { DS18B20_IO 0; // 起始拉低 delay_us(2); // 2us 延时 if (data 0x01) // 输出当前位 DS18B20_IO 1; else DS18B20_IO 0; delay_us(60); // 保持时隙 DS18B20_IO 1; // 释放总线 data 1; // 处理下一位 } }这里每一位的时序是主机先拉低总线至少 1 微秒然后在 15 微秒内决定是写 1 还是写 0。写 1 时拉低 1 到 15 微秒后释放总线写 0 时持续拉低整个时隙。上述代码是常见做法统一先拉低 2 微秒再根据数据位输出高或者低电平。这个方案简单可靠但是延时函数本身要用示波器校准过否则时序会整体偏移。3.2 读温度数据并做正负温度处理温度转换结束后暂存器中第 0 和第 1 字节分别存放温度的低 8 位和高 8 位符号位在高字节的最高位格式是 16 位有符号补码。以 12 位分辨率为例每一位代表 0.0625 度正数时整数部分直接乘以 0.0625 再乘以 16 就得到实际值负数则取反加一得到绝对值。由于这套系统设计范围是 0 到 99 度只需要处理正数但写代码时建议还是把负数分支做出来防止传感器异常输出负值时显示乱码。读取温度的核心代码如下// 连续读两个字节暂存器返回 16 位原始温度 int ds18b20_read_temperature(void) { unsigned char low, high; int temp_raw; ds18b20_reset(); // 复位 ds18b20_write_byte(0xCC); // 跳过 ROM ds18b20_write_byte(0x44); // 启动温度转换 delay_ms(750); // 等待转换完成 ds18b20_reset(); // 再次复位 ds18b20_write_byte(0xCC); // 跳过 ROM ds18b20_write_byte(0xBE); // 读暂存器 low ds18b20_read_byte(); // 读低字节 high ds18b20_read_byte(); // 读高字节 temp_raw (high 8) | low; // 拼合成原始值 return temp_raw; }其中delay_ms(750)是 12 位分辨率下最大的转换时间。12 位分辨率对应转换时间是 750 毫秒如果设成 9 位分辨率可以缩短到 93.75 毫秒但精度随之降到 0.5 度。这套系统用在报警场景温度变化一般是慢过程750 毫秒的刷新周期完全够用。3.3 四位数码管动态扫描和温度显示四位数码管显示的关键是避免闪烁。常见的做法是设置一个 2 到 3 毫秒的定时中断在中断里轮流点亮一个位显示当前位对应的数字。刷新频率必须在 50Hz 以上也就是每 20 毫秒内扫描完一轮否则肉眼能明显看到闪烁。扫描逻辑用查表法实现段码表写在常量数组中// 共阴极数码管 0-9 段码表 unsigned char code seg_table[] { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F }; void display_temperature(unsigned int temp) { unsigned char thousands, hundreds, tens, ones; // 假设 temp 是已乘 10 后的值例如 25.5 度存为 255 thousands temp / 1000; hundreds (temp % 1000) / 100; tens (temp % 100) / 10; ones temp % 10; P2 0x01; // 选中第一位 P0 seg_table[thousands]; delay_ms(2); P2 0x02; // 选中第二位 P0 seg_table[hundreds]; delay_ms(2); P2 0x04; // 选中第三位带小数点 P0 seg_table[tens] | 0x80; delay_ms(2); P2 0x08; // 选中第四位 P0 seg_table[ones]; delay_ms(2); }这里如果直接用delay_ms(2)做扫描延时会阻塞主循环DS18B20 的 750 毫秒转换等待期间数码管会停住看上去像是死机。更好的做法是用定时器中断驱动扫描主循环只负责更新显示缓冲区和读取温度。资源里提到的 378 行代码带注释这类结构性问题应该已经处理过自己做的时候也可以走这个路线。4. 三按键阈值设置与报警判定状态机设计和回差处理4.1 按键输入和消抖的实现思路三个按键的功能分配通常是一个进入设置模式一个调整上限一个调整下限。考虑到四位数码管显示空间有限设置状态下可以轮流显示上限和下限值或者通过 LED 指示当前设置的是哪一项。按键消抖是这里最容易忽视但实际很关键的环节。机械按键在按下和释放的瞬间会产生约 5 到 20 毫秒的电平抖动如果不做消抖一次按键会被误判成多次触发。消抖的常见做法是检测到按下后延时 10 到 20 毫秒再检查一次电平如果还是低电平就确认按下。更可靠的做法是使用状态机在定时中断里每 10 毫秒扫描一次按键状态将连续 3 次采样都为按下才判定为有效按下。这种方案消除了延时阻塞主循环可以专注处理温度和显示。按键状态机的核心结构如下// 每 10ms 调用一次返回 1 表示该按键被按下 unsigned char key_scan(void) { static unsigned char last_state 0xFF; static unsigned char press_flag 0; unsigned char current_state; // 读取三个按键状态低电平有效 current_state (KEY_SET | KEY_UP | KEY_DOWN); if (last_state current_state) { press_flag 1; // 状态稳定允许触发 } else { last_state current_state; // 状态不稳定等待 press_flag 0; } if (press_flag (current_state 0x01) 0) { press_flag 0; // 只触发一次 return KEY_SET_VALUE; } return KEY_NONE; }这种写法的好处是按键释放前即使有小幅抖动也不会影响已经触发的动作而且支持按住连续加减只需要在设置模式下长按判断即可。4.2 报警判定的回差设计报警阈值设定后报警条件通常写成温度值大于上限或者小于下限则报警。但这种简单判断在边界处会出问题。当温度恰好停留在上限附近时DS18B20 每次读数都有一点微小波动比如 59.9 度和 60.1 度之间跳变蜂鸣器就会反复响停非常刺耳。解决方案是引入回差滞回机制。以上限为例报警进入时温度大于等于 60 度触发但退出报警时必须要温度降到 58 度以下才解除。这样温度在 58 到 60 度之间波动时不会频繁触发报警。代码实现如下// 报警状态1 表示正在报警0 表示正常 unsigned char alarm_state 0; unsigned char temp_value; // 当前温度整数部分 unsigned char temp_low; // 下限值 unsigned char temp_high; // 上限值 #define HYSTERESIS 2 // 回差单位度 void check_alarm(void) { if (alarm_state 0) { // 正常状态进入报警条件 if (temp_value temp_high || temp_value temp_low) { alarm_state 1; buzzer_on(); led_on(); } } else { // 报警状态解除条件加上回差 if (temp_value (temp_high - HYSTERESIS) temp_value (temp_low HYSTERESIS)) { alarm_state 0; buzzer_off(); led_off(); } } }这里回差取 2 度用整数比较避免了浮点数运算。对于实际的恒温控制场景比如要求环境温度保持在 25 到 35 度回差设 2 度意味着 25 度以下报警回升到 27 度才解除不会频繁开关报警器。4.3 设置模式的显示策略设置模式下四位数码管不会再显示实时温度而是显示当前正在调整的阈值。我一般会在数码管最高位用一个小数点亮起来表示设置状态同时配合 LED 指示当前是在调上限还是下限。按键 UP 和 DOWN 每按一次阈值加 1 或减 1长按可以实现快速加减长按 1 秒后每 200 毫秒自动增减。设置完成后的超时退出也要处理。如果用户设置完忘记按确认键系统应该在一段时间后自动退出设置模式避免长时间停留在阈值设置界面而看不到实时温度。常见做法是设置一个 10 秒的倒计时每次按键都会重置计数器超过 10 秒无操作自动保存并退出。5. 实调过程中的关键技巧上拉电阻、晶振选择和仿真差异5.1 Proteus 仿真和实物之间的差异在哪里这个资源包里带仿真图和原理图。Proteus 仿真对 DS18B20 的支持已经比较完善但和实物仍然有差距。仿真中默认的引脚驱动能力、上拉状态和晶振精度都是理想化的而真实 AT89C52 的 IO 口驱动能力有限P0 口内部没有上拉必须靠外部排阻。另外一个常见差异是 Proteus 中 DS18B20 的时序容错。仿真模型的时序窗口比真实芯片宽代码延时稍微偏大或偏小也能正常工作但实物上可能直接读到 85 度这个固定值这是 DS18B20 上电后的默认温度说明初始化成功后没有读到有效寄存器。遇到这个问题先不要怀疑芯片损坏先用示波器或者逻辑分析仪看数据线上的波形。重点检查复位脉冲是否超过 480 微秒、写时隙是否在 15 微秒内完成电平切换、读时隙采样窗口是否对准握手位置。如果没有示波器也可以写一个循环测试代码不断复位并读取应答信号通过 LED 显示是否返回存在脉冲快速定位是复位失败还是读数据失败。5.2 晶振频率对时序延时的影响AT89C52 可以使用 6MHz、12MHz、24MHz 等多种晶振频率但 DS18B20 驱动的延时函数是基于晶振频率设计的。12MHz 晶振下机器周期为 1 微秒一个delay_us(1)的循环大约是 1 个机器周期加跳转指令的实际开销整体偏大。nop()指令是最准确的单机器周期指令精确延时建议用多个nop()组合。常见做法是写一个空循环延时函数然后用示波器实测校准参数时钟频率换一颗晶振延时参数必须重新调整。下面代码是一个简单的微秒延时实现具体的循环次数需要根据编译器和优化级别实测确定// 微秒延时函数Keil C51 下 O0 优化的实测校准值 void delay_us(unsigned int us) { unsigned int i; for (i 0; i us; i) { _nop_(); // 12MHz 下大约 1us _nop_(); } }注意 Keil C51 的优化选项会影响延时循环的实际执行时间。如果开了高等级优化循环可能被编译器改写延时时间发生变化。稳妥做法是延时代码所在文件设置成 O0 优化或者将延时循环改用汇编实现保证时序稳定。5.3 手动复位电路和电源去耦的规范处理AT89C52 的复位电路是经典的 10 微法电解电容加 10K 电阻接在 RST 引脚。上电瞬间电容充电RST 引脚短暂保持高电平完成复位。实物焊接时如果复位不稳定最常见的原因是电容漏电或者电阻值偏差太大。用万用表量一下 RST 引脚电平正常工作时应该稳定在 0V 左右。电源去耦也是实物调试的重点。AT89C52 和 DS18B20 之间的数据线电平容易受电源噪声干扰建议在每个芯片的电源引脚就近放置 0.1 微法陶瓷电容电源入口加一个 10 到 100 微法的电解电容。蜂鸣器属于感性负载关断瞬间会产生反向电动势在三极管集电极和电源之间反向并联一个 IN4007 续流二极管能有效避免干扰复位电路。焊接顺序建议先焊电源部分再焊主控最后焊 DS18B20 和按键。DS18B20 是 TO-92 封装三根引脚间距不大焊接时注意不要把数据线和 VCC 短路。焊完用万用表蜂鸣档量一下 VCC 和 GND 是否短路确认无误后再上电这样可以避免烧坏芯片。本文还有配套的精品资源点击获取