首页/新闻资讯/正文详情

基于AT89C51与DS18B20的多点温度检测系统设计

发布时间:2026/11/5 7:17:38 来源:云帆数科 栏目:资讯中心
基于AT89C51与DS18B20的多点温度检测系统设计
简介这是一份面向电子信息、自动化及嵌入式课程设计学习者的单片机多点温度检测系统设计文档围绕AT89C51与DS18B20组成的两路温度采集与1602LCD循环显示方案展开可用于课程设计、毕业设计开题及单片机综合实验参考。压缩包内共1个doc文件约199KB正文按绪论、总体方案、硬件设计、软件设计、系统仿真、总结与参考文献组织并附源程序代码硬件部分讲主控制器、显示模块、温度采集模块及单片机最小系统软件部分涉及单总线复位、跳过ROM、启动温度变换、读取暂存器和温度值换算等内容。该文档已有1652人学习下载适合需要理解多点测温原理、整理原理框图与电路连接、对照代码完成仿真调试的读者查漏补缺。1. 从保鲜层和冷冻层说起两点温度检测要做成什么样一台家用冰箱的保鲜层和冷冻层温度差着十几度一个传感器放在里面看到的永远只是某一个位置的温度用户想知道的是两个温区各自的真实状态。类似的场景还有配电柜的进出线接头、机房里机柜的前后风道、恒温箱的内外壁——这就是多点温度检测要解决的问题。基于单片机的多点温度检测系统设计核心也就三句话用一颗 AT89C51 做主控挂两路 DS18B20 数字温度传感器把测到的两处温度通过 1602 液晶以两秒间隔循环显示出来。测温范围按 -30℃ 到 99℃ 设计分辨率 0.0625℃显示到 0.1℃。适合正在做集成电路课程设计、单片机课设或相关毕设的人交付物通常是一套原理图、一份仿真工程和一份带注释的 C 源码。2. 总体方案设计一颗 51、两路单总线、一块 1602 的职责划分整个系统如果画成一个方块图只有四个部分主控制器、温度采集、显示输出、供电与时钟。看着简单真正决定这份方案能不能交上去答辩的是几个分岔路口怎么选主控用哪颗芯片、传感器怎么挂、显示用数码管还是液晶、温度值是硬件处理还是软件换算。这几步选错了后面画原理图、写代码、跑仿真全都要返工。2.1 主控选型为什么是 AT89C51 而不是更“高级”的芯片AT89C51 是一颗低电压、高性能的 8 位 CMOS 微处理器片内有 4K 字节的可编程闪速程序存储器擦写能力标称 1000 次以上128×8 位内部数据存储器32 条可编程 I/O 线两个十六位定时器/计数器六个中断源一个可编程串行通道支持闲置和掉电两种低功耗模式全静态工作范围从 0Hz 到 24MHz。这套资源放在今天当然不算什么但对着本设计的任务清单逐条比对它没有一条短板32 个 I/O 拿两个脚去接 DS18B20、拿十一个脚接 1602还剩一大半空闲4K 程序空间装下液晶驱动、两套单总线时序和主循环编译出来通常也就两三个 KB128 字节 RAM 看着少可温度缓冲、字符缓冲加起来不到 20 字节。选它更实际的理由有三个。第一5V 供电、DIP40 直插封装、引脚间距 2.54mm焊在万能板上或者插在实验箱上都不挑工具课设考核时现场排故也方便用万用表逐脚量。第二MCS-51 指令集和输出管脚是工业标准开发环境成熟编译链路上几乎不会卡住人这对第一次接触单总线的同学很关键——你的时间应该花在时序上不是花在搭环境上。第三它在主流仿真软件里的元件模型完整复位、晶振、I/O 电平行为都能真实反映画完原理图能直接加载 hex 文件跑不用先打板再验证逻辑。它的局限也得说清楚免得答辩被追问时答不上来。片内没有硬件 I2C、没有硬件 SPI、没有硬件单总线控制器DS18B20 的全部时序必须靠软件翻转 I/O 口加延时来实现RAM 只有 128 字节放不下大缓冲区采集只能是“读一次、算一次、显一次”的流水式结构它也不能跑任何实时内核只能写前后台的主循环。本设计的任务量小这些局限都撞不到。真要把系统做复杂比如加 SD 卡存储、加串口上传、加多机通信才需要换到带更多外设的型号。提示课程设计里主控选型不是越新越好评分看的是“指标能不能达成、方案能不能自洽”。把选型理由写成资源够用、成本可控、开发链短这三条比堆参数更有说服力。2.2 采集拓扑一口一线还是一线多挂这是本设计里最容易被忽略、又最容易翻车的一个决策。DS18B20 是单总线器件理论上所有传感器可以并联在同一根数据线上靠 64 位激光 ROM 里的 48 位序列号区分身份。听着很美但用起来有两个门槛。第一个门槛是命令层面。总线挂多片时主机不能发跳过 ROM 命令0xCC因为那条命令的意思是“接下来的操作对所有器件生效”。两片同时回应读暂存器命令都会往同一根线上拉电平高电平被低电平拽下去读回来的数据就是两片数据的按位与谁也看不懂。正确做法是先发读 ROM 命令0x33把每片的 64 位序列号读出来登记之后每次操作前发匹配 ROM 命令0x55加 64 位序列号点名叫到某一片。这套流程本身不难但它要求主机把序列号存下来还要在每次读写前完整发送 64 位代码量和调试量都翻倍。第二个门槛是电气层面。多片并联时总线电容变大上拉电阻不变的情况下上升沿变缓读时隙那 15μs 的采样窗口就容易被拖垮表现为读出来的温度偶尔跳变或者整字节变成 0xFF。本设计选了另一条路一口一线。P1.7 接第一片 DS18B20 的 DQP1.6 接第二片两片各自独占一根数据线主控对每一片的操作都是“总线上只有我一个”的简单情况跳过 ROM 命令可以放心使用时序也不受另一片影响。对比项一口一线本设计一线多挂占用 I/O每片一个两片占 2 个全部共用 1 个命令复杂度跳过 ROM 即可需读 ROM、匹配 ROM代码量一套时序复制两份一套时序加序列号管理总线电容影响几乎无随挂载数量增加扩展上限受 I/O 数量限制理论上一根线可挂很多片代码上的代价只是把 Init、Write、Read 三个函数按通道号分支多写几个 if。对课设这种两点规模一口一线是性价比最高的选择如果题目要求“一根总线挂 8 片”那就必须走 ROM 匹配路线那时候再补序列号读取流程。2.3 原理框图与信号流向把上面两块拼起来整机的信号流是这么走的两片 DS18B20 各自把现场温度转换成 12 位数字量存在自己的高速暂存存储器第 0、1 字节里AT89C51 通过 P1.7、P1.6 两根线按单总线协议先复位、再发跳过 ROM、发温度转换命令等转换完成后再复位、跳过 ROM、发读暂存器命令把两个字节读回片内 RAM主控把这 16 位补码按 0.0625℃ 的权重拆成整数部分和小数部分再转成 ASCII 字符最后通过 P0 口的 8 位数据总线和 P2.0、P2.1、P2.2 三根控制线把字符写进 1602 液晶的显示缓冲区。晶振和复位电路给主控提供 12MHz 时钟和上电复位信号5V 电源同时供给主控、液晶和两片传感器。框图里看不出但要提前想好的是节拍。液晶能显示 2 行 16 列两片传感器正好一行一个但题目要求“两秒间隔循环显示”也就是同一时刻屏幕上只有一路温度在动。这里有两种做法一是每两秒切换一次显示内容第一秒显示第一路、第二秒显示第二路二是两行都在但轮流刷新哪一路更新时闪一下。课程设计里第一种更好写也更好验收用定时器 0 做 2 秒基准中断里置标志位主循环检测到标志就切换当前通道并重画屏幕。2.4 指标怎么落到具体参数上课程设计最容易丢分的地方是任务书上的指标和自己的实现对不上。任务书说“测温范围 -30℃ 到 99℃”代码里却直接用 unsigned char 存温度一遇到零下就变成两百多说“显示精度 0.1℃”屏幕上却只打了个整数。所以参数必须在设计阶段就换算成代码里的具体形式。指标项设计要求实现方式测温范围-30℃ ~ 99℃温度原始值用 16 位有符号整型存储负温走补码分支分辨率0.0625℃DS18B20 配置寄存器 R0R1112 位转换显示精度0.1℃低 4 位乘 625 再除 1000取一位小数刷新周期2 秒循环定时器 0 产生 2 秒基准主循环轮换通道显示方式1602 液晶 2 行第一行通道 1第二行通道 2 或整屏轮换供电单 5V传感器外部供电液晶 5V主控 5V0.0625℃ 这个分辨率来自 DS18B20 的 12 位模式温度寄存器共 16 位其中低 4 位是小数位每一位权重 2⁻⁴ 也就是 0.0625。显示到 0.1℃ 意味着要在这个基础上做一次舍入具体算法在软件章节展开。这里先记住一句话分辨率是传感器给的显示精度是你算的两者不是一回事答辩时经常被追问这个区别。3. 硬件设计最小系统、传感器接口与液晶驱动的落地细节原理图这一块纸质方案里往往是几张图一贴就过去了但真正动手连的时候问题全在“这根线为什么必须接”“那个电阻为什么是这个值”上。这一章按模块拆开讲每个模块都给到可直接照抄的引脚级细节。3.1 最小系统12MHz 晶振、22pF 负载电容、RC 复位最小系统只有三块时钟、复位、电源。时钟用 12MHz 石英晶振接在 XTAL119 脚和 XTAL218 脚之间两端各挂一只 22pF 瓷片电容到地。选 12MHz 不是随手写的51 系列在 12 分频下一个机器周期正好 1μs单总线那些 15μs、480μs 的延时可以直接按“循环几次约等于几微秒”来估调试时脑子里有一把尺子换成 11.0592MHz 虽然串口波特率更整但机器周期是 1.085μs所有软件延时都要重算对课设这种靠延时撑时序的场景反而不友好。两只 22pF 是晶振的负载电容取值要和晶振规格匹配画图时随便写个 30pF 也能跑但频率会有偏差属于能省则省、不该省的地方。复位电路用经典的上电复位加按键复位RST9 脚一路经 30μF 电解电容接 5V另一路经 1k 电阻接地电容两端并一个复位按键到 5V。上电瞬间电容未充电RST 呈高电平随着电容通过 1k 电阻充电RST 电压下降高电平持续时间由 RC 时间常数决定30μF×1k 约 30ms远大于 51 要求的两个机器周期复位可靠。按键按下时 RST 直接拉高用于手动重启。EA 引脚31 脚必须接 5V。这一脚叫外部访问允许接高电平表示从片内 4K Flash 取指令接低电平就从外部存储器取——很多人画图时忘了接仿真里表现为程序完全不跑或者跑飞到一个乱七八糟的地址。这个坑后面还会提一次。3.2 DS18B20 接口外部供电还是寄生供电上拉电阻怎么放DS18B20 只有三个引脚1 脚 GND 接地2 脚 DQ 是数字信号输入/输出3 脚 VCC 接电源。它支持两种供电方式。外部供电时 VCC 接 5VDQ 通过一只上拉电阻接 5V器件内部电路由 VCC 供电总线只在通信瞬间被拉低工作最稳。寄生供电时 VCC 直接接地器件从 DQ 线上“偷电”靠总线高电平时给内部电容充电成本省一根线代价是转换期间总线必须被强上拉保持高电平否则转换结果不可靠多片并联时更容易出问题。本设计用外部供电理由很直接板子上 5V 到处都有不差这一根线而寄生供电在温度转换那 750ms 里需要主机把 DQ 强制拉高51 的 I/O 口内部上拉很弱撑不住得再加一只 MOSFET 做强的上拉电路反而复杂。外部供电下 DQ 只需一只 4.7k 到 10k 的上拉电阻到 5V作用是总线空闲时把电平拉到高读时隙里主机释放总线后能快速回到高电平。这里有个必须点出来的细节两片传感器各占一根数据线就各需要一只上拉电阻不能两片共用一个。曾经见过把两片的 DQ 都接到同一个 10k 排阻的一路上仿真里勉强能跑一上实物两路数据就互相干扰。另外传感器引线如果超过一米最好用双绞线DQ 和 GND 绞在一起并且在传感器端加一只 0.1μF 去耦电容抑制长线引入的毛刺。3.3 1602 液晶8 位并行接线、P0 口上拉与对比度调节显示模块选的是 LM016L2 行 16 列字符型液晶内部控制器兼容 1602 系列。它有 14 个引脚带背光的 16 个其中 D0~D7 是 8 位数据总线RS 是寄存器选择0 选指令寄存器1 选数据寄存器R/W 是读写选择0 写1 读E 是使能信号下降沿锁存数据。剩下三只是电源 VDD、地 VSS 和对比度调节端 VEE。本设计把 D0~D7 接到单片机的 P0 口32~39 脚RS 接 P2.0R/W 接 P2.1E 接 P2.2。这个接法有个隐藏前提P0 口内部是开漏结构做通用 I/O 输出高电平时必须外接上拉电阻图上那只 10k 排阻9 脚封装1 脚接 5V其余 8 脚分别接 P0.0~P0.7就是干这个的。少了它P0 输出高电平带不动液晶的数据输入端屏幕上会显示出一堆莫名其妙的字符。VEE 端接一只 10k 电位器的中间抽头电位器两端分别接 5V 和地通过调分压来改变液晶的对比度。这个调节不是可选项很多“屏幕全黑”或“屏幕全白什么都没有”的现象就是对比度拧到了极端。调试时的经验做法是先上电拧电位器看到第一行出现一排黑色方块说明液晶本身活了再往下查字符内容。R/W 线本设计保留了读功能因为初始化后要读忙标志位确认液晶内部控制器空闲了再写下一个字节。如果为了省一根线把 R/W 直接接地只写模式就必须在每个写操作后加足够长的软件延时替代忙检测延时给保守一点通常 2ms 以上。两种做法都能通但保留读忙标志的版本更稳也更容易通过答辩时的提问。3.4 总体连接清单与仿真元件对照把三块拼成一张总图需要连的线其实不多但每一根都要能说出理由。下面这张表把关键连接点列全画图时可以直接对着勾。网络连接关系说明VCC / GND主控 40 脚、20 脚40 脚接 5V20 脚接地不可反接XTAL1 / XTAL218、19 脚接 12MHz 晶振晶振两端各 22pF 到地RST9 脚接 30μF 电容到 5V、1k 电阻到地并复位按键EA31 脚接 5V使用片内程序存储器P1.7 / P1.6分别接两片 DS18B20 的 DQ各配 4.7k 上拉电阻P0.0~P0.7接 LCD 的 D0~D7P0 口需 10k 排阻上拉P2.0 / P2.1 / P2.2接 LCD 的 RS / R/W / E控制线顺序不可混LCD VEE接 10k 电位器中间抽头调对比度传感器 VCC / GND3 脚接 5V1 脚接地外部供电方式在仿真软件里建工程时元件库中对应的名称分别是单片机搜 AT89C51液晶搜 LM016L温度传感器搜 DS18B20晶振搜 CRYSTAL电阻搜 RES电解电容搜 CAP-ELEC瓷片电容搜 CAP排阻搜 RESPACK-8。画完连线后双击单片机把生成的 hex 文件路径填进 Program File 一栏时钟频率填 12MHz就能开始跑。双击 DS18B20 可以手动设定它模拟的环境温度这是验证负温和高温分支最方便的手段。4. 软件设计主循环、单总线时序与定点小数换算硬件定了骨架软件才是让这套系统真正跑起来的部分。整个程序按子程序划分液晶初始化、液晶写命令、液晶写数据、液晶定位、DS18B20 复位、写一个字节、读一个字节、启动转换、读温度、温度转字符、主循环。这么拆不是为了好看是因为单总线时序一旦和显示逻辑混在同一个函数里改一个延时就会牵连另一处排故时根本无从下手。4.1 主程序框架开机画面、两秒节拍与通道轮换主循环的节拍由定时器 0 提供。12MHz 下机器周期 1μs定时器 16 位模式最大计数值 65536单次最多 65.5ms所以按 50ms 中断一次中断服务程序里累加计数满 40 次就是 2 秒。这个结构的好处是主循环不用写长延时节拍由硬件保证显示切换的节奏稳定不会因为某一路传感器读得慢而整体漂移。主程序流程是上电先做液晶初始化屏幕清空显示一行开机字符比如系统名和版本延时 2 秒让评审看清然后进入主循环检测 2 秒标志位标志到了就启动两片传感器同时转换等待转换完成读回两路温度切换当前显示的通道把对应温度写到液晶上。这里“同时启动转换”是个值得说的小设计如果先让第一片转换再等 750ms 读再让第二片转换再等 750ms两路数据在时间上差了将近一秒测同一个温区时读数不一致先给两片都发转换命令一起等 750ms再分别读两路数据就是同一时刻的快照。#include reg51.h #include intrins.h #define uint unsigned int #define uchar unsigned char sbit LcdRs P2^0; sbit LcdRw P2^1; sbit LcdEn P2^2; sbit DQ1 P1^7; /* 第一片 DS18B20 数据线 */ sbit DQ2 P1^6; /* 第二片 DS18B20 数据线 */ uchar tick50ms 0; /* 50ms 中断计数 */ bit flag2s 0; /* 2 秒到标志 */ uchar ch 1; /* 当前显示通道 */ void Timer0_Init(void) { TMOD 0xF0; TMOD | 0x01; /* 定时器0模式116位 */ TH0 (65536 - 50000) / 256; /* 50ms 12MHz */ TL0 (65536 - 50000) % 256; ET0 1; EA 1; TR0 1; } void Timer0_ISR(void) interrupt 1 { TH0 (65536 - 50000) / 256; TL0 (65536 - 50000) % 256; if (tick50ms 40) { /* 40 × 50ms 2s */ tick50ms 0; flag2s 1; } }这段代码里TMOD 0xF0先清掉定时器 0 的低 4 位再赋值避免影响定时器 1 的配置重装值按 50ms 算是 65536 减去 50000 个机器周期interrupt 1是定时器 0 的中断号这个号在 51 里是固定的写错了编译能过但永远不进中断。标志位用bit类型而不是uchar是因为bit在位寻址区置位和清零都是单条指令中断里改、主循环里读不会出现读到一半被改写的情况。4.2 单总线三条时序复位、写一位、读一位DS18B20 的全部通信建立在三种基本时隙上这三种时隙对时间的要求是微秒级的也是整个设计里唯一不能用“大概差不多”糊弄过去的地方。复位时隙主机把 DQ 拉低至少 480μs然后释放总线由上拉电阻拉高。DS18B20 检测到上升沿后等待 15~60μs把总线拉低 60~240μs 作为应答。主机在释放总线后约 70μs 采样读到低电平说明器件在线读到高电平说明没接上或者坏了。写时隙每个写时隙至少 60μs相邻写时隙之间至少 1μs 恢复。写“1”时主机拉低总线 1~15μs 后释放写“0”时拉低至少 60μs。器件在主机拉低后的 15~60μs 窗口内采样。读时隙主机拉低总线至少 1μs 后释放然后在拉低之后的 15μs 内采样总线电平读到高就是 1低就是 0。整个读时隙不小于 60μs两次读之间至少 1μs 恢复。/* 12MHz 下的粗略微秒延时实际值需按编译结果微调 */ void delay_us(uchar n) { while (n--) { _nop_(); _nop_(); _nop_(); _nop_(); } } /* 通道选择ch1 用 P1.7ch2 用 P1.6 */ void dq_low (uchar c) { if (c 1) DQ1 0; else DQ2 0; } void dq_high(uchar c) { if (c 1) DQ1 1; else DQ2 1; } uchar dq_val(uchar c) { return (c 1) ? DQ1 : DQ2; } /* 复位返回 1 表示器件应答0 表示无应答 */ uchar ds_reset(uchar c) { uchar ack; dq_low(c); delay_us(480); /* 拉低 ≥480us */ dq_high(c); delay_us(70); /* 等器件应答窗口 */ ack !dq_val(c); /* 读到低电平说明有应答 */ delay_us(410); /* 补足复位周期剩余时间 */ return ack; } /* 写一个字节低位先出 */ void ds_write(uchar c, uchar dat) { uchar i; for (i 0; i 8; i) { dq_low(c); if (dat 0x01) { delay_us(2); /* 写 1短低脉冲 */ dq_high(c); delay_us(60); } else { delay_us(60); /* 写 0长低脉冲 */ dq_high(c); delay_us(2); } dat 1; } } /* 读一个字节低位先出 */ uchar ds_read(uchar c) { uchar i, dat 0; for (i 0; i 8; i) { dat 1; dq_low(c); delay_us(2); dq_high(c); delay_us(12); /* 15us 内采样 */ if (dq_val(c)) dat | 0x80; delay_us(50); /* 补足 60us 时隙 */ } return dat; }这四段延时参数是按 12MHz、机器周期 1μs 估的delay_us里每个_nop_占一个机器周期加上循环本身的判断和跳转实际会比 n 略大所以取值时宁可偏长不要偏短。偏长了通信变慢但不会出错偏短了器件采样不到脉冲读回来就是全 1。如果手边有示波器最好的做法是把 DQ 接到示波器上抓一次复位波形量出低电平实际有多宽再回来改延时参数这比反复试代码快得多。还有一点容易被忽略ds_read里第一次拉低后只延时 2μs 就释放这个“短脉冲”要足够短保证落在器件要求的 1~15μs 窗口内。如果写成先延时 15μs 再释放读时隙就从“主机拉低期间器件就开始输出”变成了“主机已经采样完器件才开始输出”读回来永远是 1。4.3 温度寄存器解析整数、小数与负数补码温度转换完成后读暂存器命令会吐出 9 个字节前两个字节就是温度值低位在前、高位在后。16 位里的低 4 位是小数中间 7 位是整数高 5 位是符号位正数全 0负数全 1。12 位模式下实际温度 原始值 × 0.0625。直接做浮点乘法在 51 上代价很高会拖进来一大段浮点库占用宝贵的 4K 空间也没必要。工程上的做法是把 0.0625 拆成整数运算小数部分只有 4 位取值范围 0~15把低 4 位记为 t温度的小数部分是 t×0.0625要显示到 0.1℃就把它换算成 0.1℃ 为单位的整数即 t×625÷1000结果是 0~9正好是小数点后第一位。t15 时得 9表示 0.9℃和 15×0.06250.9375 四舍五入到一位小数的结果一致。负温要单独处理。高 5 位全 1 代表负数此时原始值是补码先取反加一变成原码再按正数的方式拆整数和小数显示时前面加一个负号。/* 读一片 DS18B20返回“0.1℃”为单位的整数如 -125 表示 -12.5℃ */ int ds_read_temp01(uchar c) { uchar lo, hi; uint raw; int t_int, t_frac, result; bit neg 0; ds_reset(c); ds_write(c, 0xCC); /* 跳过 ROM该通道只有一片 */ ds_write(c, 0x44); /* 启动温度转换 */ delay_us(600); /* 12 位分辨率最大转换时间 750ms */ delay_us(200); ds_reset(c); ds_write(c, 0xCC); ds_write(c, 0xBE); /* 读暂存寄存器 */ lo ds_read(c); hi ds_read(c); raw ((uint)hi 8) | lo; if (raw 0xF800) { /* 高 5 位非 0负数 */ neg 1; raw (~raw) 1; /* 补码转原码 */ } t_int raw 4; /* 整数部分 */ t_frac ((raw 0x0F) * 625) / 1000; /* 小数第一位0~9 */ result t_int * 10 t_frac; if (neg) result -result; return result; }raw 0xF800用掩码一次判完高 5 位比逐位判断简洁(~raw) 1是标准的补码取负过程注意 raw 声明成uint取反不会有意外的符号扩展整数和小数分开算再合并成“0.1℃ 单位”的整数全程不碰浮点编译出来的代码不到一百字节。返回值的整数形式还有个好处负号、整数位、小数点、小数位都可以用除法取余拆开转字符非常方便。/* 把 -125 这样的整数拆成 “-12.5C” 形式的显示字符串 */ void temp_to_str(int t01, uchar *buf) { uchar i 0; int v t01; if (v 0) { buf[i] -; v -v; } buf[i] (v / 100) ? (v / 100 0) : ; /* 百位无则填空格 */ buf[i] (v / 100) ? ((v % 100) / 10 0): (v / 10 0); buf[i] .; buf[i] v % 10 0; buf[i] 0xDF; /* 液晶字符发生器中“度”的符号 */ buf[i] C; buf[i] \0; }数字转字符的核心就一句数字加字符0的编码值。液晶只认 ASCII直接送一个 0~9 的数值过去会显示成控制字符或者乱码这个坑几乎每个第一次用 1602 的人都踩过。另外 1602 内部字符表里没有标准 ASCII 的“℃”但有一个自定义的度的符号编码 0xDF用它拼出“25.3°C”的显示效果比写“25.3C”更像成品。4.4 1602 驱动与循环显示液晶驱动分四步初始化、写命令、写数据、定位。初始化的顺序不能乱标准流程是写 0x388 位数据端口、2 行显示、5×7 点阵连写三次并各延时 5ms这是为了兼容不同厂家的控制器上电状态不确定的问题然后写 0x0C 开显示、关光标写 0x01 清屏写 0x06 设置输入模式为地址递增、画面不动。写命令和写数据的区别只在 RS 脚RS0 时数据端口上的是命令RS1 时是数据。两者都要保证 R/W0写、E 端产生一个高脉冲先拉高再拉低并且在每次操作后等待液晶内部完成。忙标志的读法是把 RS 置 0、R/W 置 1、E 置 1读 P0 口最高位为 1 表示内部正忙需要循环等待。#define LCD_CMD 0 #define LCD_DATA 1 void lcd_wait(void) { uchar cnt 0; P0 0xFF; /* 读之前先置高P0 是准双向口 */ LcdRs 0; LcdRw 1; LcdEn 1; while ((P0 0x80) (cnt 200)); /* 等忙标志清零带超时 */ LcdEn 0; } void lcd_write(bit style, uchar dat) { lcd_wait(); LcdRs style; LcdRw 0; P0 dat; LcdEn 1; _nop_(); _nop_(); LcdEn 0; /* 下降沿锁存 */ } void lcd_init(void) { lcd_write(LCD_CMD, 0x38); delay_ms(5); lcd_write(LCD_CMD, 0x38); delay_ms(5); lcd_write(LCD_CMD, 0x38); delay_ms(5); lcd_write(LCD_CMD, 0x0C); delay_ms(5); /* 开显示无光标 */ lcd_write(LCD_CMD, 0x01); delay_ms(5); /* 清屏 */ lcd_write(LCD_CMD, 0x06); delay_ms(5); /* 地址递增画面不动 */ } void lcd_gotoxy(uchar x, uchar y) { lcd_write(LCD_CMD, (y 0) ? (0x80 | x) : (0x80 | (x 0x40))); } void lcd_puts(uchar *s) { while (*s) { lcd_write(LCD_DATA, *s); } }lcd_gotoxy里那个0x40是 1602 的行偏移第一行显示缓冲区起始地址是 0x00第二行是 0x40写地址时加上指令标志位 0x80。这个偏移量写错字符会跑到屏幕外面去现象是“程序没报错屏幕就是不显示”。主循环里把前面几块串起来就成形了等 2 秒标志两片同时启动转换等转换完成分别读回温度转成字符串按当前通道刷到液晶对应行然后切换通道。屏幕布局有两种可选一是两行同时显示两路温度稳定性更好评审一眼看到全部数据二是只显示当前通道符合“循环显示”的字面要求。课设里建议做成两行常显加轮换高亮既有循环动作又不会让评审觉得信息量太少。5. 避坑与排查单总线温度采集最容易翻车的五个点这套电路的元件加起来不到二十个逻辑也不复杂真正让人卡住半天的地方集中在时序、电平、初始化顺序这几处。下面五条是按发生频率排的每条都按现象、原因、解决的顺序写遇到问题时可以从上往下对。5.1 上电第一屏永远是 85.0℃现象程序烧进去液晶亮起来第一行稳定显示 85.0℃过一会儿才变成正常室温或者一直卡在 85.0℃ 不动。原因85℃ 是 DS18B20 上电复位后温度寄存器的默认值对应十六进制 0x0550。它出现在屏幕上说明主机读到了数据但读到的是器件还没完成一次真实转换时的出厂缺省值。常见有两条路径一是发完 0x44 转换命令后等待时间不够就发 0xBE 去读12 位分辨率最大转换时间 750ms只等几十毫秒必然读到旧值二是根本没发 0x44直接读了暂存器读到的就是上电默认值。解决把转换后的等待时间补足到 750ms 以上宁可多等也不要少等。如果系统要求快速响应可以把配置寄存器的 R0、R1 改成 10 位或 9 位分辨率转换时间分别降到 375ms 和 93.75ms代价是分辨率降到 0.25℃ 或 0.5℃这时 0.1℃ 的显示精度就名不副实了指标对不上答辩会被问住。所以课设里还是老老实实保持 12 位、等满 750ms。5.2 两片读数互相串一路降温另一路跟着变现象手捏第一片传感器第一路温度上升第二路也跟着往上跳或者两片读数完全相同。原因最常见的是两片 DQ 接到了同一个 I/O 口代码里又用了跳过 ROM 命令。跳过 ROM 的语义是“后面这条命令对所有在线器件生效”两片同时收到读暂存器命令就同时往总线上送数据高电平被低电平拉下去读回来的是两路数据按位与的结果看上去就是“两路一样”或者“一路跟着另一路变”。另一种情况是两片各有各的 I/O 口但代码里通道参数传错读第一路时实际操作的却是第二路的引脚。解决先确认硬件上是真的一口一线两个 DQ 各接各的引脚、各配上拉电阻再检查读写函数里的通道号ds_read_temp01(1)和ds_read_temp01(2)有没有在后面被复制粘贴后忘了改。如果确实需要一根总线挂多片就必须走读 ROM 加匹配 ROM 的流程把每片的 64 位序列号先读出来存好。5.3 读数偶尔跳变或者整字节读回 0xFF现象大部分时候正常偶尔跳出一个明显不合理的值比如 -55℃ 或 125℃下一次刷新又正常了。原因时序边缘。读时隙的采样点卡在 15μs 的边界上主机程序的延时稍有偏差采样时就落在器件还没开始输出或者已经输出结束的时刻读回全 1拼出来就是 0xFFFF也就是 -0.0625℃或者被当成无效数据。另一个来源是总线上的干扰传感器引线较长又没做双绞旁边有继电器或电机动作时DQ 上会耦合进毛刺。解决把读时隙的采样点往前提拉低后延时 2μs 就释放、再等 12μs 采样确保落在窗口中间写时隙的恢复时间从 1μs 加到 2μs 以上。硬件上把上拉电阻从 10k 降到 4.7k提高上升速度引线超过一米时加双绞和去耦电容。软件上还可以加一层数据合理性判断读回的温度如果超出 -30℃ 到 99℃ 的范围就丢弃保留上一次的有效值避免屏幕上闪出离谱数字。5.4 液晶上电全黑或者全白一个字符都没有现象电路上电液晶背光如果有亮着但屏幕上要么一整片黑块要么干干净净什么都没有程序在跑但屏幕不响应。原因按可能性从高到低排。对比度端 VEE 悬空或调到极端液晶的透光率被拉到全黑或全白P0 口没接上拉排阻写进去的数据高电平根本推不上去初始化序列里 0x38 只写了一次控制器上电状态不明后续命令全被当成无效指令E 端脉冲宽度不够或者极性搞反数据没被锁存R/W 接反写操作实际变成了读总线上全是高阻。解决先拧电位器看能不能拧出一行黑块能拧出来说明液晶本体和供电没问题再量 P0 口写数据时的实际电平如果只有 1V 左右就是缺上拉然后抓 E 端的波形确认是“低—高—低”的脉冲而不是一直高或一直低最后把初始化序列从头对着写一遍0x38 写三次这个细节不要省。5.5 仿真跑得通焊到板子上就不工作现象仿真里温度正常显示、循环也正常照图焊出来的实物通电后屏幕不亮或者一直显示 85℃。原因仿真软件对时序的容忍度比实物宽得多延时短一点、上拉弱一点仿真里照样跑实物就不行。具体的实物差异有晶振的实际频率偏差导致软件延时整体偏短万能板走线的分布电容比仿真理想线大电池或者 USB 供电的实际电压不到 5V液晶对比度整体偏移焊点虚焊尤其是 DS18B20 那三个细引脚。解决先量电源确认板子上每个芯片的 VCC 脚都是 4.8V 以上再量晶振两端有没有起振用示波器看 XTAL2 上有没有 12MHz 正弦波然后用示波器抓 DQ 上的复位波形量低电平宽度是不是真的超过 480μs不够就把延时参数整体加长最后逐个补焊传感器引脚特别是 GND。这套流程走下来九成的实物问题都能定位。6. 验收与答辩怎么证明这套系统真的跑通了课设最后交的不是一堆元件是“能证明它work”的一组证据。评审不会盯着你的代码逐行看他们看的是屏幕上有没有正确的数字、数字会不会随环境变化、边界条件顶不顶得住、你讲不讲得清为什么这么设计。所以验收要提前设计测试用例把系统往极限上推。6.1 四组必做的仿真测试在仿真软件里双击 DS18B20 可以手动设定温度这给测试提供了极大的方便。下面四组用例基本能覆盖所有分支建议按顺序做每做一组截一张图存进报告。用例操作预期现象验证的分支常温对照两片分别设 25℃ 和 26℃屏幕显示 25.0℃ 与 26.0℃基本采集与字符转换负温边界第一片设 -30℃第二片设 -10℃显示 -30.0℃ 与 -10.0℃补码转原码、负号处理高温边界第一片设 99℃第二片设 125℃显示 99.0℃第二路超范围被丢弃量程判断小数分辨设 25.0625℃ 与 25.9375℃分别显示 25.0℃ 与 25.9℃低 4 位换算与舍入第三组用例是很多人会漏的DS18B20 本身能测到 125℃但本设计的显示范围定在 -30℃ 到 99℃超出范围时程序该怎么处理必须有明确行为不能显示出乱码或者三位数把屏幕挤爆。我一般会在温度转换函数后面加一道范围判断超限时显示固定字符串“OUT”或者保留上一次有效值并在报告里写明这个处理策略——这比装作没有边界问题更能体现工程意识。6.2 答辩时最容易被追问的三个问题第一个问题通常是“为什么用两个 I/O 口而不是一根总线挂两片”。回答的落点是跳过 ROM 命令在多片共线时会造成总线冲突要挂多片必须实现读 ROM 和匹配 ROM 的完整流程本设计的两点规模用一口一线更简洁可靠同时留了扩展路径——真要扩到八点可以改用一根总线加序列号管理代码框架不需要推倒重来。第二个问题是“0.0625℃ 的分辨率为什么只显示 0.1℃”。这是分辨率和显示精度两个概念传感器能分辨 0.0625 的变化但液晶一行 16 字符、人眼读数习惯和系统噪声都不支持显示四位小数所以显示层做一次舍入到 0.1℃内部计算仍然保留完整精度避免多次舍入累积误差。第三个问题是“如果传感器断线了会怎样”。这时候要能说清楚复位时隙收不到应答ds_reset返回 0程序应当识别这个返回值并显示“ERR”之类的提示而不是继续往下读、读回一堆 0xFF 当成 -0.0625℃ 显示出来。这一个细节往往就是“及格”和“良好”的分界。从那以后我每次带人做这类单总线项目都会强制走一遍“示波器看波形 → 边界温度测试 → 断线测试”这三步哪怕仿真里一切正常也不跳过。这套流程花不了半小时但能挡掉答辩现场被随手拔一根线就露馅的尴尬。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

