DS18B20无线测温系统:单总线时序、射频链路与报警实现
2026/9/18 20:50:15 网站建设 项目流程

简介:这是一份面向电子信息、自动化及相关专业学生的传感器课程大作业完整报告,围绕无线温度数据采集系统展开,可用于课程作业参考、实验报告撰写与温控报警类小项目设计借鉴。压缩包内共1个doc文档,约561KB,正文按目录组织为温控设计思路、硬件部分与参考文献三大板块,含设计框图、总电路图、报警与显示模块电路图及PCB板示意图,硬件上给出蜂鸣器驱动报警与LCD1602显示的具体选型理由和方案对比,并说明温度采集、射频传输、监控节点显示与超限报警的完整链路。软件与器件部分介绍了DS18B20数字智能温度传感器的精度范围、响应速度与小型化特点,以及数据采集、处理和显示的实现思路,末尾附有传感器与检测技术、电子技术基础、单片机原理等参考文献。目前已有175人学习,适合需要完整报告框架、图文电路说明与选型论证参考的读者查阅。

1. 从一份传感器大作业报告说起:DS18B20 无线测温到底难在哪

传感器课程设计做到最后一周,最常见的场面是:液晶上稳定显示 85.0℃,换了三根 DS18B20 结果一样,报告里的框图画得漂漂亮亮,实物却卡在这一步。这份《传感器大作业报告完整版》给出的正是典型的分布式测温方案——前端用 DS18B20 采温,通过射频把数据送到监控节点,监控节点用 LCD1602 实时显示,并配一组 NPN 三极管驱动的蜂鸣器和报警灯。它瞄准的场景很具体:电气机箱、配电柜、粮仓、温室这类不方便铺信号线、人又不常驻的位置。选它做课程设计的人,通常要同时应付单总线时序、射频收发、液晶驱动和 PCB 打样四件事。下面不按报告章节顺序复述,而是把这四件事拆成能直接复现的步骤,顺带把报告里一笔带过的参数和坑补上。

2. DS18B20 单总线时序与温度换算:报告里没写透的部分

报告只写了"温度传感器选择 DS18B20",但真正决定你能不能读到数的,是它那套微秒级的单总线协议。这一章先把选型理由讲清楚,再落到时序代码和温度换算。

2.1 选型:为什么这类课题大多落在 DS18B20 上

测温元件的选择面其实很宽,课程设计里常见的几类对比如下,差别主要集中在"要不要额外放大电路"和"输出是模拟还是数字"。

类型输出形式典型精度接口复杂度单点成本适合场景
NTC 热敏电阻电阻变化±1℃ 需标定需分压+ADC+查表极低成本敏感、精度要求低
PT100 铂电阻电阻变化±0.1℃需恒流源+仪表放大+ADC中高工业计量、宽温区
热电偶毫伏级电压±1~2℃需冷端补偿+高增益放大高温炉、窑炉
DS18B20数字量,单总线±0.5℃(-10~85℃)一根数据线直连 MCU多点分布式、远距离走线
红外测温数字/模拟±1℃ 视发射率需考虑视场与发射率非接触、移动目标

选 DS18B20 的核心理由是"数字化"和"可挂载"。它把 ADC、基准、标定全部封在芯片里,MCU 端只需要一个 GPIO 加一个 4.7kΩ 上拉电阻,就能在一条线上挂 8 个甚至更多探头,每个探头有出厂唯一的 64 位 ROM 地址。报告里那套"温度采集 + 射频上传"的架构,本质上就是靠这个特性把布线成本压下来的。代价是它的转换速度慢,12 位分辨率下单次转换要 750ms,而且协议对延时的容差很小。

提示:DS18B20 有三个封装版本,TO-92 直插最便宜但引线是刚性针脚;防水探头版内部已灌封并带线缆,适合机箱外部测温;贴片 SOIC-8 适合直接焊在 PCB 上。做机箱测温建议选防水探头版,避免探头本体受潮导致读数漂移。

2.2 复位脉冲、存在脉冲与读写时隙

