FEATURED · 精选文章

51单片机DS18B20温度报警系统:单总线时序与Proteus仿真详解

发布时间 / 2026/9/12 11:55:53
来源 / 创域科博编辑部
栏目 / 资讯中心
51单片机DS18B20温度报警系统:单总线时序与Proteus仿真详解 简介一份面向电子信息、计算机等专业在校大学生的课程设计/毕业设计资料基于AT89C51单片机与DS18B20数字温度传感器构建环境温度检测与超限报警系统。压缩包包含36个文件整体约97KB涵盖C语言源码、Keil工程文件、电路原理图、HEX烧录文件及调试中间件等能够完整支撑从硬件搭建、程序编写到烧录验证的实践环节。目前已有36人浏览学习。资料核心呈现单总线通信协议、温度数据解析、阈值比较和蜂鸣器报警等关键模块同时配有系统初始化、按键设置、LCD显示等可复用代码。该项目既可作为课程设计、期末大作业或毕业设计的完整参考也有助于读者理解单片机应用开发流程、传感器接口设计与嵌入式调试方法适合有一定基础或正在筹备相关项目的学习者。1. 为什么一个课设级温度报警系统值得拆开读这个zip里不是网上那种缺驱动、缺头文件的半成品而是一整套能直接打开的Keil工程bsp_ds18b20.c、bsp_lcd1602.c、bsp_key.c、bsp_warn.c、main.c外加Proteus仿真文件BSP_TEMP.DSN和编译好的bsp_tem.hex。整套系统用AT89C51单片机和DS18B20数字温度传感器实现温度采集、LCD1602实时显示、按键设阈值、超限报警。很多人会问温度报警为什么不用热敏电阻加ADC因为DS18B20直接把温度换算成数字量精度最高0.0625℃省掉了运放、采样、校准这些环节。但对51单片机来说DS18B20的单总线时序要求很苛刻正好拿来练精确延时、状态机设计和多文件工程组织。适合做课程设计、毕业设计也适合工作后需要快速补底层驱动细节的工程师。2. 单总线时序AT89C51读DS18B20的核心难点2.1 从初始化到ROM指令总线状态怎么判定DS18B20只有一根数据线DQ所有指令和温度数据都靠主机控制时序来读写。标准流程是初始化复位脉冲→ 发ROM指令 → 发功能指令 → 读写数据。由于它是半双工、单主机多从机的总线结构每个命令前都必须复位一次确定从机在线。AT89C51在11.0592MHz晶振下一个机器周期约1.085us所以延时函数必须按微秒级别来写。常见初始化代码如下sbit DQ P3^7; // 数据线接P3.7 unsigned char DS18B20_Reset(void) { unsigned char presence; DQ 0; // 主机拉低总线 Delay_Us(500); // 至少480us复位脉冲 DQ 1; // 释放总线 Delay_Us(70); // 等待从机响应15~60us后采样 presence DQ; // 从机存在时会拉低60~240us Delay_Us(500); // 等待完整时隙结束 return presence; }presence返回0表示检测到DS18B20返回1表示总线上没有设备。这里有一个常见错误复位后要延时足够时间再读取presence很多人只等几微秒就采样读到的永远是高电平导致后续指令无响应。初始化之后写字节。写每一位都是一个独立的写时隙void DS18B20_WriteByte(unsigned char dat) { unsigned char i; for (i 0; i 8; i) { DQ 0; // 写时隙开始 _nop_(); // 保持低电平至少1us DQ dat 0x01; // 先写最低位 Delay_Us(60); // 整个时隙至少60us DQ 1; // 释放总线等待下一个时隙 dat 1; } } unsigned char DS18B20_ReadByte(void) { unsigned char i, dat 0; for (i 0; i 8; i) { dat 1; DQ 0; // 读时隙起始 _nop_(); DQ 1; // 释放总线从机开始输出 _nop_(); if (DQ) // 15us内采样有效 dat | 0x80; Delay_Us(60); // 等待读时隙结束 } return dat; }写时隙中主机必须先拉低总线以产生起始条件拉低时间不能太短否则DS18B20不认为这是一个时隙。读时隙时主机拉低1us后释放然后在15us内读取DQ电平因为DS18B20只在读时隙开始的15us内输出有效数据过了这个时间它就释放总线了。2.2 读取温度并解析成十进制浮点单点测温最简单的是跳过ROM指令0xCC然后发启动转换指令0x44转换时间最长750ms。转换结束后读暂存器指令是0xBE读出的前两个字节是温度低字节和高字节。代码如下int DS18B20_ReadTemperature(void) { unsigned char tempL, tempH; unsigned int temp; int result; DS18B20_Reset(); DS18B20_WriteByte(0xCC); // 跳过ROM因为总线上只有一个传感器 DS18B20_WriteByte(0x44); // 启动温度转换 while (!DQ); // 等待转换完成忙时DQ为低 DS18B20_Reset(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // 读暂存器低字节在前 tempL DS18B20_ReadByte(); tempH DS18B20_ReadByte(); DS18B20_Reset(); temp (tempH 8) | tempL; if (temp 0x8000) { // 符号位为1说明是负温度 temp ~temp 1; // 补码转原码 result -(int)(temp * 0.0625); } else { result (int)(temp * 0.0625); } return result; }返回的result是整数摄氏度。如果要显示一位小数可以改成返回“温度乘以10”的整数例如25.5℃返回255这样既避免浮点运算又方便LCD1602显示。温度数据是12位分辨率低4位是小数位转换公式为实际温度 原始值 × 0.0625℃。提示while(!DQ)在传感器断线或上拉电阻缺失时会死循环。工程做法是固定延时750ms或者加一个超时计数器。3. 从bsp目录看工程组织驱动层、应用层和主循环3.1 工程文件对照这个项目的目录结构很清晰各文件职责如下表文件职责main.c系统初始化、主循环、任务调度bsp_ds18b20.h / .cDS18B20复位、读写字节、温度采集bsp_lcd1602.h / .cLCD1602初始化、命令/数据写入、光标定位bsp_key.h / .c按键扫描、消抖、阈值加减bsp_warn.h / .c蜂鸣器、LED报警控制STARTUP.A51Keil启动代码不用修改把驱动层和应用层拆成独立文件看似多花了几分钟但后面改显示、加按键、调报警阈值时不用在乱糟糟的main.c里大海捞针。我在维护旧项目时见过把LCD、DS18B20、按键全写在一个文件里的最后帮别人排查蜂鸣器误响问题光定位就花了一下午。3.2 主循环如何兼顾温度采集和按键响应DS18B20一次转换最长750ms如果程序在主循环里直接调用读取温度函数期间按键扫描会被完全阻塞用户按一下阈值加减可能要等一秒才反应。常见解法是用一个简单的分时调度void main(void) { unsigned int counter 0; int temp_tenths 0; unsigned char threshold 30; // 默认高温报警阈值30℃ LCD1602_Init(); Key_Init(); Warn_Init(); while (1) { if (counter % 5 0) { // 每50ms扫描一次按键 Key_Scan(threshold); } if (counter % 100 0) { // 每1s采集一次温度 temp_tenths DS18B20_ReadTemperature(); LCD1602_ShowTemperature(temp_tenths); Warn_Check(temp_tenths, threshold); } Delay_Ms(10); counter; if (counter 1000) counter 0; } }这里用counter对主循环延时10ms计数模拟出一个简单时间片按键50ms扫一次温度1000ms刷新一次。这样做的好处是温度转换的等待分散在时间片里不会长时间霸占CPU。虽然算不上实时调度但工程上够用。counter要记得清零否则到65535后会回绕导致时间片混乱。3.3 阈值存储与掉电丢失threshold只是RAM里的全局变量上电时赋初值30。AT89C51内部没有EEPROM所以关机后阈值会恢复默认值。很多课设到这里就结束了但考虑到实际使用温度报警的阈值如果每次都要进入设置模式重新调很麻烦。外扩AT24C02是最常规的做法或者换用STC系列单片机用内置EEPROM的IAP接口读写阈值。这个项目没有包含这部分但论文里可以写“后续扩展”体现工程思考。4. LCD1602人机交互按键消抖、界面刷新与阈值设置4.1 LCD1602时序和初始化LCD1602是并行接口控制需要RS数据/命令选择、RW读写选择、EN使能和8条数据线。写命令或数据前最好先检查忙标志BF否则可能丢数据。常用代码如下#define LCD_DATA P0 sbit LCD_RS P2^6; sbit LCD_RW P2^5; sbit LCD_EN P2^7; void LCD1602_WriteCommand(unsigned char cmd) { LCD1602_CheckBusy(); // 忙则等待 LCD_RS 0; LCD_RW 0; LCD_DATA cmd; LCD_EN 1; Delay_Us(1); LCD_EN 0; } void LCD1602_WriteData(unsigned char dat) { LCD1602_CheckBusy(); LCD_RS 1; LCD_RW 0; LCD_DATA dat; LCD_EN 1; Delay_Us(1); LCD_EN 0; }初始化序列一般固定为0x388位模式两行显示5×7点阵0x0C屏幕开启光标和闪烁关0x06写入地址自动加10x01清屏。注意P0口内部没有上拉接LCD时必须外接4.7kΩ排阻或独立电阻到VCC否则数据线上的高电平读不出来。4.2 温度小数显示的方法不推荐在51里直接调用printf它会大量占用代码空间而且浮点格式化慢。自己写一个拆分函数更可控void LCD1602_ShowTemperature(int tenths) { unsigned char int_part, frac_part; unsigned char negative 0; if (tenths 0) { negative 1; tenths -tenths; } int_part tenths / 10; frac_part tenths % 10; LCD1602_SetCursor(0, 0); LCD1602_WriteString(Temp:); LCD1602_WriteData(negative ? - : ); LCD1602_WriteData(int_part / 10 0); // 十位 LCD1602_WriteData(int_part % 10 0); // 个位 LCD1602_WriteData(.); LCD1602_WriteData(frac_part 0); // 小数位 }tenths是温度乘以10后的值比如255表示25.5℃。int_part最大99所以显示范围足够覆盖DS18B20的-55℃到125℃。要注意正温度时在符号位显示空格保证LCD上位对齐。4.3 按键扫描和阈值设置状态机bsp_key.c里通常用三个按键SET进入阈值设置、UP加一、DOWN减一。按下最后一个键后阈值立即刷新到LCD第二行。清零抖是按键稳定读取的关键unsigned char Key_ReadStatus(void) { if (!KEY_SET || !KEY_UP || !KEY_DOWN) { Delay_Ms(10); // 第一次检测到按下后延时10ms if (!KEY_SET) return KEY_P_SET; if (!KEY_UP) return KEY_P_UP; if (!KEY_DOWN) return KEY_P_DOWN; } return KEY_NONE; }高电平到低电平跳变的瞬间机械触点会产生长达5~10ms的抖动延时10ms之后重新读取能过滤掉大部分抖动。之后再判断具体是哪个键void Key_Scan(unsigned char *threshold) { unsigned char key Key_ReadStatus(); static unsigned char set_mode 0; if (!set_mode) { if (key KEY_P_SET) set_mode 1; // 进入设置 } else { if (key KEY_P_UP) (*threshold); if (key KEY_P_DOWN) (*threshold)--; if (key KEY_P_SET) set_mode 0; // 退出设置 if (*threshold 99) *threshold 99; LCD1602_SetCursor(1, 6); LCD1602_WriteData(*threshold / 10 0); LCD1602_WriteData(*threshold % 10 0); } }这个状态机的核心是静态变量set_mode它记住当前是否处于设置状态。设置状态下按SET退出然后回到正常运行。注意阈值上下限要约束防止用户把阈值设到负数或超过传感器的量程。5. 报警驱动与Proteus仿真验证5.1 蜂鸣器、LED驱动电路AT89C51的IO口做灌电流时可以吸收约20mA直接推高电平给蜂鸣器却不靠谱因为拉电流能力有限接上去电压会被拉低声音发闷甚至不响。常见做法是用NPN三极管做开关比如S8550P1.0接三极管基极基极串1kΩ电阻发射极接地集电极接有源蜂鸣器负极蜂鸣器正极接VCC当P1.0输出高电平时三极管导通蜂鸣器鸣叫。LED同样串一个220Ω或330Ω电阻一端接P1.1另一端接VCC或GND。如果用灌电流方式LED正极接VCC负极接P1口输出0时点亮。Proteus原理图中引脚接法一目了然注意P0口需要外接上拉排阻否则LCD数据线在仿真中也会乱码。5.2 报警逻辑滞回避免反复触发如果程序写成“温度大于等于阈值就响小于阈值就停”那么在阈值临界点会有两次读取数据微小的波动导致蜂鸣器快速反复开关。解决方法是加入滞回区间#define ALARM_HYSTERESIS 2 // 滞回宽度2℃ void Warn_Check(int temp_tenths, unsigned char threshold) { static unsigned char warn_on 0; int th_tenths threshold * 10; // 阈值也放大10倍 if (!warn_on temp_tenths th_tenths) { warn_on 1; Warn_On(); // 触发报警 } else if (warn_on temp_tenths (th_tenths - ALARM_HYSTERESIS * 10)) { warn_on 0; Warn_Off(); // 解除报警 } }当温度从低到高超过30℃时报警要等到温度降到28℃以下才解除。这个2℃的差值就是滞回区它能滤掉温度在阈值附近抖动产生的误报。如果希望报警声更柔和可以在Warn_On里用定时器翻转P1.0实现蜂鸣器每秒响半秒停半秒。5.3 在Proteus里打开BSP_TEMP.DSN验证整个流程我一般拿到课设源码第一件事不是读代码而是直接跑仿真因为仿真通过了再改代码定位问题会快很多。操作步骤双击BSP_TEMP.DSN打开Proteus工程如果打开失败用“Last Loaded BSP_TEMP.DBK”恢复最近存档双击原理图中的AT89C51芯片在Program File一栏找到Objects/bsp_tem.hex加载后点击OK点击左下角运行按钮LCD1602会显示当前温度鼠标点击DS18B20元件右下角会出现温度调节图标把它拖到35℃观察蜂鸣器和LED是否动作把温度降到27℃报警应停止。如果不是这样检查阈值设置和滞回参数。提示Proteus仿真中DS18B20的DQ引脚到单片机之间必须加一个4.7k上拉电阻到VCC否则时序不满足读回来的温度一直是85℃。6. 烧录排错与几个容易被忽略的细节6.1 AT89C51的烧录方式与兼容替代AT89C51本身不支持串口ISP下载要用并行编程器或专用下载线。现在很多学生在课设里拿到这个工程后直接用STC89C52替换因为引脚和指令集完全兼容烧录只需要USB转TTL串口在STC-ISP软件里选择STC89C52RC、11.0592MHz晶振加载bsp_tem.hex就能烧。这种替换很实用但论文里如果写“基于AT89C51”最好说明STC89C52是兼容方案。6.2 EA引脚必须接高电平AT89C51有内部4KB FlashEA引脚接高电平时访问内部ROM。如果EA悬空或接地CPU会默认从外部程序存储器取指表现为程序不运行、LCD无显示。这是新手最容易犯的布局错误。另外最小系统还需要两个30pF电容配合晶振复位电路用10uF电容加10k电阻。6.3 DS18B20负温度显示乱码和上拉电阻负温度在寄存器里是补码直接转十进制显示会出现65535之类的乱码。我习惯在读温度函数里先判断符号位temp 0x8000然后取反加一最后再乘以0.0625。还有一种情况是无论怎么测都显示85℃通常是因为DS18B20没有正确复位或上拉电阻阻值过大。常见做法是DQ接4.7k电阻到VCC导线超过1m时改2.2k或1k。6.4 用逻辑分析仪看单总线时序如果没有示波器可以拿台式逻辑分析仪或者Digilent的Analog Discovery夹在DQ引脚采样率设2MHz以上抓取复位脉冲和设备应答波形。正常波形中主机拉低约480us后释放总线被从机拉低60~240us然后恢复高电平。写时隙和读时隙宽度都在60us左右如果宽度偏差超过20%说明延时函数没有按照晶振频率校准需要逐条调整Delay_Us。Proteus里也可以用虚拟示波器挂在DQ上效果一样适合在交课设前自查。6.5 阈值设置后的显示不一致设置阈值时LCD第二行显示的“Set xxx”和主界面第一行的“Temp”是两套刷新逻辑。在主循环里温度显示每秒刷新一次而阈值在按键释放时立即写入LCD如果顺序没控制好温度刷新会覆盖掉刚设置的阈值。解决方法是设置一个display_page标志设置状态时主循环跳过温度刷新退出设置后再恢复。这个标志同时也让状态机更干净后续加菜单、加延时息屏都方便。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