用MCIWnd四十行代码实现Win32 AVI播放器
用MCIWnd四十行代码实现Win32 AVI播放器

简介:这是一份基于 MCIWnd 的 AVI 视频播放器示例工程,面向正在学习 MFC 多媒体编程、需要理解 MCIWnd 控件用法的开发者。工程实现通过“文件→打开”选择 AVI 文件,在客户区左上角创建 MCIWnd 窗口并显示首帧画面,点击控制条播放… · 2026/11/5 7:16:38

AD封装库全流程:原理图库、PCB库与3D库管理避坑
AD封装库全流程:原理图库、PCB库与3D库管理避坑

简介:面向Altium Designer用户的元器件库合集,覆盖原理图绘制到PCB布局布线的常见需求,适合刚入门AD、需要快速补齐基础库的电子工程师与在校学生,也便于有经验的设计者减少重复建库。压缩包共117个文件,约464.27MB&am… · 2026/11/5 7:16:38

MySQL存储过程实战指南:性能优化与安全实践
MySQL存储过程实战指南:性能优化与安全实践

1. MySQL存储过程全面解析作为一名长期与MySQL打交道的数据库工程师,我深刻体会到存储过程在实际项目中的价值。今天我将系统性地分享MySQL存储过程的完整知识体系,包含大量教科书上不会提及的实战经验。存储过程本质上是一组预编译的SQL语句集合&#x… · 2026/11/5 7:16:38

