C51温度检测报警系统设计:DS18B20单总线驱动与回差控制
2026/9/11 19:34:26 网站建设 项目流程

简介:面向单片机课程设计、毕业设计及工程实训场景,这份基于C51的温度检测报警系统资料包适合需要完成类似课题的初学者或进阶学习者。系统以AT89C51为核心,通过DS18B20采集环境温度,实时显示在LCD1602上,并支持按键自由设定上下限,超限时触发高温或低温报警灯及电机正反转,涵盖完整逻辑闭环。资源共9个文件,压缩包约2.69MB,包含C语言源码(如LCD.c、Motor.c)、设计报告docx、答辩pptx、Proteus工程pdsprj、工程截图jpg及README说明,便于对照学习代码与仿真调试。已有150人浏览学习。资料可作为课程设计或初期项目立项的参考方案,重点帮助理解传感器读取、液晶显示、按键交互与报警控制等模块的集成思路,但需具备一定基础,自行调试并扩展功能。

1. 温度检测报警系统是C51课程设计里最容易翻车的高频选题

温度检测报警系统是C51单片机课程设计中的高频选题,也是翻车率最高的选题之一。很多学生拷贝网上源码,烧进去后温度显示乱跳或停在85℃,报警在阈值附近反复通断,答辩时被问“为什么用DS18B20”“阈值存在哪里”就卡壳。这个题目真正练的是把最小系统、单总线时序、定时器、按键和输出驱动串成一个稳定闭环。下面按课程设计的完整链路来走,从传感器选型、C51驱动实现、报警回差控制讲到Keil工程搭建,最后落到报告和答辩PPT的技术整理。适合正在做这个课程设计的人,也适合想拿C51做完整小项目练手的人。

2. 系统结构设计与温度传感器选型依据

2.1 C51最小系统与温度传感器三种方案对比

C51课程设计一般以STC89C52RC或AT89S52为核心,这类芯片内部没有ADC。温度检测要在“没有ADC”和“模拟/数字接口”之间做选择。常见三种方案:热敏电阻分压、LM35模拟输出、DS18B20单总线数字输出。热敏电阻阻值随温度非线性变化,需要查表标定;LM35输出电压10mV/℃,线性度好,但要外接ADC0809或换带ADC的STC15系列,外围电路变大;DS18B20用单总线协议,不占ADC,一根数据线直接输出16位温度值,12位分辨率下达到0.0625℃,完全满足室温超限报警需求。下表从课程设计交付角度做对比:

方案信号类型是否需ADC精度外围电路代码复杂度答辩说服力
热敏电阻模拟电阻值低,依赖标定一般
LM35模拟电压一般
DS18B20单总线数字0.5℃/0.0625℃中高

DS18B20看起来代码更复杂,因为要处理严格的时序,但课程设计要的就是这个训练点。方案确定后,晶振选11.0592MHz还是12MHz会直接决定延时和波特率。11.0592MHz能把9600波特率误差降到0,DS18B20时序按微秒计算时与12MHz差距不大;如果还要用串口打印调试,11.0592MHz更稳妥。复位电路用10uF电解电容和10k电阻接到RST引脚,Proteus里不接也能仿真,但实物不接复位电路,上电瞬间程序可能跑飞。

2.2 DS18B20单总线时序与C51引脚规划

DS18B20的DQ引脚需要外接4.7k上拉电阻到VCC。测量时,单片机先复位总线,然后发送跳过ROM指令0xCC,再发启动转换指令0x44,等待转换结束(12位精度最长750ms),再次复位并发送读取暂存器指令0xBE,连续读两个字节得到温度低字节和温度高字节。写0时总线低电平需保持60~120us,写1时低电平保持1~15us后释放;读时序由主机拉低总线1~15us,随后释放并在15us前采样。C51主频12MHz时,一个_nop_()大约耗时1us,但单总线操作时不能开串口中断,否则时序被截断。

引脚分配参考:LCD1602数据线接P2口,DS18B20接P3.7,蜂鸣器接P1.5,LED接P1.6,按键接P3.2和P3.3。P3口本身带第二功能,如果开发板上有串口和外部中断,注意别把DQ与RXD/TXD接在一起。下面是一个标准的初始化与存在脉冲检测代码:

#include <reg52.h> #include <intrins.h> sbit DQ = P3^7; void Delay10us(unsigned char t) { while(t--) { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } } bit DS18B20_Reset(void) { bit presence; DQ = 1; Delay10us(2); DQ = 0; Delay10us(50); // 拉低约 500us DQ = 1; Delay10us(6); // 释放后等约 60us presence = DQ; Delay10us(50); // 等待存在脉冲结束 return presence; // 返回 0 表示传感器在位 }

