文章目录

一、数字温度传感器DS18B20
应用:设备温度 环境温度
二、传感器指标参数
-
量程
(测量范围):-55℃ - 125℃
-
精度
(传感器测量的温度与实际温度值之间所允许的最大误差):±0.5℃
-
分辨率
(传感器对温度变化的敏感程度):分辨率越高,能察觉到越微小的温度变化,读数越细腻。
9位:0.5℃
10位:0.25℃
11位:0.125℃
12位:0.0625℃(默认分辨率)
-
工作电压
3V - 5.5V
三、51单片机与DS18B20通信
半双工、异步通信、串行

GPIO One-Wire 单总线:传感器与单片机通过一根GPIO进行通信


四、线与特性

引脚拉高,不能直接决定引脚电平
释放总线:在传感器通信中,将引脚拉高这一行为称为释放总线。
你作为数据的接收方时,需要释放总线
五、温度读数
(两字节):16位、符号位扩展、二进制补码
六、DS18B20采集温度流程

七、DS18B20复位时序

复位时序:
-
主机将总线拉低480-960us,发送复位脉冲
-
主机释放总线,延时15-60us
-
DS18B20将总线拉低60-240us,回复响应脉冲
-
DS18B20释放总线,总线呈现高电平,初始化过程结束。
八、DS18B20读写时序

写时序:
-
写'0'时序:
a. 主机将总线拉低至少60us,最多不超过120us
b. ds18b20在15us-60us内进行采样,若总线此时为低电平,则代表主机发送了'0'
c. 主机释放总线
-
写'1'时序:
a. 主机将总线拉低小于15us,释放总线
b. ds18b20在15us-60us内进行采样,若此时为高电平,则代表主机发送了'1'
读时序:
-
读'1'时序:
a. 主机拉低总线,大于1us,然后释放总线
b. ds18b20释放总线,总线呈现高电平
c. 主机在15us内采样电平,此时总线为高电平,代表主机读到'1
-
读'0'时序:
a. 主机拉低总线,大于1us,然后释放总线
b. ds18b20在主机释放总线后,主动拉低(代表要传输'0)
c. 主机在15us内进行采样,此时总线为低电平,代表主机读到'0
九、代码示例
下面的代码以 P3.7 作为单总线 DQ 引脚,封装了单总线复位、写字节、读字节底层时序函数,复位函数完成总线复位并检测传感器应答,超时就串口输出错误信息;写、读函数按照 DS18B20 单总线时序逐位收发数据,低位优先;get_temp 函数先复位传感器,发送跳过 ROM 命令与温度转换命令,延时等待转换结束,再次复位后发送读寄存器指令,读取温度高低字节拼接成 16 位原始数据,最后乘以 0.0625 换算成实际摄氏温度并返回浮点温度值,适用于单 DS18B20 测温场景。
c
#include <reg51.h>
#include <intrins.h>
#include "ds18b20.h"
#include "delay.h"
#include "uart.h"
#define DQ_PIN_LOW (P3 &= ~(1 << 7)) // DQ引脚拉低
#define DQ_PIN_HIGH (P3 |= (1 << 7)) // DQ引脚拉高
#define DQ_CHECK ((P3 & (1 << 7)) != 0) // 判断DQ引脚为高电平
// ds18b20 复位
int ds18b20_reset(void)
{
int time = 0;
// 主机向ds18b20发送复位脉冲
DQ_PIN_LOW;
Delay10us(70);
DQ_PIN_HIGH;
Delay10us(6);
// 等待低电平到来 (超时时间)
while (DQ_CHECK && time < 30)
{
Delay10us(1);
time++;
}
if (time >= 30)
{
uart_sendstr("wait ds18b20_low timeout!\n");
return -1;
}
// 等待高电平到来
time = 0;
while (!DQ_CHECK && time < 30)
{
Delay10us(1);
time++;
}
if (time >= 30)
{
uart_sendstr("wait ds18b20_high timeout!\n");
return -2;
}
return 1;
}
// 主机发送一个字节
void write_ds18b20(unsigned char dat)
{
int i = 0;
for (i = 0; i < 8; i++)
{
if (dat & 1) // 写1
{
DQ_PIN_LOW;
_nop_();
_nop_();
DQ_PIN_HIGH;
Delay10us(6);
}
else // 写0
{
DQ_PIN_LOW;
Delay10us(6);
DQ_PIN_HIGH;
}
dat >>= 1;
}
}
// 主机读取一个字节
unsigned char read_ds18b20(void)
{
unsigned char dat = 0;
int i = 0;
for (i = 0; i < 8; i++)
{
DQ_PIN_LOW;
_nop_();
_nop_();
DQ_PIN_HIGH;
_nop_();
_nop_();
_nop_();
// 代表读到1
if (DQ_CHECK)
{
dat |= (1 << i);
}
Delay10us(6);
}
return dat;
}
// 读取ds18b20温度
float get_temp(void)
{
unsigned char temp_low = 0;
unsigned char temp_high = 0;
short temp = 0;
ds18b20_reset(); // 复位
write_ds18b20(0xCC); // skip ROM
write_ds18b20(0x44); // 开启温度转换
Delay1ms(1000); // 等待温度转换完毕
ds18b20_reset(); // 复位
write_ds18b20(0xCC); // skip ROM
write_ds18b20(0xBE); // 读取温度
temp_low = read_ds18b20(); // 读取温度低位
temp_high = read_ds18b20(); // 读取温度高位
// 2个字节温度值
temp = temp_high << 8;
temp |= temp_low;
return temp * 0.0625;
}