【亲测免费】 Distil-Whisper: distil-large-v2的安装与使用教程
【亲测免费】 Distil-Whisper: distil-large-v2的安装与使用教程

Distil-Whisper: distil-large-v2的安装与使用教程 【免费下载链接】distil-large-v2 项目地址: https://ai.gitcode.com/hf_mirrors/distil-whisper/distil-large-v2 引言 随着语音识别技术在各个领域的广泛应用,高效、准确的语音识别模型成为了研究人员和… · 2026/11/5 9:46:26

10款开源Android游戏完整指南:从离线解谜到Roguelike地牢,按上手成本一次选齐
10款开源Android游戏完整指南:从离线解谜到Roguelike地牢,按上手成本一次选齐

10款开源Android游戏完整指南:从离线解谜到Roguelike地牢,按上手成本一次选齐 【免费下载链接】open-source-android-apps Open-Source Android Apps 项目地址: https://gitcode.com/gh_mirrors/op/open-source-android-apps 本清单收录10款可装进… · 2026/11/5 9:46:26

【亲测免费】 CodiumAI PR-Agent:重塑代码审查的未来
【亲测免费】 CodiumAI PR-Agent:重塑代码审查的未来

CodiumAI PR-Agent:重塑代码审查的未来 【免费下载链接】pr-agent 🚀 PR Agent: The Original Open-Source PR Reviewer. This project is not the Qodo free tier. 项目地址: https://gitcode.com/GitHub_Trending/pr/pr-agent 随着软件开发日新… · 2026/11/5 9:45:25

UART接口24位ADC在工业温度采集中的工程实践
UART接口24位ADC在工业温度采集中的工程实践

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

ADS122U04IPWR+TM4C129ENCPDT工业温度采集系统实战
ADS122U04IPWR+TM4C129ENCPDT工业温度采集系统实战

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

UART接口的24位ADC:用PIC18F46K22实现多路PT100测温
UART接口的24位ADC:用PIC18F46K22实现多路PT100测温

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

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

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

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

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

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

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

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

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

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

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

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

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

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码