最近把 DS18B20 的资料过了一遍,把要点记下来,免得下次又去翻手册。
一、指标参数
量程:-55℃ ~ 125℃
精度:±0.5℃(实际 25℃ 时,采回来 24.5 ~ 25.5)
分辨率:9~12 位可调,步进 0.5℃ / 0.25℃ / 0.125℃ / 0.0625℃
工作电压:3V ~ 5.5V
二、通信方式
51 和 DS18B20 是半双工、异步、串行通信,走单总线(One-Wire),一根 GPIO 就能搞定。
总线有"线与"特性,引脚拉高并不能直接决定电平------拉高其实就是释放总线。所以作为接收方的时候,要把总线释放掉,交给传感器去控制。
读回来的温度是 16 位、带符号位扩展的二进制补码。
三、采集流程
复位 → 发 0xCC 跳过 ROM → 发 0x44 开启温度转换 → 延时 750ms → 再复位 → 发 0xBE 读温度 → 连续读 2 个字节。
0xCC 就是 1100 1100。
四、时序
复位:
-
主机拉低总线 480~960us,发出复位脉冲
-
主机释放总线,等 15~60us
-
DS18B20 把总线拉低 60~240us,回响应脉冲
-
传感器释放总线,初始化结束
写:
写'0':拉低至少 60us、不超过 120us,传感器在 15~60us 内采样到低电平
写'1':拉低不足 15us 就释放,传感器采样到高电平
读:
主机先拉低总线超过 1us,再释放
读'1':传感器释放总线保持高电平,主机 15us 内采样
读'0':传感器主动拉低总线,主机 15us 内采样到低电平
五、驱动代码
#include <reg51.h>
#include <intrins.h>
sbit DQ = P2^0; // DQ接DS18B20数据线
// 简单延时(按12MHz晶振估算)
void delay_us(unsigned int n)
{
while(n--) nop();
}
void delay_ms(unsigned int n)
{
unsigned char i;
while(n--)
for(i = 0; i < 120; i++);
}
// 复位,返回0表示传感器应答
unsigned char ds18b20_reset(void)
{
unsigned char ack;
DQ = 0;
delay_us(600); // 拉低480~960us,复位脉冲
DQ = 1; // 释放总线
delay_us(30); // 等15~60us
ack = DQ; // 采样应答(拉低60~240us)
delay_us(100);
return ack;
}
// 写一个字节
void write_ds18b20(unsigned char dat)
{
unsigned char i;
for(i = 0; i < 8; i++)
{
DQ = 0;
if(dat & 0x01) // 写1:拉低<15us就释放
{
nop();
DQ = 1;
delay_us(50);
}
else // 写0:拉低60~120us
{
delay_us(70);
DQ = 1;
nop();
}
dat >>= 1;
}
}
// 读一个字节
unsigned char read_ds18b20(void)
{
unsigned char i, dat = 0;
for(i = 0; i < 8; i++)
{
DQ = 0;
nop(); // 拉低>1us后释放
DQ = 1;
nop();
dat >>= 1;
if(DQ) dat |= 0x80; // 15us内采样
delay_us(50);
}
return dat;
}
// 读取温度
float get_temperature(void)
{
unsigned char low, high;
int raw;
ds18b20_reset();
write_ds18b20(0xCC); // 跳过ROM
write_ds18b20(0x44); // 开启温度转换
delay_ms(750); // 等转换完成
ds18b20_reset();
write_ds18b20(0xCC);
write_ds18b20(0xBE); // 读温度寄存器
low = read_ds18b20();
high = read_ds18b20();
raw = (high << 8) | low; // 16位补码,符号位扩展
return raw / 16.0; // 12位分辨率,步进0.0625℃
}