Delay10us的循环体里有5个_nop_(),加上while(t--)sbit操作,12MHz下循环一次约10us,参数50对应500us左右。如果改成11.0592MHz,同样代码耗时约10.85us,500us需求仍能满足。presence = DQ放在释放后的6次延时之后,也就是大约60us处,DS18B20的存在脉冲通常发生在释放后的60~240us窗口,所以这个采样点读到的电平时序上没问题。实际调试中如果连续返回1,先查DQ引脚是否虚焊、上拉电阻是否漏贴、供电是否5V,DS18B20在3.3V下驱动能力下降后会表现为随机复位失败。

2.3 报警输出电路与硬件设计细节

蜂鸣器若是5V有源蜂鸣器,工作电流约20~30mA,C51的IO口弱上拉模式只能提供几百微安级输出,不能直接驱动。常见做法是加一个S8550三极管做开关,IO口通过1k电阻接基极,蜂鸣器接在集电极和VCC之间,发射极接地。IO口输出高电平时三极管导通,蜂鸣器响;输出低电平时关闭。如果直接用IO口驱动,蜂鸣器声音很弱,甚至在报警状态被拉低为0V导致单片机复位。继电器控制加热设备时,必须并联1N4007续流二极管,否则断电瞬间的反向电动势会打坏IO口。课程设计如果只做声光报警,用三极管驱动蜂鸣器就够;如果报告里写了“控制加热器”,就要把继电器保护电路画出来,否则答辩被问到“感性负载怎么保护”会很被动。

3. C51程序实现:温度采集、整数换算与报警回差控制

3.1 定时器1秒节拍与主循环设计

温度采集程序最容易写崩的地方,是主循环里用Delay(1000)等转换完成,然后按键扫描失灵。我一般会让定时器0产生1s时间片,主循环检测到标志后再执行一轮温度读取。定时器0初值按12MHz计算,工作方式1单次最多定时65.535ms,所以设置50ms中断一次,累计20次就是1s。以下代码是定时器初始化和中断服务函数:

#include <reg52.h> bit t_1s_flag = 0; void Timer0_Init(void) { TMOD = 0x01; // 定时器0,方式1,16位定时 TH0 = 0x3C; TL0 = 0xB0; // 初值,50ms@12MHz ET0 = 1; TR0 = 1; EA = 1; } void Timer0_ISR(void) interrupt 1 { static unsigned int cnt = 0; TH0 = 0x3C; TL0 = 0xB0; cnt++; if(cnt >= 20) { cnt = 0; t_1s_flag = 1; } }

TMOD=0x01只把定时器0设置为16位定时,不影响定时器1;TH0/TL0重装必须放在中断入口最前,否则中断处理时间过长会累积计时误差。interrupt 1是Keil C51规定的定时器0中断号,STC89C52RC的中断向量与该标准一致。主循环检测到t_1s_flag后调用温度读取。需要强调,读取DS18B20时序期间要关中断,否则定时器中断插入会破坏单总线时序,因此在读取函数入口执行EA=0,读取结束后EA=1。定时器计数因此会产生几个毫秒误差,但对秒级采集没有影响。

3.2 写字节、读字节与整数温度换算

DS18B20一个字节的收发需要按位操作。单片机向传感器写一个字节时,先发最低位,每个位周期拉低总线,延时1~15us后写入位电平,再保持60~120us;读字节时主机产生一个短暂的拉低脉冲,释放后采样总线状态。下面这段是常用的位时序实现:

void DS18B20_WriteByte(unsigned char dat) { unsigned char i; for(i=0; i<8; i++) { DQ = 0; _nop_(); _nop_(); DQ = dat & 0x01; Delay10us(8); DQ = 1; dat >>= 1; } } unsigned char DS18B20_ReadByte(void) { unsigned char i, dat = 0; for(i=0; i<8; i++) { DQ = 0; _nop_(); _nop_(); DQ = 1; dat >>= 1; _nop_(); if(DQ) dat |= 0x80; Delay10us(8); } return dat; }

写字节函数里Delay10us(8)让总线位电平保持80us左右,如果Keil优化等级设置到3,编译器可能把空循环优化掉,导致延时失效。把Delay10us参数设为unsigned char t并放在单独C文件中,能避免被过度优化。读字节函数在DQ=1后只执行两个_nop_()就采样,对应约15us内的采样窗口,再继续等80us结束该位周期。读出的两个字节拼接成16位有符号数后,还需要换算成带小数的温度值。

读取温度的完整过程如下:

