news 2026/9/16 1:08:24

DS18B20温度采集:51单片机与Proteus仿真实战全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DS18B20温度采集:51单片机与Proteus仿真实战全解析

简介:面向51单片机初学者的DS18B20温度采集C语言实例,可配合Proteus仿真进行验证,也适合课程设计参考。资源围绕温度传感器驱动和LCD显示功能展开,包含完整的Keil工程、C源程序及烧录文件,可帮助理解单总线时序、数据读取和显示流程。RAR压缩包共14个文件,仅14KB,轻量紧凑,包含uv2工程文件、c源码、STARTUP.A51启动代码、hex可烧录文件,以及lst、obj、m51等编译过程文件,并带有备份配置,方便直接打开编译或对照检查生成结果;整体结构清晰,便于学习时快速定位源文件和生成文件。目前已有400人学习下载,适合单片机入门者、电子爱好者及做温度采集相关实验的学生参考。通过该资源可获得完整的DS18B20读写程序框架、LCD显示调用方式以及Keil工程下的代码组织思路,对理解51单片机外设操作和C语言底层编程有直接帮助。

1. DS18B20、51单片机和Proteus:温度采集例程先过时序这一关

同样一份DS18B20例程,在Proteus仿真里能正常显示29.5℃,烧进51单片机实物后却经常回85℃或者温度纹丝不动。这不是复制粘贴的问题,而是单总线(1-Wire)通信里的时序、上拉电阻和转换等待三个环节,每一个都有出错机会。DS18B20只用一根DQ线既收命令又回数据,从复位脉冲到读写时隙全是微秒级电平;C语言延时、Proteus元件模型和51单片机IO配置稍有偏差,表现就会完全不同。下面直接按做项目的顺序讲:先把时序参数和命令表立住,再搭Proteus仿真工程,给出能直接编译的C51代码,最后用示波器看波形定位“读不到温度”的原因。适合正在做课设、想从“能显示”做到“稳定可靠”的51开发者参考。

2. DS18B20时序与单总线参数:写C语言前的必要功课

2.1 单总线物理层:为什么DQ必须接4.7kΩ上拉

DS18B20是漏极开路输出,只能把总线拉低和释放,不能主动驱动高电平。51单片机端口本身是准双向IO,高电平时靠内部上拉维持,驱动能力较弱;把DQ直接接在P2.0上而不加上拉电阻,长距离或负载较重时高电平可能被拉低,时序判断自然出错。所以硬件设计上DQ要接一个4.7kΩ电阻到VCC,短距离(一米内)4.7kΩ够用,超过两米建议改成2.2kΩ或加总线驱动器。

供电方式有外接电源和寄生电源两种。做51项目时建议直接外部供电,省去寄生供电在转换期间必须额外处理总线拉高的时序要求。Proteus仿真里漏掉上拉电阻,最常见的症状是复位后读不到存在脉冲,程序一直卡在while(!reset())里;加上上拉后如果还读不到温度,问题大多出在延时或者转换等待不够。连接关系见下表:

引脚外部供电接法寄生供电接法
VDD接+5V,与GND间加0.1μF电容不接外部电源,与GND间加0.1μF电容
DQ4.7kΩ上拉至+5V,接单片机IO4.7kΩ上拉至+5V,接单片机IO
GND接GND接GND

Proteus仿真直接用外部供电,VDD接电源端子,DQ接P2.0并上拉,GND接地,这套接法最省事。

2.2 初始化时序:复位脉冲、存在脉冲和最小C片段

单总线通信从复位开始。主机先把DQ拉低480~960μs,然后释放,DS18B20在15~60μs之后主动拉低总线60~240μs作为存在应答。主机采样DQ电平,就能知道总线上有没有设备。常见错误是拉低时间太短,或者释放后立刻采样,存在脉冲还没出现就误判为无设备。

