尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STC89C52RC驱动DS18B20温度传感器数码管显示实战解析

STC89C52RC驱动DS18B20温度传感器数码管显示实战解析 简介本资源是一套面向单片机初学者与课程设计学生的完整嵌入式实践项目基于STC89C52RC单片机实现DS18B20数字温度采集与四位数码管实时显示功能覆盖硬件驱动、单总线通信、动态扫描显示及KEIL C51工程构建等核心技能点。压缩包共26个文件包含3个核心C源文件main.c、18b20.c、delay.c、2个头文件18b20.h、delay.h、1个KEIL工程文件.uvproj、1个PDF开发板原理图、1个可直接烧录的.hex文件以及编译生成的.obj、.lst、.m51等辅助文件完整呈现从代码编写、编译调试到硬件验证的全流程包体仅635KB结构清晰、即开即用。已有342人学习下载适合单片机原理课设、电子实训或自学进阶使用——读者可快速理解DS18B20单线协议时序实现、数码管段码/位码控制逻辑并通过原理图反向梳理IO口分配与外围电路连接关系显著提升软硬协同开发能力。 前两天整理移动硬盘翻出一个很老的压缩包名字是“STC89C52RC单片机DS18B20 温度传感器 数码管显示 软件源码KEIL C51工程文件开发板PDF原理图.zip”。这种资料包在单片机学习圈里几乎人手一份问题也几乎一样烧进去之后温度永远显示85℃或者数码管乱跳甚至屏幕完全不亮。很多人折腾两三天没结果就把锅甩给“资料是坏的”。其实大部分情况下工程包是好的只是你还没搞清楚STC89C52RC、DS18B20和数码管这三样东西是怎么配合的。这篇文章就是我基于这类工程包从复现到改造的完整记录适合正在学51单片机、想用DS18B20做温度采集显示或者手里有类似源码但没跑通的朋友。我会把KEIL C51工程怎么打开、DS18B20时序怎么理解、数码管扫描怎么写、原理图怎么对照以及调试时怎么一步步定位问题全部讲清楚。1. 工程包到手之后先看什么文件构成、编译器版本和烧录前的核对清单1.1 压缩包里通常有哪些文件这类工程包解压后一般不会只有一个孤零零的文件而是会有一堆看起来杂乱无章的内容。以我手里这份为例解压后常见的是这几类.uvproj或.uvprojxKEIL 的工程文件双击可以直接打开。如果是老版本项目可能是.uv2。.c和.h源码文件核心的驱动代码例如main.c、ds18b20.c、delay.c、smg.c数码管。.hex编译好的烧录文件如果不想重新编译可以直接用 STC-ISP 烧录。PDF 原理图开发板的完整硬件连接图这个是排查问题时的“宪法”。可能还有运行说明文档、Proteus 仿真文件、取模软件截图等。很多人下载后直接双击.uvproj然后发现 KEIL 报错或者打开后显示一堆乱码、找不到源文件就开始怀疑资料有问题。实际上很可能是编译器版本和工程不匹配。1.2 KEIL C51 工程和 MDK 工程的区别这里必须先说清楚一个新手最容易踩的坑STC89C52RC 是 51 单片机内核是 8051必须使用 KEIL C51 编译器而不是 KEIL MDK也就是现在通常说的 KEIL 5 的 MDK-ARM 版本。如果你电脑里只装了 KEIL MDK直接打开.uvproj大概率会提示“没有匹配的编译器”或者编译报出一大堆跟 ARM 有关的错误。正确做法是安装 KEIL C51 版本旧一点的像 C51V9.54、C51V9.60 都可以。打开工程后进入Project - Options for Target - Device确认芯片型号选择为 STC89C52RC 或者 AT89C52。如果没有 STC 选项就用 STC-ISP 软件内置的器件库导入或者直接选 AT89C52两者寄存器完全兼容时序也一样。在Output选项卡里勾选Create HEX File这样编译之后才能生成.hex文件。如果工程文件被加密或者损坏最简单的方法是自己重新新建一个空工程然后把源码文件添加进去重新写启动配置。51 单片机不比 Cortex-M 复杂新建工程花不了几分钟。1.3 烧录前的核对清单很多工程包作者用的开发板和你手里的板子不一定一样。烧录之前先花两分钟核对下面这几点系统时钟代码里的延时函数是基于多少 MHz 晶振写的常见 11.0592MHz 和 12MHz。STC89C52RC 板子上通常配 11.0592MHz但也有不少板子用 12MHz。如果代码时钟参数和实际晶振不一致DS18B20 时序就会出问题。DS18B20 接在哪个引脚代码里可能定义sbit DQ P3^2;你的板子上 DS18B20 插针是否真的连到了 P3.2数码管类型共阴还是共阳段选、位选分别接在哪个 IO有没有锁存器DQ 上拉电阻DS18B20 的数据线必须接 4.7k 上拉到 VCC很多学习板预留了孔位但没焊。烧录软件STC-ISP 里选择芯片型号为 STC89C52RC串口号正确频率选择尽量和开发板一致否则串口下载可能失败。我见过太多人“先烧一下试试”结果卡在串口识别上然后又去折腾驱动其实这些都是小事。真正麻烦的是程序能跑但温度不正常这时候才需要进入下一层去理解 DS18B20 的时序。2. DS18B20 三段时序逐条拆初始化、写位、读位的边界条件2.1 单总线器件为什么难调DS18B20 是 DALLAS现在归 Maxim出的单总线数字温度传感器所谓单总线就是数据和控制都通过一根 DQ 线来传输。主机既可以给这根线灌高低电平去控制传感器又可以释放总线去读取传感器拉低的电平。这种设计省 IO但代价就是时序要求非常严格所有操作都是一条一条的微小时间窗口。很多工程包的源码里一眼看过去就是几个 delay 函数和 DQ 引脚操作缺少注释。如果直接复制到别的板子上晶振不同、延时精度不同温度就会变成乱码或者固定值。所以读懂时序比背代码重要得多。2.2 初始化时序拉低至少 480us然后释放等存在脉冲DS18B20 每一次通信前都要先复位。复位时序大概是这样主机把 DQ 拉低持续 480us 到 960us。注意这个时间宁可长一点不要短于 480us。主机释放总线DQ 1然后等待 15us 到 60us。DS18B20 检测到总线上的上升沿后会等待一会然后主动把 DQ 拉低 60us 到 240us作为“存在脉冲”告诉主机我在这里。主机读取这个低电平确认传感器在线。一个常见的复位函数可以这样写sbit DQ P3^2; unsigned char ds18b20_reset(void) { unsigned char presence; DQ 0; // 主机拉低总线 delay_us(500); // 至少 480us DQ 1; // 释放总线 delay_us(60); // 等待 15~60us presence DQ; // 读取存在脉冲 delay_us(400); // 等待剩余复位时间结束 return presence; // 返回 0 表示传感器在位 }这里的delay_us(500)在实际 12MHz 晶振、12T 模式下可能实际延时不是 500us而是更长。后面我会专门说延时精度的坑。但如果初始化返回的 presence 是 1高电平说明 DQ 上没有传感器拉低要么传感器没接好要么上拉电阻失效要么时序时间太短。2.3 写时序写 0 和写 1 的区别关键在于释放时机DS18B20 的写时序是把每一个“位”分成一个时间槽slot每个槽至少 60us两个槽之间要有至少 1us 的恢复时间。写 0 和写 1 的区别如下写 1主机拉低总线然后必须在 15us 内释放总线让上拉电阻把总线拉高一直保持到槽结束。写 0主机拉低总线并且在整个 60us 槽内保持低电平不要释放。所以写字节的程序思路就是逐位判断如果是 0 就拉低一整段时间如果是 1 就拉低后马上释放void ds18b20_write_byte(unsigned char dat) { unsigned char i; for (i 0; i 8; i) { DQ 0; _nop_(); // 保证拉低时间 if (dat 0x01) { DQ 1; // 写 1在 15us 内释放 } delay_us(60); // 保持时隙 DQ 1; // 恢复总线 dat 1; } }很多代码里会把if (dat 0x01)改成if (dat 0x80)然后左移只要保证位序正确即可。关键点是写 1 时从拉低到释放之间的时间不能太长如果超过了 15us传感器会认为你在写 0。我在调试中见过不少程序因为用了低效的 delay 函数实际释放时机拖到了 30us 以上导致写入的指令全错。2.4 读时序主机拉低后快速释放在 15us 内采样读时序和写时序几乎对称。主机先拉低总线持续至少 1us然后释放总线之后 DS18B20 会决定把总线拉低或保持高电平分别对应读回 0 和 1。主机必须在释放总线后的 15us 内完成采样否则会读到后面无意义的电平。unsigned char ds18b20_read_byte(void) { unsigned char i, dat 0; for (i 0; i 8; i) { dat 1; DQ 0; _nop_(); // 拉低 1us 以上 DQ 1; // 释放总线 _nop_(); if (DQ) // 在 15us 内采样 { dat | 0x80; } delay_us(60); // 等待时隙结束 } return dat; }读时序最容易犯的错误是采样点太晚。比如在释放总线后延时了 30us 再去读这时候 DS18B20 可能已经把总线拉高或者进入下一个状态读回来的数据就乱了。如果你用示波器观察标准读时序在释放后会产生一个很窄的低电平窗口必须在窗口内采样。2.5 延时函数精度why 不能照搬前面所有时序操作都依赖 delay_us但 C51 里最常见、也最坑的 delay_us 是这样写的void delay_us(unsigned int us) { while (us--); }在 STC89C52RC 的 12T 模式、12MHz 晶振下一个机器周期是 1us。但是while (us--)这个循环本身包含比较、自减、跳转指令每执行一次大约消耗 4 到 5 个机器周期所以这个函数实际延时大约是 4 到 5 倍参数值。如果原作者基于经验设的参数换一个编译器优化等级后时间还会变。更稳妥的做法是直接用 STC-ISP 软件里的“软件延时计算器”让它生成对应频率下的精确延时函数。生成的代码通常长这样void delay_us(unsigned int us) //12.000MHz { unsigned char i; while(us--) { _nop_(); i 10; while (i--); } }不同晶振生成结果不同但至少这套代码是作者实测过的。如果你要复制别人的工程第一步就是把所有延时函数替换成自己开发板频率对应的版本。3. 数码管动态扫描共阴共阳、消影顺序和温度数字拼装3.1 共阴共阳和段码表数码管显示看起来简单但引脚定义搞错会显示成乱码。数码管有共阴和共阳两种共阴就是把所有 LED 的阴极接到公共端共阳就是所有阳极接到公共端。对于单个数码管段选码决定了显示什么数字。常见的共阴段码表如下显示共阴段码共阳段码00x3F0xC010x060xF920x5B0xA430x4F0xB040x660x9950x6D0x9260x7D0x8270x070xF880x7F0x8090x6F0x90负号0x400xBF熄灭0x000xFF如果你的板子是共阳却用了共阴段码那么显示出来的数字会变成“补码”一样的效果比如想显示 0结果显示 8 或者全灭。代码里unsigned char code seg_table[] {0x3F, ...};这种数组必须根据硬件原理图改。3.2 动态扫描原理用视觉暂留骗过人眼任何时刻只能点量一个数码管通过快速轮流点亮不同位利用人眼视觉暂留看起来就像同时亮着。扫描频率至少要 50Hz也就是 20ms 内完成一轮四位数码管的扫描通常每一位点亮 1ms 到 2ms。如果每位的点亮时间太长会看到亮度不均太短则会变暗。最简单的扫描代码void display_scan(unsigned char *buf) // buf[0]~buf[3] 存放段码 { unsigned char i; P0 0x00; // 先消隐 for (i 0; i 4; i) { P0 buf[i]; // 段选数据 P2 (1 i); // 位选假设 P2.0~P2.3 控制位 delay_ms(2); P0 0x00; // 消隐防止鬼影 } }这里有两个关键点。第一位选和段选的配合顺序。通常先送段码再送位选或者先送位选再送段码取决于锁存器电路。但无论顺序如何在切换位选之前一定要先把当前位的段码清零否则会看到前一个数字的残影。第二消隐不是可选项。我见过不少新手的代码没有消隐结果数字边缘拖着一点点虚影虽然不大但看着很别扭。如果在高速扫描下消隐时间太长亮度又会下降。一般消隐就是几条P0 0x00;成本很低。3.3 把 DS18B20 温度值拼成数码管数据DS18B20 返回的是两个字节LSB 和 MSB。12 位分辨率下温度寄存器低 4 位是小数部分有效温度等于temp (MSB 8 | LSB) * 0.0625C51 里不擅长浮点运算更常见的是用整数处理。比如int temp_raw; unsigned char int_part; unsigned char dec_part; temp_raw (MSB 8) | LSB; // 注意 MSB 是带符号扩展的高字节 if (temp_raw 0x8000) { temp_raw ~temp_raw 1; // 负数取补码 negative_flag 1; } int_part temp_raw 4; dec_part ((temp_raw 0x0F) * 625 50) / 1000; // 四舍五入到 0.1℃然后显示时把int_part的十位、个位分别放到对应位再把dec_part放到最后一位并点亮小数点。如果温度是负数就在最前面显示一个负号用段码 0x40 或 0xBF看共阴共阳。这里要提醒一点temp_raw (MSB 8) | LSB;在 C51 里如果 MSB 是有符号 char左移后整型提升可能会产生符号位问题。更保险的写法是把两个字节先转成 unsigned char再拼成 int然后用减法处理补码int temp_raw ((int)(unsigned char)MSB 8) | (unsigned char)LSB; if (temp_raw 0x8000) { temp_raw (int)(0x10000 - (unsigned int)temp_raw); }注意 51 的 int 是 16 位0x10000已经超过 int 范围所以直接用temp_raw ~temp_raw 1;更符合 C51 的习惯。4. KEIL C51 工程主循环设计定时、刷新、状态标志和优化陷阱4.1 main 函数结构别在温度转换时卡死屏幕DS18B20 发起温度转换后需要等待最长 750ms 才能读取结果。如果主循环里直接执行“发转换 - 延时 750ms - 读温度 - 显示”那么这 750ms 内数码管是完全不刷新的你会看到数码管明暗闪烁而且按键响应也会卡顿。更好的做法是把温度读取和显示拆开在循环里快速扫描显示每隔一段时间才去读一次温度。比如void main(void) { unsigned char i; unsigned char buf[4]; while (1) { // 每循环扫描显示约 50 次约 100ms 后刷新一次温度 for (i 0; i 50; i) { display_scan(buf); delay_ms(2); } read_temperature_from_ds18b20(buf); // 更新 buf } }这样温度刷新频率是 10Hz足够日常使用而且数码管不会闪。4.2 温度转换命令和执行流程一次完整的温度读取流程是复位检测存在脉冲。发送 0xCC跳过 ROM再发 0x44启动温度转换。等待转换完成。如果你不想硬等 750ms可以在转换命令之后不立即读而是先扫描一遍数码管等时间差不多了再去读温度。复位再发 0xCC再发 0xBE读暂存器。读取 LSB 和 MSB。这个流程在源码里一定要写清楚很多工程包的问题在于作者把启动转换和读取写在同一个函数里中间还加了一个大延时导致整个程序看起来“卡了很久”。实际代码示例unsigned char ds18b20_read_temp(void) { unsigned char lsb, msb; ds18b20_reset(); ds18b20_write_byte(0xCC); // skip ROM ds18b20_write_byte(0x44); // start conversion delay_ms(750); // 等待转换 ds18b20_reset(); ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // read scratchpad lsb ds18b20_read_byte(); msb ds18b20_read_byte(); return (msb 8) | lsb; // 实际要返回 int }如果你用 12MHz 晶振750ms 延时可以用delay_ms(750);但精度要求不高因为传感器提前完成也不会导致错误。4.3 存储位置code、data、xdata 和段码表51 单片机内部 RAM 只有 256 字节扩展 RAM 也不大。STC89C52RC 的 Flash 有 8KB因此常量数组应该放到 code 区unsigned char code seg_table[] {0x3F, 0x06, ...};如果把段码表定义成普通数组就会占用宝贵的内部 RAM数据多一点之后很容易出现“变量空间溢出”的报错。同理延时函数里的临时变量可以用 unsigned char只要够用不用 unsigned int 就不用。4.4 编译优化陷阱volatile 与延时函数被吃掉这是 KEIL C51 下非常经典的问题。前面提到过很多同学的delay_us是这样写的void delay_us(unsigned int t) { while (t--); }如果 KEIL 的优化级别比较高编译器发现这个循环没有任何输出只是修改一个局部变量就会把这个循环直接优化成空或者大幅减少循环次数。结果就是程序里调用了delay_us(500)实际可能只执行了几条 NOP。DS18B20 初始化时序完全乱套自然读不到正常温度。解决方法是把延时函数里的循环变量声明为volatilevoid delay_us(unsigned int t) { volatile unsigned int i t; while (i--); }或者把优化级别调低比如在Options for Target - C51里面选择 Optimization Level 0 或 1 先调通确认功能正常后再尝试优化。我个人的习惯是所有用于特定外设时序的延时函数一律用 STC-ISP 生成的版本并且把相关变量定义成 volatile。这样更换板子和晶振时只需要重新生成一次延时函数不会因为优化等级变化而翻车。5. 开发板PDF原理图与代码引脚对照上拉、锁存器、供电一个都不能错5.1 DS18B20 三根线的接法DS18B20 通常是一个 TO-92 封装的三脚元件正面朝自己时引脚排列是1 脚 GND2 脚 DQ3 脚 VCC。千万不要接反接反大概率会发烫甚至烧毁。在原理图上DQ 引脚通常会画一条线连到单片机某个 IO同时会有一个电阻从 DQ 拉到 VCC这个电阻阻值一般是 4.7k。如果你的开发板原理图里看不到这个电阻那就要自己在外接传感器时加一个。没有上拉电阻单总线空闲状态就是一个悬空电平复位时传感器无法产生稳定的存在脉冲。检查方法用万用表量 DQ 对地电压。正常空闲时应该是接近 VCC 的高电平比如 4.8V 左右。如果测到 0V 或者飘忽不定先查上拉。5.2 数码管的锁存器和限流电阻很多开发板为了让 IO 口复用数码管会用 74HC573 或 74HC245 这类锁存器隔离。原理图里会看到 P0 口既连锁存器输入又连其他外设。这时代码里控制数码管的步骤就不是简单的P0 seg_code而是把段码送到 P0。把段选锁存器的 LE锁存使能引脚置 1然后置 0数据被锁存。再送位选码到 P0。把位选锁存器的 LE 引脚拉高再拉低。比如常见开发板用 P2.6 控制段选锁存器P2.7 控制位选锁存器void display_scan(unsigned char *buf) { P0 0x00; // 消隐 LE_SEG 1; LE_SEG 0; P0 buf[0]; // 第一个数码管的段码 LE_SEG 1; LE_SEG 0; P0 0xFE; // 位选低电平稳第一个数码管 LE_BIT 1; LE_BIT 0; delay_ms(2); }如果你的代码里直接把P0当段码输出却发现数码管不亮大概率是漏掉了锁存器操作。看 PDF 原理图时搜索“74HC573”或者“SEG”“BIT”这些网络标签就能知道引脚对应关系。5.3 引脚定义不一致代码里的 sbit 必须和原理图一一对应这类工程包里DS18B20 的 DQ 可能定义在sbit DQ P3^2;你的开发板却把传感器插到了 P1.0。如果不去改程序当然读不到温度。数码管也一样段选、位选可能不同。所以拿到工程后第一步就是用 PDF 阅读器搜索原理图中的传感器接口找到 DQ 连到单片机的哪个引脚然后统一修改代码里的 sbit 定义。这个排查非常机械却非常有效。5.4 供电问题5V 和 3.3V 别混用STC89C52RC 标准工作电压是 5VDS18B20 在 3V 到 5.5V 都能工作但如果你用 3.3V 给 STC89C52RC 供电跑偏了之后很多型号工作不稳定。给 DS18B20 供电时最好直接用开发板的 5V 电源轨不要从某个 IO 口反灌电源也不要和电机这类大电流设备并联。另外DS18B20 虽然号称“寄生供电”可以只用两根线但在实际开发板上我更推荐 VCC 和 GND 都接好独立供电数据线上拉也一样不能少。寄生供电在交流电干扰大、线长超过 30cm 的情况下容易读取失败。6. 一次“温度永远85℃”的完整排查过程与修复6.1 85℃这个数字是从哪来的DS18B20 上电复位后温度寄存器的默认值是 0x0550换算成温度正好是 85℃。如果你的数码管稳定显示 85.0℃或者 85.1℃基本说明程序里读到了传感器复位后的默认值但是后续的温度转换没有成功或者读取的数据有问题程序没有把错误识别出来。换句话说传感器可能在线但通信不完整。常见原因有DQ 上拉电阻缺失。晶振频率和延时函数不匹配。延时函数被优化成空。读取时序采样点太晚。引脚定义错误程序访问的引脚根本没接 DS18B20。6.2 排查过程的完整链路我当时拿到的是一个显示 85.0℃的工程包数码管能正常显示按键也没问题说明数码管部分没问题。于是按照下面顺序排查第一步测 DQ 静止电压。万用表红笔接 DQ黑笔接 GND静态显示 4.96V正常。说明上拉电阻没问题传感器也接了电源。第二步在程序里临时把 DS18B20 复位函数的返回值用数码管显示出来。如果返回 0说明传感器有回应如果不为 0说明初始化失败。当时显示的是 0说明复位成功了。第三步怀疑是读取时序问题。没有示波器我就写了一个测试程序连续发送读出暂存器命令把 LSB 和 MSB 读到数码管上显示。结果发现读出来的数据一直是 0x50 和 0x05也就是默认值。这说明写入指令可能没有正确执行或者读时序采样有问题。第四步检查写入指令的时序。我用 GPIO 翻转和逻辑分析仪观察 DQ 波形发现写 1 时序中拉低到释放的时间已经超过了 15us。正常应该是 5us 左右但实际到了 40us。原因就是延时函数被优化了——不是变快而是变慢了这里要说明因为while循环没有被优化掉但编译器可能把局部变量 t 放在了不同的寄存器循环体执行时间变长导致每个时隙都超了。更关键的是我在Options for Target里看到优化级别被设成了 Level 8最快。虽然这不一定必然导致错误但在某些 C51 编译器下它会把“空循环”改成更短的指令序列。我把延时函数改成 volatile 后重新编译问题依旧。接着把优化级别改成 Level 0重新下载温度立刻变成正常室温 27.5℃。6.3 为什么优化级别会影响延时函数C51 的优化会尝试减少循环跳转的开销比如把多次空循环合并或者把仅修改变量的语句识别为“无副作用”从而删除。DS18B20 的时序要求拉低时间必须大于 480us如果一个delay_us(500)实际只执行了 10us那传感器复位就永远不会成功。解决后的经验是所有延时函数尤其是微秒级延时不要依赖编译器优化。用volatile是第一步但最可靠的还是用 STC-ISP 生成的精确延时函数。调通前把优化级别调到 Level 0Optimization Level 0。确认跑通后再逐步升高优化等级每升一档都重新测试温度读取是否正常。如果开了优化后温度偶尔变成 85℃或者乱跳不要犹豫直接关掉优化或者把关键延时函数单独放在一个.c文件里对该文件选择“不优化”。6.4 修复后的校准与验证温度能正常读出来之后还要做精度验证。DS18B20 的出厂精度是 ±0.5℃在室温下通常够用。为了验证我做了两个测试冰水混合物把传感器探头放在 0℃ 冰水混合物里等待 2 分钟显示 0.1℃左右可以接受。沸水水温 100℃实测 99.6℃。这里要注意探头不能直接触底否则测量的是锅底温度会超过 100℃。如果发现整体偏差很大比如显示 30℃实际 25℃可以检查供电电压和线路电阻也可以查看是否使用了寄生供电。有一个更简单的方法跑完温度转换后再连续读两次暂存器取平均值能滤掉一部分读数抖动。但不要频繁读因为 DS18B20 在转换期间读出来的值是上一轮的旧值。7. 从固定温度计到可扩展的温控系统改造思路与常见扩展7.1 增加上下限报警和继电器控制数码管温度计跑通之后下一步自然想到的就是“超过某个温度就报警”。这个改造很容易不需要改 DS18B20 驱动只在主循环里加一个比较逻辑if (negative_flag 0 int_part 30) // 大于 30℃ { beep 0; // 蜂鸣器响低电平有效取决于电路 } else { beep 1; }如果要控制继电器驱动方式类似但要注意继电器线圈需要三极管或 ULN2003 驱动STC89C52RC 的 IO 口直接拉继电器很容易烧片子。用继电器控制风扇、加热棒就是一个简易温控系统。7.2 总线上挂多个 DS18B20跳过 ROM 命令就不够用了单总线的价值之一是可以在同一根 DQ 上挂多个 DS18B20每个 DS18B20 都有唯一的 64 位 ROM 编码。如果只用一个传感器可以用 0xCC 跳过 ROM挂多个时需要先用 0x33读 ROM或 0xF0搜索 ROM获取每个传感器的编码再通过 0x55 命令匹配对应编码来读取。这在 51 单片机上完全可行但要注意总线长度不要超过 50cm否则信号反射严重。多个 DS18B20 的总线上拉电阻可能需要减小为 2.2k。搜索 ROM 的算法比较长网上有现成代码直接移植时要小心位序和延时。如果你只是想做一两个温度点的监控也可以直接用两个不同的 IO 口接两个 DS18B20各自独立读取代码反而更简单。STC89C52RC 的 IO 足够多没必要为难自己去搞单总线寻址。7.3 升级显示器件从数码管到 1602 LCD 或 OLED数码管显示温度直观但能显示的信息量太少了。如果想显示温度曲线、报警状态、历史极值可以考虑换成 1602 字符液晶点阵屏或者 0.96 寸 OLED 屏。OLED 用 I2C 接口51 上软件模拟 I2C 也不难。改造时最省力的方式就是保留现有的 DS18B20 驱动只把display_scan换成 LCD 的显示函数。我实际做的时候把温度值格式化成一个字符串sprintf(buf, Temp: %d.%d C, int_part, dec_part);然后调用 OLED 显示字符串数码管那部分代码全部注释掉。整个移植过程大概一个晚上就能搞定前提是 DS18B20 驱动已经稳定。7.4 用串口把温度数据发给上位机如果还想做数据分析串口是很方便的通道。STC89C52RC 有 UART通过 STC-ISP 下载线的 USB 转 TTL 接口连接电脑把温度数据不断发出去。C51 的 printf 默认会把数据发到串口 1但要先初始化串口波特率并且printf对浮点数支持有限最好用整数分别发送printf(T%d.%d\n, int_part, dec_part);这样电脑端用串口助手或者自己写的 Python 脚本就能记录温度曲线。这也是很多人拿到 DS18B20 工程后做的第一个“数据采集系统”。我个人这几年调试下来的最大感受是DS18B20 这类单总线器件最关键的不是代码本身而是“时序图 延时准确”。如果你也拿到了类似的工程包但没跑通不要急着怀疑资料先把原理图里 DS18B20 所在引脚的上拉电阻确认好再用 STC-ISP 生成一套精确延时函数成功概率会高很多。等你把它跑通再去扩展成温控风扇或者智能鱼缸温度计就会非常得心应手。本文还有配套的精品资源点击获取
返回列表