int DS18B20_ReadTemperature(void) { unsigned char high, low; int raw; EA = 0; // 关中断,保护单总线时序 DS18B20_Reset(); DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0x44); // 启动转换 while(!DQ); // 等待转换完成 DS18B20_Reset(); DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0xBE); // 读暂存器 low = DS18B20_ReadByte(); high = DS18B20_ReadByte(); EA = 1; raw = (high << 8) | low; return raw; }

while(!DQ)在传感器完成转换后会释放总线,DQ变高,循环退出。如果传感器没接好,DQ一直为高,这个等待会立即跳过,读到的数据就是上一次暂存器里的旧值。换算时,0.0625℃/LSB写成整数运算就是“乘以25再除以4”,得到温度值乘以100的整数。例如原始数0x0191(十进制401)乘以25除以4,结果是2506,对应25.06℃。显示时把2506拆成千位、百位和个位即可。这种算法没有浮点误差,在阈值比较时直接用temp_100 > 2800表示28.00℃,非常直观。

3.3 报警阈值设定与回差控制

报警逻辑不能写成“温度大于上限就响”,否则温度在阈值附近抖动时,蜂鸣器会反复通断。工程做法是加入回差,也叫滞回比较。设置上限TEMP_MAX和回差TEMP_DIFF,触发报警时温度超过上限,解除报警时温度必须低于TEMP_MAX - TEMP_DIFF;下限报警反过来处理。以下是一段可直接移植的报警检查函数:

#define TEMP_MAX 28 // 上限 28.00℃ #define TEMP_MIN 18 // 下限 18.00℃ #define TEMP_DIFF 2 // 回差 2.00℃ bit over_high = 0; bit over_low = 0; void Alarm_Check(int temp_100) { if(!over_high) { if(temp_100 > TEMP_MAX * 100) over_high = 1; } else { if(temp_100 < (TEMP_MAX - TEMP_DIFF) * 100) over_high = 0; } if(!over_low) { if(temp_100 < TEMP_MIN * 100) over_low = 1; } else { if(temp_100 > (TEMP_MIN + TEMP_DIFF) * 100) over_low = 0; } P1 |= 0x60; // 默认关蜂鸣器和LED if(over_high || over_low) { P1 &= ~0x20; // 蜂鸣器响 P1 &= ~0x40; // LED 亮 } }

阈值全部乘以100,与temp_100同单位,避免浮点。P1 |= 0x60把P1.5和P1.6置1,P1 &= ~0x20把蜂鸣器引脚拉低。有源蜂鸣器低电平驱动时响;LED如果也是灌电流接法,低电平点亮。开发板如果用的是高电平驱动,逻辑要反过来。回差选取要看场景,强电控制场合设2~5℃都合理,纯声光报警设1~2℃即可。回差太大会造成控制目标偏移,例如上限28℃、回差5℃意味着下次解除报警要降到23℃。下面是一组可直接写进报告的参数示例:

参数说明
TEMP_MAX28上限阈值
TEMP_MIN18下限阈值
TEMP_DIFF2回差,防止报警抖动

4. Keil5工程搭建、Proteus仿真与实物下载调试

4.1 Keil5兼容C51和STM32安装时的共存配置

很多电脑上先装了Keil MDK用于STM32,打开后找不到C51器件,于是觉得51编译器不见了。这其实是Keil的ARM和C51是两套独立组件。Keil官网提供C51安装包,安装时可以选择与MDK相同或不同目录。安装完成后,µVision里编译51工程时自动选择C51编译器,编译STM32工程时选择ARMCC,互不干扰。问题多出在License:File -> License Management里能看到C51和ARM的许可状态,C51项目提示PRODUCT MISSING,说明当前授权没有C51组件,需要单独添加C51许可证。C51组件许可缺失时,用学校正版License添加即可,不要依赖来路不明的工具。

STC89C52RC这类国产51型号在Keil原装设备库里没有,需要用STC官方的STC-ISP软件导入。STC-ISP里有一个“Keil仿真设置”页签,点击“添加型号和头文件到Keil中”,选择Keil安装目录后,软件自动写入STC官方设备数据库。导入后Device列表能看到STC89C52RC、STC15W4K32S4等型号,同时把STC89C52.H之类的头文件复制到Keil的INC目录。这个操作只增加设备描述,不改变C51编译器,所以不会影响原有ARM工程。如果暂时无法安装STC设备库,直接用Keil自带的AT89C52也能编译,因为代码里用到的寄存器在标准51里都存在;烧录时再通过STC-ISP选真实型号下载HEX即可。

4.2 Proteus仿真中DS18B20和晶振频率的调试坑

Proteus仿真这种系统,最常见两个怪现象:温度恒为85℃,或者数值周期性跳变。85℃是DS18B20上电后的初始值,说明程序发出的启动转换指令没有被模型执行,常见原因是仿真原理图里的晶振频率远低于12MHz。Proteus放置8051时默认Clock Frequency为1MHz,如果程序延时按12MHz计算,单总线时序会被拉长12倍,自然失败。正确做法是在单片机属性里把Crystal Frequency改为12MHz或11.0592MHz。第二个坑是Proteus的DS18B20模型对时序非常敏感,Reset释放后等待存在脉冲的代码如果超过240us才采样,模型会返回错误。调试时把虚拟示波器接到DQ引脚上,观察复位低电平是否保持480~960us;如果低电平过短,检查Delay10us里是否有被Keil优化掉的空循环。仿真环境下供电和上拉电阻的寄生效应与实物不同,仿真通过不代表实物一定通过,反之亦然。

现象可能原因处理方式
温度恒为85℃晶振频率设置不对改Crystal Frequency为12M
温度不变传感器引脚接触不良测DQ电压,检查上拉电阻
下载失败TXD/RXD接反交叉连接后重试

4.3 HEX烧录、冷启动与串口打印温度

编译生成HEX文件后,用STC-ISP软件烧录STC89C52RC。STC单片机ISP下载必须冷启动:先在STC-ISP界面选择串口、单片机型号和HEX文件,点击“下载/编程”,直到提示“正在检测目标单片机”后,再给目标板断电重新上电。如果程序里用了外部晶振,STC-ISP里还有一个“选择IRC频率”的选项,选择与硬件一致的频率,否则串口波特率或定时器初值会偏。下载失败时优先检查USB转TTL模块的TXD/RXD是否交叉连接,以及目标板是否独立供电。

调完下载,可以加一个串口输出函数,把temp_100格式化后发到串口助手,快速判断温度读取是否正常。9600波特率下,11.0592MHz晶振,定时器1方式2初值设为0xFD。发送字节流可以直接按整数处理:

void Send_Temp(int temp_100) { unsigned char b[4]; b[0] = temp_100 / 1000 + '0'; b[1] = (temp_100 / 100) % 10 + '0'; b[2] = (temp_100 / 10) % 10 + '0'; // 发送012这样的三位整数,再单独发小数位 }

这里temp_100 / 1000得到十位,temp_100 / 100 % 10得到个位,temp_100 / 10 % 10得到十分位。串口助手显示“25 5”这样的非格式化数据也比没有输出强,至少能区分读温度的问题和显示的问题。如果串口收到数据全是0xFF,检查波特率初值是否写反,或者晶振频率与STC-ISP里选择不一致。

5. 报告撰写与答辩PPT里容易加分的三个实测技巧

5.1 报告中的回差控制和整数运算论证

课程设计报告不要平铺直叙,“温度大于上限报警”只能算需求说明。在软件设计部分用一小节专门讲回差控制,给出触发/解除阈值公式,再附一组实测数据:设定上限28℃,回差2℃,温度从27.9℃升到28.3℃触发报警,降到27.5℃解除报警,记录时间点。这组数据以表格呈现,比贴一段代码更有说服力。再把温度整数换算算法temp_100 = raw * 25 / 4写进报告,注明“避免浮点库占用资源”,就显示出你理解了嵌入式资源约束。源码组织上,把DS18B20驱动、LCD显示、按键和报警逻辑分文件写,报告里附源码文件清单,评委扫一眼就知道不是单文件堆出来的。

5.2 答辩PPT按“一页一问题”准备

答辩PPT不要做成长篇代码展示。按10页左右的容量,每一页对应一个可能的提问:系统框图页对应“为什么选DS18B20”,准备一个方案对比表;软件流程图页对应“报警阈值存在哪里”,解释存在STC单片机内部EEPROM或外部AT24C02中,掉电不丢失;实物演示页对应“传感器被拔掉会怎样”,演示代码中Reset返回1时显示Sensor Error,蜂鸣器不动作,避免误报。这样评委的追问恰好落在你准备过的内容上,比你猜题更可靠。PPT里放一张用串口记录的温度趋势图,展示温度从室温爬升到报警阈值的完整过程,以及报警解除点的位置,能直观说明回差控制的必要性。

5.3 演示前最后5分钟的自检清单

答辩现场最容易翻车的是硬件而不是PPT。按这个顺序自检:先用STC-ISP确认HEX已写入且校验通过;用LED闪烁程序排除最小系统不起振的问题;再烧温度检测程序,用手捏住DS18B20的金属外壳,2秒内温度应上升2℃以上;最后把电源断开再重插一次,确认冷启动后报警功能自动恢复。如果温度显示为85℃或负数,先别改代码,检查DQ线上拉电阻和第一次初始化时序。经过这套自检,现场演示出问题的概率会降到很低;最后给报告附上这份自检清单本身,也可以作为“调试与验证”章节的内容来源,评分时比单纯放截图更扎实。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询