单总线没有独立时钟线,主机和从机全靠约定的时长区分 0 和 1。以 STM32F103 为例,系统主频 72MHz 时,用 DWT 或定时器做一个微秒级延时是第一步,下面这段是最小可用的时序层。

// ds18b20.c —— 单总线底层时序(STM32F103,GPIO 推挽输出 + 上拉输入切换) #include "stm32f10x.h" #define DQ_HIGH() do{ GPIOB->CRL &= ~(0xF << 20); GPIOB->CRL |= (0x8 << 20); \ GPIOB->BSRR = GPIO_Pin_5; }while(0) // 上拉输入 #define DQ_LOW() do{ GPIOB->CRL &= ~(0xF << 20); GPIOB->CRL |= (0x3 << 20); \ GPIOB->BRR = GPIO_Pin_5; }while(0) // 推挽输出低 #define DQ_READ() ((GPIOB->IDR & GPIO_Pin_5) ? 1 : 0) static void delay_us(uint32_t n) // 72MHz 下约 1us 粒度 { uint32_t i; for (i = 0; i < n * 8; i++) __NOP(); } /* 复位:拉低至少 480us,再释放,等待从机 60~240us 的存在脉冲 */ uint8_t DS_Reset(void) { uint8_t presence; DQ_LOW(); delay_us(500); DQ_HIGH(); delay_us(70); presence = !DQ_READ(); // 读到低电平说明有器件应答 delay_us(430); // 补齐整个时隙,等总线回高 return presence; // 1 = 检测到器件,0 = 无应答 } /* 写一位:写 1 拉低 1~15us 后释放;写 0 拉低 60us 以上 */ void DS_WriteBit(uint8_t bit) { DQ_LOW(); if (bit) { delay_us(5); DQ_HIGH(); delay_us(60); } else { delay_us(60); DQ_HIGH(); delay_us(5); } } /* 读一位:主机拉低 1us 后释放,在 15us 内采样从机拉低的时长 */ uint8_t DS_ReadBit(void) { uint8_t bit; DQ_LOW(); delay_us(2); DQ_HIGH(); delay_us(10); bit = DQ_READ(); delay_us(50); return bit; } void DS_WriteByte(uint8_t dat) { uint8_t i; for (i = 0; i < 8; i++) { DS_WriteBit(dat & 0x01); dat >>= 1; } } uint8_t DS_ReadByte(void) { uint8_t i, dat = 0; for (i = 0; i < 8; i++) { dat >>= 1; if (DS_ReadBit()) dat |= 0x80; } return dat; }

逻辑说明:DS_Reset里 500us 的拉低是"复位脉冲",从机检测到后会拉低总线 60~240us 作为"存在脉冲",主机在第 70us 左右采样,采样点必须落在存在脉冲窗口内。DS_WriteBit的关键是写 1 的拉低时间不能超过 15us,否则从机会把它当成写 0;写 0 则要持续 60us 以上。DS_ReadBit的采样点放在释放总线后 10~15us 的窗口内,从机此时送出的数据保持 15us 左右。这几处延时如果被中断打断,读数就会随机出错,所以一般在读写期间关掉全局中断。

参数说明:delay_us的系数随主频变化,用示波器量一次 500us 复位脉冲即可校准;上拉电阻取 4.7kΩ,线长超过 1 米时可降到 2.2kΩ 提高上升沿速度,但静态电流会增加到 1.5mA 以上,功耗敏感场合要权衡。

2.3 温度寄存器格式与分辨率配置

DS18B20 上电默认是 12 位分辨率,温度寄存器是 16 位带符号数,低 4 位是小数部分,LSB 权重 0.0625℃。配置寄存器的 bit6、bit5 决定分辨率,对应的转换时间和 LSB 如下。

