ds18b20 数字温度传感器
1.参数指标
(1)量程(温度测量范围): -55℃----125℃
(2)精度(测量的温度值与实际温度值之间所允许的最大误差): ±0.5℃
(3)分辨率(传感器对温度变化的敏感程度):
9位:0.5℃
10位:0.25℃
11位:0.125℃
12位(默认):0.0625℃
(4)工作电压:3v---5.5v
2.ds18b20通信(半双工,串行,异步):

GPIO One-wire:GPIO单总线通信,通过一根GPIO信号线来进行通信
3.ds18b20芯片内部结构
(1)可以通过内部电源给芯片供电
(2)64位ROM和单总线接口;
(3)存储器控制逻辑模块:协调芯片内部各模块工作
(4)暂存器(SCRATCHPAD):存放温度,配置参数
(5)温度传感器:采集温度
(6)高温触发阈值与低温触发阈值(可配置)
(7)8位CRC校验生成器:生成CRC校验
4.上拉电阻
上拉电阻 是数字电路中非常基础但极其重要的元件,用于确保信号线在"空闲"时有确定的电平状态


51和ds18b20都释放总线时,总线能够呈现高电平,释放总线 (需要作为数据的接收方)
任何一方拉低总线,整个总线都变低
5.dsl8b20读数
16位、符号扩展的二进制补码,通过单总线DQ串行发出
6.读取数据流程
(1)复位
(2)发送0xCC,跳过ROM
(3)发送0x44,开启温度转换
(4)延时750ms
(5)复位
(6)发送0xCC,跳过ROM
(7)发送0xBE,读取温度
(8)读取两个字节的温度数据
float get_temp(void)
{
unsigned char temp_low=0;
unsigned char temp_high=0;
short temp=0;
ds18b20_reset();
write_ds18b20(0xCC);
write_ds18b20(0x44);
Delay1ms(1000);
ds18b20_reset();
write_ds18b20(0xCC);
write_ds18b20(0xBE);
temp_low=read_ds18b20();
temp_high=read_ds18b20();
temp=temp_high << 8;
temp |= temp_low;
return temp * 0.0625;
}
DS18B20 返回的温度数据是16位的 ,但单片机一次只能读取8位(1个字节),所以必须分两次读取。
要遵循LSB读取顺序
// DS18B20 先发送低字节(LSB),再发送高字节(MSB)
temp_low = read_ds18b20(); // 先读低字节
temp_high = read_ds18b20(); // 后读高字节
// 如果顺序错了:
// temp_high = read_ds18b20(); // ❌ 先读高字节 → 数据错乱
// temp_low = read_ds18b20();
7.时序逻辑
(1)复位时序

1.主机将总线拉低480---960us,发送复位脉冲,告诉从机准备复位
2.主机释放总线,交出控制权,总线呈现高水平
3.ds18b20检测到总线为高水平后,等待15---60us
4.ds18b20将总线拉低60---240us,回复响应脉冲,向主机应答
5.ds18b20释放总线,总线呈现高水平,告诉主机执行完毕
#include<reg51.h>
#include"ds18b20.h"
#include"delay.h"
#include"uart.h"
#define DQ_PIN_LOW (P3 &=~(1<<7))
#define DQ_PIN_HIGH (P3 |=(1<<7))
#define DQ_PIN_CHECK ((P3 & (1<<7))!=0) // 检测DQ引脚是否为高电平
int ds18b20_reset(void)
{
int time=0;
// 主机向ds18b20发送复位脉冲
DQ_PIN_LOW;
Delay10us(70);
DQ_PIN_HIGH;
Delay10us(5);
// 等待低电平到来,ds18b20拉低总线
while(DQ_PIN_CHECK && time<30)
{
Delay10us(1);
time++;
}
if (time >= 30)
{
uart_sendstr("wait ds18b20_low timeout!\r\n");
return -1;
}
// 等待高电平到来,ds18b20释放总线
time = 0;
while (!DQ_PIN_CHECK && time < 30)
{
Delay10us(1);
time++;
}
if (time >= 30)
{
uart_sendstr("wait ds18b20_high timeout!\r\n");
return -2;
}
return 1;
}
(2)写0时间片与写1时间片

写0时序
1.主机首先将总线拉低小于15us,告诉从机开始写数据,然后持续拉低60us,驱动 '0' 的低电平到总线上
2.ds18b20在30us---60us内进行采样,此时总线如果是低水平,则ds18b20读0
3.主机释放总线,呈现高水平
写1时序
1.主机将总线拉低小于15us,告诉从机开始写数据,然后释放总线,呈现高水平,驱动"1"电平到总线上,从机此时释放总线
2.ds18b20在拉高后45us内进行采样,此时总线如果是高水平,则ds18b20读1
void write_ds18b20(unsigned char dat)
{
int i=0;
for(i=0;i<8;i++)
{
if(dat & 1)
{
DQ_PIN_LOW;
_nop_();
_nop_();
DQ_PIN_HIGH;
Delay10us(5);
}
else
{
DQ_PIN_LOW;
Delay10us(6);
DQ_PIN_HIGH;
}
dat >>= 1;
}
}
(3)读0时间片与读1时间片

读0时序
1.主机拉低总线,持续1us,释放总线
2.ds18b20在主机释放总线后,主动拉低总线(表示传输'0')
3.主机在15us内进行采样,此时总线为低电平,主机读到0
读1时序
1.主机拉低总线,持续1us,释放总线
2..ds18b20释放总线,总线由上拉电阻拉为高电平
3.主机在15us内采样,此时总线为高电平,主机读到1
unsigned char read_ds18b20(void)
{
unsigned char dat = 0;
int i = 0;
for (i = 0; i < 8; i++)
{
DQ_PIN_LOW;
_nop_();
_nop_();
//主机发起读时序,告诉 DS18B20 "我要读数据了"
DQ_PIN_HIGH;
_nop_();
_nop_();
_nop_();
//释放总线,让 DS18B20 驱动数据线
DS18B20 会在主机释放总线后:
- 在 1-3μs 内驱动数据线
- 发送 '0':拉低总线(低电平)
- 发送 '1':释放总线(高电平)
if (DQ_PIN_CHECK) // 读到ds18b20发送的'1'
{
dat |= (1 << i);
}
Delay10us(6);
}
return dat;
}