sbit DQ = P2^0; bit ds18b20_reset(void) { bit ack; DQ = 0; delay_us(500); // 复位脉冲,480~960us DQ = 1; // 释放总线 delay_us(70); // 等15~60us后采样ACK ack = DQ; // 0=存在,1=无设备 delay_us(400); // 补足复位周期 return !ack; }

采样点放在释放后70μs,正好落在DS18B20拉低的时间窗口内。后面的400μs延时不是必须但建议保留,它让整个复位周期接近1ms,避免两次操作间隔太短时总线状态还没恢复。

2.3 写时隙与读时隙:关键就在采样点位置

写时序时,主机先拉低总线;写0时保持低电平60~120μs,写1时只拉低1~15μs后释放,让上拉电阻把总线带高。读时序则反过来,主机拉低至少1μs后释放,然后在15μs内读取DQ电平;DS18B20在主机释放后把总线拉低表示0,或保持高电平表示1。

操作最小/最大时间常用取值
复位脉冲低电平480~960μs500μs
等待存在应答15~60μs70μs
存在应答低电平60~240μs由从机决定
写0时隙低电平60~120μs60μs
写1时隙低电平1~15μs约5μs
读时隙低电平(主机)≥1μs2μs
读采样点释放后15μs内释放后8μs
时隙间隔/恢复时间≥1μs5μs

时序容差其实比很多教程讲的宽松。真正导致失败的是:延时函数被编译器优化掉、总线时序和代码执行顺序错位、采样点太靠近边界。采样点放在读时隙开始后8μs左右最稳,既避开主机拉低造成的过冲,又远在15μs上限以内。

2.4 ROM命令与暂存器:0xCC、0x44、0xBE和85℃的联系

DS18B20命令分ROM级和功能级。单设备场景用0xCC跳过ROM,0x44启动温度转换,0xBE读暂存器;多设备才需要0x55匹配ROM或0xF0搜索ROM。转换命令发出后,12位分辨率最多需要750ms,这期间不要读温度。

命令用途
跳过ROM0xCC单设备时跳过序列号匹配
启动转换0x44触发一次温度转换
读暂存器0xBE读9字节暂存器,前2字节为温度值
读ROM0x33读64位序列号
匹配ROM0x55多设备时按序列号选择设备

出名的“85℃故障”就在这里:DS18B20上电后暂存器默认值为0x0550,折算正好85℃。如果程序没有发送0x44、或者转换还没结束就执行0xBE,读出来的永远是0x0550。用Proteus仿真调试时遇到“永远85℃”,先查代码里0x44和750ms延时在不在,比反复调时序函数更有效。

3. Proteus仿真与Keil联调:从DS18B20元件到hex下载

3.1 Proteus元件库:DS18B20、4.7kΩ电阻和LCD1602的查找方式

在Proteus 8 Professional里按快捷键P打开元件库,搜索DS18B20即可找到数字温度传感器;LCD1602对应搜索LM016L,注意不一定搜“LCD1602”这个拼写。AT89C52和电阻、电容都在默认库,元件名用RES、CAP、CRYSTAL。先把下面这张清单的器件放到原理图:

器件搜索关键词数量作用
单片机AT89C521运行C51程序
温度传感器DS18B201测温
上拉电阻RES1DQ上拉,4.7kΩ
晶振CRYSTAL112MHz
电容CAP2晶振负载电容
液晶LM016L1显示温度

放好后双击元件改属性:电阻的RESISTANCE填4.7k,单片机的Crystal Frequency按实际延时基准填。晶振属性和C语言延时函数基准必须一致,否则示波器看波形时会发现时序宽度整体偏移。

3.2 DS18B20引脚连接:上拉电阻和供电不能省

原理图连接按外部供电方式:GND接系统地,VDD接+5V电源端子,DQ接P2.0,同时DQ到+5V之间放一个4.7kΩ上拉电阻。连接顺序是先放电源端子再接电阻,Proteus仿真中漏了上拉电阻,很多版本会因为DQ浮空读回0xFF或者0x0550,表现和实物“一直85℃”几乎一样。

仿真工程建议固定一套连线流程:先放单片机,把P0口接LCD数据线,P2.0单独引线给DS18B20;再接晶振和负载电容;最后处理显示部分。这样即使后面改到P1口或加按键,只需要改一处连线和端口定义。启动仿真前检查三项:单片机有没有加载hex文件、晶振频率和代码延时基准对不对、电源端子有没有正确接上。

3.3 Keil工程:勾选Create HEX File和延时基准

Keil C51(μVision5)新建工程时选Atmel AT89C52,代码里包含reg52.h头文件。写代码前先在Options for Target - Output里勾选Create HEX File,双击单片机把生成的hex加载进Proteus。这里有个常见坑:C51默认优化级别会把没有副作用的空循环“优化”掉,DS18B20这类靠微秒级延时的代码容易踩中。我一般把优化级别设为O0,并在延时函数里调用_nop_()防止空循环被删除。

#include <reg52.h> #include <intrins.h> void delay_us(unsigned int us) { while (us--) { _nop_(); // 1个机器周期,12MHz下约1us _nop_(); } }

在12MHz晶振下,循环体两个_nop_()配合循环判断,一次大约2μs。把延时函数的实际值用Proteus的虚拟示波器或虚拟仪器校准后再调时序,后续复位和读写就不必反复猜参数。

3.4 先跑一个最小验证:只复位加读序列号

仿真的第一件事不是显示温度,而是验证单总线通不通。只执行一次复位、发送0x33读ROM,把64位序列号用虚拟终端显示出来。序列号能读出来,说明上拉、复位、读时序都正常;读不出来,先查硬连接和延时。把“温度显示”拆成“总线通→能读序列号→能启动转换→能读到温度”四步,出现异常时定位范围会小很多。

4. C语言实现DS18B20读取:时序函数、温度拼接与主循环

4.1 端口定义与延时函数:12MHz下的延时基准

代码从端口定义开始,数据线接P2.0:

#include <reg52.h> #include <intrins.h> sbit DQ = P2^0; // 单总线,连接DS18B20 DQ unsigned char flag_neg = 0; // 负温度标志 void delay_us(unsigned int us) { while (us--) { _nop_(); _nop_(); } } void delay_ms(unsigned int ms) { unsigned int i; while (ms--) { for (i = 0; i < 120; i++); // 12MHz下近似1ms,以编译结果为准 } }

延时函数是整个时序代码的基准,晶振换成11.0592MHz后要重新校准。_nop_()在C51里是一个机器周期,12MHz时正好1μs;delay_us(500)配合循环开销实际约500μs左右,满足480~960μs的要求。统一用delay_usdelay_ms命名,后面调时序时一眼能看出单位。

4.2 复位、写一个字节、读一个字节的完整C代码

三件事一个都不能少:复位建立通信、写字节下发命令、读字节取回数据。

bit ds18b20_reset(void) { // 复位,返回1表示检测到设备 bit ack; DQ = 1; delay_us(2); DQ = 0; delay_us(500); // 复位脉冲480~960us DQ = 1; // 释放总线 delay_us(70); // 等待15~60us后采样 ack = DQ; delay_us(400); // 补足复位周期 return !ack; } void ds18b20_write_byte(unsigned char dat) { unsigned char i; for (i = 0; i < 8; i++) { DQ = 0; // 每个时隙从低电平开始 if (dat & 0x01) { delay_us(5); // 写1:短低后释放 DQ = 1; delay_us(60); // 时隙总长约65us } else { delay_us(60); // 写0:持续拉低 DQ = 1; delay_us(5); } dat >>= 1; // LSB先发 } } unsigned char ds18b20_read_byte(void) { unsigned char i, dat = 0; for (i = 0; i < 8; i++) { DQ = 0; delay_us(2); // 读时隙:拉低2us DQ = 1; // 释放,让从机控制总线 delay_us(8); // 采样点:距开始约10us dat >>= 1; if (DQ) dat |= 0x80; delay_us(55); // 读时隙其余部分+恢复 } return dat; }

写字节时LSB先发,命令和返回数据的位序都是低位在前。读字节代码里先dat >>= 1再判断DQ,正好让第0位进入最低位,第7位进入最高位。延时参数用上面的推荐值,写1时隙低电平约5μs、写0约60μs、读采样点约10μs,都在DS18B20时序参数的中心位置;看不到数据时优先调这三个数。

4.3 温度拼接:12位二进制补码怎么变成有符号小数

读回来的两个字节组成16位寄存器,其中12位有效。完整拼接公式是temp_raw = (msb << 8) | lsb;如果最高位是1表示负温度,先取反加1再分离整数和小数。

unsigned int temp_raw; signed int temp_real; unsigned char lsb, msb; temp_raw = (msb << 8) | lsb; if (temp_raw & 0x8000) { temp_real = (signed int)(~temp_raw + 1); // 补码转原码 flag_neg = 1; } else { temp_real = (signed int)temp_raw; flag_neg = 0; }

得到正数之后,整数部分等于temp_real >> 4,小数部分等于(temp_real & 0x0F) * 625,结果是万分之一摄氏度。比如0x0191:整数25,小数1×0.0625×10000=625,即25.0625℃。

12位原始值实际温度说明
0x01D029.0000℃低位0x00
0x019125.0625℃低位1对应0.0625℃
0xFF92-10.8750℃补码0xFF92取反加1后为0x006E

如果不需要小数,直接右移4位输出整数,-10.875会变成-10;需要显示一位小数时用整数部分和小数625拆分即可,不建议在51上用浮点运算。

4.4 主循环:0x44之后必须等转换完成再0xBE

主流程包含两次复位:第一次复位后发跳过ROM(0xCC)和启动转换(0x44),等待750ms;第二次复位后发0xCC和读暂存器(0xBE),再连续读前2个温度字节。

void main(void) { unsigned char lsb, msb; unsigned int temp_raw; lcd_init(); while (1) { if (!ds18b20_reset()) { lcd_show_string("DS18B20 ERR"); delay_ms(1000); continue; } ds18b20_write_byte(0xCC); // 跳过ROM,单设备场景 ds18b20_write_byte(0x44); // 启动温度转换 delay_ms(750); // 12位分辨率转换时间 ds18b20_reset(); ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // 读暂存器 lsb = ds18b20_read_byte(); msb = ds18b20_read_byte(); temp_raw = (msb << 8) | lsb; // 格式化、LCD显示 delay_ms(1000); // 两次完整读取间隔 } }

“0x44之后必须等转换完成再0xBE”是这条流程的核心。转换期间DS18B20会把总线拉低表示忙,所以理论上可以等DQ变高再继续,但Proteus仿真模型对忙状态的模拟有时和实物不一致,固定延时750ms更通用。实际工程中如果还要响应按键或显示刷新,建议把转换等待拆成“每1ms查询一次DQ”,避免主循环死等。

5. 排错与验证:示波器看DS18B20波形,85℃的两种解法

5.1 用Proteus的虚拟示波器观察复位和读写时隙

仿真的好处是能直接看内部波形。在Proteus左侧栏选Virtual Instruments,把Oscilloscope拖到原理图,A通道接DQ,地线接GND。运行时把时基调到100μs/div,触发沿选下降沿,复位脉冲会作为最宽的低电平出现在屏幕左侧。

判断波形时按特征对应命令:约500μs的低电平之后紧跟着一段窄的低电平脉冲,说明“复位+存在应答”正常;一串持续约60μs的低电平时隙是写0;短促低电平后很快回到高电平的是写1;读数据时主机只释放2μs左右,总线电平由从机决定。如果示波器里只能看到大量60μs宽的低电平、读数据时没有随温度变化的电平,问题出在读时序的采样点,而不是命令字。

波形特征对应环节
500μs宽低电平 + 60μs窄低电平复位脉冲 + 存在应答
等宽约60μs连续低电平写0时隙
短低电平后快速回到高电平写1时隙
释放总线后出现从机信号读时隙

5.2 “永远85℃”的两种原因与读取策略

85℃是DS18B20上电时暂存器的默认值0x0550,所以“永远85℃”的本质是:程序没有真正执行完一次启动转换和等待,只是在反复读取上电默认值。最常见的原因有两个:一是0x44命令根本没发出去,检查复位函数返回值和写字节的位序;二是0x44之后没有等待750ms就紧接着0xBE。在Proteus里,把温度读取写成一个带超时的函数,发送0x44后延时750ms,再复位、发0xBE读值,基本能消除这一故障。

校验方面,读暂存器前9字节中的最后一个字节是CRC校验值,用查表法可以验证读回来的数据是否被破坏。如果对精度有更高要求,可以在配置寄存器写入0x7F(12位分辨率)后再启动一次转换;12位分辨率下转换时间最长为750ms,9位最快只要93.75ms。DS18B20时序设计上最后留一个原则:每次完整读取都以复位开头,任何两个操作之间保留足够的总线恢复时间,精度和转换时间的对应关系在9/10/11/12位下分别是93.75/187.5/375/750ms,做闭环控制或长时间采集时按这个节奏安排读取频率。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 1:07:36

CISP-PTE 日志分析2:Codex 连上 TaoToken 后成功筛出 /admin/goodluck.php

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 1:04:20

开题报告的“隐藏语法”:为什么导师一眼就知道你还没想清楚

毕夏AI官网 www.bixiaai.com 毕夏AI写作官网 www.bixiaai.com 毕夏官网 www.bixiaai.com 毕夏智能写作官网 www.bixiaai.com 你有没有过这种经历。 开题报告写了八页&#xff0c;研究背景引了二十篇文献&#xff0c;研究方法列了五条&#xff0c;进度安排精确到周。发给…

作者头像 李华
网站建设 2026/9/16 1:03:02

五自由度机械臂正逆运动学仿真:DH参数建模与Matlab实现

简介&#xff1a;基于MATLAB实现的五自由度机械臂正逆运动学仿真源码&#xff0c;面向自动化、机械电子、机器人工程等专业的本科毕业设计与课程设计人群&#xff0c;同时也适合用于项目初期的算法验证与功能预研。资源围绕机械臂运动学核心问题&#xff0c;涵盖MDH参数建模、正…

作者头像 李华
网站建设 2026/9/16 1:02:52

Spring Boot + FFmpeg 批量视频处理实战:压缩、切片与异步任务引擎

做服务端的兄弟应该都有同感&#xff0c;视频处理看起来是个小需求&#xff0c;真做起来全是坑。压缩压得狠了画质没法看&#xff0c;压得轻了文件体积没变化&#xff1b;切片切出来播放器不兼容&#xff1b;任务一多&#xff0c;Tomcat线程直接被拖死。这套 Spring Boot FFmp…

作者头像 李华
网站建设 2026/9/16 1:02:44

LMS自适应滤波器原理与MATLAB实现:从维纳解到参数调优的完整指南

简介&#xff1a;面向信号处理学习者和MATLAB使用者的LMS自适应滤波器源码包&#xff0c;解决动态环境中滤波器参数自动调整问题&#xff0c;演示基于最小均方误差准则的梯度下降更新过程&#xff1b;相比RLS、IIR等算法&#xff0c;LMS实现简单、计算量小&#xff0c;适合作为…

作者头像 李华