bit6:bit5分辨率LSB 权重最大转换时间
0:09 位0.5℃93.75ms
0:110 位0.25℃187.5ms
1:011 位0.125℃375ms
1:112 位0.0625℃750ms
/* 单点读取:跳过 ROM 只适用于总线上只有一个探头 */ float DS_ReadTemp(void) { uint8_t tl, th; int16_t raw; DS_Reset(); DS_WriteByte(0xCC); // SKIP ROM DS_WriteByte(0x44); // CONVERT T,发起一次转换 HAL_Delay(750); // 12 位分辨率下必须等够 DS_Reset(); DS_WriteByte(0xCC); DS_WriteByte(0xBE); // READ SCRATCHPAD tl = DS_ReadByte(); th = DS_ReadByte(); raw = (int16_t)((th << 8) | tl); return raw * 0.0625f; // 负数会自然取到,DS18B20 用补码 }

逻辑说明:0xCC 是跳过 ROM 命令,只在总线上仅挂一个探头时使用,多探头时必须先发 0x55 加 8 字节 ROM 地址定位。0x44 发起转换后主机可以去做别的事,750ms 后再回来读。0xBE 读出的前两字节就是温度值,第三、四字节是高温和低温报警阈值,最后两字节分别是配置寄存器和 CRC。

参数说明:如果只做机箱温度监控,9 位分辨率(0.5℃、93.75ms)足够,能把节点功耗降下来;需要显示到小数点后一位时用 11 位(0.125℃);报告里渲染的 0.0625℃ 精度是理论 LSB,实际误差由器件本身的 ±0.5℃ 决定,别把两者混为一谈。

2.4 多点挂载与 85℃ 假值

上电瞬间读到的 85.0℃ 是 DS18B20 的转换寄存器默认值,不是故障,而是"你还没让它转换就先把寄存器读出来了"。解决办法是在初始化完成后先发一次 0x44 并等够时间,再进入正常轮询。如果一直读到 85℃,优先查两件事:总线有没有 4.7kΩ 上拉、HAL_Delay(750)是否被漏掉。

多探头场景要改用 ROM 搜索流程:DS_Reset()→ 写 0x33(READ ROM,只适用单探头)或 0xF0(SEARCH ROM,多探头)→ 逐位读取从机响应的 64 位地址,用"分歧点"算法遍历整棵树。常见做法是第一次上电把扫描到的 ROM 地址存进 Flash,之后直接用 0x55 + 地址直读,省掉每次搜索的时间。

3. 无线温度采集节点与监控端链路实现

报告只画了"温度传感器—最小系统—射频—显示"的框图,中间的数据怎么组织、怎么保证不串码,才是实物能不能跑起来的关键。这一章按节点分工、帧格式、显示、报警四步走。

3.1 节点分工与射频模块选型

系统拆成两个角色:采集节点负责测温并把数据发出去,监控节点负责接收、显示和报警。射频部分的常见选型如下。

模块频段空中速率标称距离接口备注
433MHz 超再生433.92MHz几十米单数据脚成本最低,抗干扰差,需软件编码
nRF24L01+2.4GHz250k~2Mbps空旷 100mSPI自带地址与 CRC,最省事
SI4432433MHz可调数百米SPI灵敏度高,配置寄存器多
LoRa 模块470/868MHz0.3~37.5kbps公里级UART/SPI适合更大范围,成本高

课程设计里用 nRF24L01+ 的性价比最高,它把地址过滤、CRC 校验、自动重传都做在硬件里,MCU 端只需要操作 SPI。如果老师指定了 433MHz,就得自己在软件层加同步字和校验。

3.2 数据帧格式与 CRC8 校验

空中传的数据包一定要带校验,否则接收端偶发误码会直接把温度显示成离谱数值。推荐帧结构如下。

偏移长度字段说明
01帧头 0xA5用于接收端字节对齐
11节点 ID0x01~0xFE,支持多节点区分
22温度原始值int16,单位 0.0625℃,小端
41报警标志bit0 高温、bit1 低温、bit2 传感器故障
52电池电压mV,可选
71CRC8前 7 字节的多项式 0x07 校验
/* 发送端打包:温度放大成整数再发,避免浮点跨平台对齐问题 */ uint8_t crc8(const uint8_t *buf, uint8_t len) { uint8_t crc = 0x00, i, b; for (i = 0; i < len; i++) { crc ^= buf[i]; for (b = 0; b < 8; b++) crc = (crc & 0x80) ? (uint8_t)((crc << 1) ^ 0x07) : (uint8_t)(crc << 1); } return crc; } void BuildFrame(uint8_t *f, uint8_t node, float temp, uint8_t flag) { int16_t raw = (int16_t)(temp / 0.0625f); // 转成 DS18B20 原始刻度量纲 f[0] = 0xA5; f[1] = node; f[2] = (uint8_t)(raw & 0xFF); f[3] = (uint8_t)((raw >> 8) & 0xFF); f[4] = flag; f[5] = 0x00; // 电压占位 f[6] = 0x00; f[7] = crc8(f, 7); // 只校验前 7 字节 }

逻辑说明:温度不做浮点传输,而是换算回 0.0625℃ 的整数刻度,接收端乘 0.0625f 还原即可,这样两端不存在字节序和浮点格式差异。CRC8 用多项式 0x07,覆盖除校验位以外的全部字段,接收端算出不一致就整帧丢弃,不更新显示。

参数说明:帧头 0xA5 要选得足够有辨识度,别用 0x00 或 0xFF 这种容易被噪声凑出来的值;如果节点数多,可以在帧尾再加一个序号用于丢包统计;nRF24L01 本身带 16 位 CRC,但由于还可能有应用层拼帧错误,双保险不吃亏。

3.3 监控端接收与 LCD1602 显示

接收端流程是"收到中断 → 收包 → 校验 → 更新缓存 → 刷新液晶"。校验失败时不改缓存,保持上一次有效值,同时在液晶上打一个错误计数。

/* 监控节点主循环片段 */ uint8_t frame[8]; float last_temp = 0.0f; uint8_t err_cnt = 0; void Monitor_Loop(void) { if (NRF_DataReady()) { NRF_ReadPayload(frame, 8); if (frame[0] == 0xA5 && crc8(frame, 7) == frame[7]) { int16_t raw = (int16_t)((frame[3] << 8) | frame[2]); last_temp = raw * 0.0625f; } else { err_cnt++; // 坏帧只计数,不覆盖 last_temp } } LCD_SetCursor(0, 0); LCD_Printf("TEMP:%5.1f C ", last_temp); LCD_SetCursor(1, 0); LCD_Printf("ERR:%3d ", err_cnt); Alarm_Check(last_temp); }

逻辑说明:这段循环放在 main 里非阻塞执行,射频模块用中断脚触发读取,避免轮询丢包。液晶每轮全刷 16 个字符并补空格,防止上一次的长数字残留成"鬼影"。Alarm_Check单独抽出来,方便把阈值改成从按键或串口配置。

参数说明:LCD1602 走 4 位模式只需 D4~D7 四根数据线加 RS、RW、E 三根控制线,RW 可以直接接地恒为写模式,省一根线;对比度引脚 V0 接 10kΩ 电位器中间抽头,背光 A/K 串 100Ω 限流到 5V,串 220Ω 会偏暗。

3.4 报警阈值与回差设置

报告只写了"超出一定范围发出报警",实际做出来最容易被吐槽的是蜂鸣器在阈值附近疯狂启停。原因是温度本身有 ±0.5℃ 波动,阈值又设成单点。正确做法是加回差(滞回)。

参数建议值说明
高温阈值45.0℃按被测设备允许上限留 5℃ 余量
高温解除值42.0℃比阈值低 3℃,即回差 3℃
低温阈值5.0℃机箱防结露下限
低温解除值8.0℃回差同为 3℃
报警确认次数连续 3 次过滤单次误码造成的假报警

报警确认次数用计数器实现:连续 N 次超限才置报警位,连续 N 次回到安全区才清零,这一段逻辑比阈值本身更影响实物体验。

4. 报警与显示模块的硬件落地:三极管驱动、PCB 与电源排错

报告里报警模块只写了一句话——"使用一个 NPN 型三极管作为蜂鸣器的驱动"。这一章把这句话拆成能算的参数,再补上 PCB 布局和上电排错的顺序。

4.1 蜂鸣器驱动三极管的参数计算

MCU 的 GPIO 一般只能拉 8~20mA,而 5V 有源蜂鸣器工作电流常在 20~40mA,直连会把 IO 拉垮甚至损坏。用 NPN 管做低边开关是标准做法,型号上 2N3904、S8050、MMBT3904 都能用,S8050 的集电极电流余量更大。

计算过程:设蜂鸣器工作电流 Ic = 30mA,S8050 的 hFE 取 100(保守值,手册典型 120~400),则基极电流 Ib ≥ Ic / hFE = 0.3mA。为保证深度饱和,实际取 3~5 倍余量,即 Ib ≈ 1.5mA。GPIO 高电平 3.3V,Vbe 取 0.7V,则 Rb = (3.3 - 0.7) / 1.5mA ≈ 1.7kΩ,取标称值 1.5kΩ 或 2.2kΩ。

元件取值作用
驱动管 Q1S8050(NPN)低边开关,集电极接蜂鸣器负极
基极电阻 Rb1.5kΩ限制基极电流,防止 IO 过流
基极下拉电阻10kΩ防止 MCU 复位期间悬空误导通
续流二极管1N4148并在蜂鸣器两端,泄放感性反峰
报警 LED 限流470Ω3.3V 供电下约 5mA,亮度足够
蜂鸣器5V 有源有源自带振荡,给电即响

接法:蜂鸣器正极接 5V,负极接三极管集电极,发射极接地,基极经 Rb 接 GPIO。LED 与 1kΩ 电阻串在另一路 GPIO 上,由软件同步闪烁,这就是报告里提到的"控制蜂鸣器报警的同时控制报警灯闪烁"。

注意:软件上别用GPIO_SetBits之后立刻GPIO_ResetBits做"滴滴"声,中断里频繁翻转会拖慢主循环。用定时器中断按 500ms 周期翻转标志位,主循环里根据标志控制引脚更清晰。

4.2 LCD1602 的接线、对比度与初始化顺序

LCD1602 上电后必须先走一遍初始化序列,否则会出现"背光亮但无字符"。标准流程是上电等待 15ms 以上,然后依次发送 0x33、0x32(切到 4 位模式),再配置显示模式 0x28、开显示 0x0C、清屏 0x01、设置输入模式 0x06。顺序反了就会出现半屏黑块。

显示内容上,报告明确要"实时显示机箱环境温度和风扇转速"。转速这类计数型数据建议单独占一行,用整数显示,避免小数位跳动导致整行重刷。

4.3 PCB 布局:单总线走线、晶振与射频净空

打样前有几个位置值得多花十分钟:DS18B20 的数据线尽量远离晶振和 PWM 走线,旁边加 4.7kΩ 上拉;射频模块的天线区域(通常是 PCB 天线或外置天线座)下方所有层都不铺铜,净空区至少 5mm,否则距离会掉一半;每个芯片电源脚配 0.1uF 去耦电容,紧贴引脚放置;模拟地和数字地单点汇接在电源入口。

如果探头要引出机箱,数据线超过 1 米时建议用屏蔽线并把屏蔽层单端接地,同时把上拉电阻改到 2.2kΩ。线更长的话,DS18B20 的分布电容会把上升沿拖慢,示波器上看就是波形从方波变成圆弧,这时候除了减小上拉还要降低总线上的探头数量。

4.4 上电不亮、读数异常、报警乱响的排查顺序

硬件问题靠猜效率很低,按现象分表查会快很多。

现象优先怀疑验证方法
液晶背光亮但无字符V0 对比度电压、初始化顺序调电位器看是否出现黑块;逻辑分析仪抓 E 脚脉冲数
读数恒为 85.0℃未发 0x44 或延时不足单步调试看是否执行转换命令
读数恒为 0.0℃上拉电阻缺失、DQ 脚方向切换写错万用表量总线空闲时是否被拉到 3.3V
读数随机跳变延时被中断打断、线太长读写期间关中断后复测;缩短探头引线
蜂鸣器一直响基极下拉缺失、GPIO 复位期间悬空加 10kΩ 下拉后复测
射频丢包严重天线净空不足、供电纹波大拉开距离测 RSSI;示波器看 3.3V 纹波

排查时按"先电源、再时钟、后信号"的顺序走:先量 3.3V 和 5V 是否正常且纹波小于 50mV,再确认晶振起振,最后才用逻辑分析仪看总线时序。

5. 进阶:用逻辑分析仪和上位机把报告变成可验证的系统

报告写完不等于系统做完,答辩现场最容易被问的是"你怎么证明这个温度是准的"。这一章给三个能当场演示的验证手段。

5.1 用逻辑分析仪抓单总线时序

DS18B20 的时序看代码只能看个大概,接上 8 通道逻辑分析仪(采样率设 24MHz 以上,1us 时隙才抓得清)抓 DQ 脚,重点看三处:复位脉冲宽度是否大于 480us、存在脉冲是否落在 60~240us、读时隙的采样点是否在 15us 窗口内。如果波形上出现晶振般的毛刺,多半是上拉电阻偏大或走线过长。抓一次 12 位转换的完整过程大约 750ms,采样深度要开到 20M 点以上,否则尾部会被截断。

5.2 从串口到上位机:把数据变成曲线

监控节点额外引一路 UART,按固定格式输出,主机端用 Python 画实时曲线,比盯着液晶看有说服力得多。

# plot_temp.py —— 读取串口温度并实时绘图,帧格式 "TEMP:23.5\r\n" import serial, matplotlib.pyplot as plt, matplotlib.animation as anim ser = serial.Serial('COM3', 115200, timeout=0.5) # 按实际端口修改 xs, ys = [], [] def update(_): line = ser.readline().decode('ascii', 'ignore').strip() if line.startswith('TEMP:'): xs.append(len(xs)) ys.append(float(line[5:])) # 截掉前缀转浮点 xs, ys = xs[-200:], ys[-200:] # 只保留最近 200 点 plt.cla() plt.plot(xs, ys, lw=1) plt.ylim(0, 60) # 与报警阈值区间对齐 plt.title('temperature / sample index') ani = anim.FuncAnimation(plt.gcf(), update, interval=200) plt.show()

逻辑说明:timeout=0.5保证读不到数据时不会卡死;xs, ys做滑动窗口,防止长时间运行时内存持续增长;ylim设成和报警阈值一致的量程,报警点在图上会非常直观。

参数说明:波特率必须与 MCU 端一致,115200 下每帧 10 字节左右,100ms 一次完全够用;如果现场干扰大,把绘图间隔拉长到 500ms 并加滑动平均(窗口 5 点),曲线会平滑很多。

5.3 用 Modbus 或 MQTT 把数据接到已有系统

如果答辩要求"能和现有平台对接",两条路比较常见。一条是把监控节点做成 Modbus RTU 从机,用 ModbusPoll 这类工具直接读保持寄存器,温度和报警状态各占一个 16 位寄存器,温度放大 10 倍传整数;另一条是在监控节点上加一路 Wi-Fi 模组,按 MQTT 把 JSON 发到云平台,用 PlatformIO 开发时可以直接引用现成的 PubSubClient 库,把BuildFrame里那几个字段填进 payload 即可。两条路都不改前端采集,只在监控节点侧扩一个转发任务。

5.4 精度与响应时间的实测方法

最后补一个能写进报告"测试"章节的做法:把探头和一支已校准的温度计(或标准水银温度计)一起放进恒温水浴,从 20℃ 升到 50℃,每 5℃ 稳定 3 分钟后记录一次读数和标准值,算最大偏差;响应时间则用探头从室温快速插入 50℃ 水浴,用 5.2 的曲线记录从跳变到达到稳态值 63% 所需的时间。9 位分辨率下这个时间通常在 1~2 秒,12 位下 3 秒以上——这组数据比任何理论精度说明都更能说明你选的配置合不合理。

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

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

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

立即咨询