DS18B20是一种数字温度传感器,由美国达拉斯半导体公司生产。
具有以下特征:
1. 单线传输:DS18B20使用单线传输协议(1-Wire)进行通信,只需要一个数据线就可以实现数据传输和电源供应。
2. 高精度:DS18B20可以测量范围为-55°C至+125°C的温度,精度为±0.5°C(在-10°C至+85°C范围内)。
3. 数字输出:DS18B20输出数字温度值,可以直接与数字系统集成,不需要进行模拟信号转换。
4. 多点测量:通过1-Wire总线,可以连接多个DS18B20传感器,实现多点温度测量。
5. 低功耗:DS18B20具有低功耗特性,工作时只需要极低的能量,可以通过1-Wire总线实现供电。
6. 内部存储:DS18B20具有内部存储器,可以存储自身序列号和温度校准系数等信息,方便管理和配置。
管脚描述
VDD 引脚。当采用“寄生电源”供 电时,VDD 必须连接到地 | VDD |
数据输入/输出。1-Wire 漏极开路接口引脚。当采用“寄生电源”供电方式时,同时向设备提供电源。 | DQ |
地 | GND |
内部结构框图
寄生电源电路 | 控制寄生电源供电或者VDD供电 |
64位Bit ROM | 作为器件地址,用于总线通信的地址 |
内存控制逻辑单元 | 控制Read or Write |
暂存器 | 用于总线的数据交互(RAM) |
供电方式
单总线电路规范
- 设备的DQ均要配置成开漏输出模式
- DQ添加一个4.7KΩ的上拉电阻
- 若总线的从机采取寄生供电,则主机还应该配置一个强上拉输出
DS18B20操作流程
- 初始化:从机复位,主机判断从机是否相应
- ROM操作:ROM指令+本指令需要的读写操作
- 功能操作:功能指令+本指令需要的读写操作
ROM指令
搜索ROM[F0h] | 匹配ROM[55h] |
读取ROM[33h] | 跳过ROM[CCh] |
警报搜索[ECh] |
功能指令
温度转换[44h] | 写入暂存寄存器[4Eh] |
读取暂存寄存器[BEh] | 拷贝暂存寄存器[48h] |
召回 EEPROM[B8h] | 读取供电模式[B4h] |
单总线时序结构
初始化
在初始化序列期间,总线上的主设备通过拉低 1-Wire 总线超过 480us 来发送(TX)复位脉冲。 之后主设备释放总线而进入接收模式(RX)。当总线释放后,5kΩ左右的上拉电阻将 1-Wire 总线 拉至高电平。当 DS18B20 检测到该上升边沿信号后,其等待 15us 至 60us 后通过将 1-Wire 总线拉 低 60us 至 240us 来实现发送一个存在脉冲。
写入一位
写时段有两种情况:“写 1”时段和“写 0”时段。
为了形成写 1 时段,在将 1-Wire 总线拉低后,主设备必须在 15us 之内释放总线。当总线释放后,5kΩ的上拉电阻将总线拉至高。
为了形成写 0 时段,在将 1-Wire 总线拉低后,在整个时段 期间主设备必须一直拉低总线(至少 60us)
在主设备初始化写时段后,DS18B20 将会在 15us 至 60us 的时间窗口内对总线进行采样。如果总线在采样窗口期间是高电平,则逻辑 1 被写入 DS18B20;若总线是低电平,则逻辑 0 被写入 DS18B20。
读出一位
主设备在执行完读暂存寄存器[BEh] 或读取供电模式[B4h]后,必须及时地生成读时段,这样 DS18B20 才能提供所需的数据。
每个读时段最小必须有 60us 的持续时间且独立的写时段间至少有 1us 的恢复时间。
读时段通 过主设备将总线拉低超过 1us 再释放总线来实现初始化。当主设备初始化完读时段后, DS18B20 将会向总线发送 0 或者 1。
从 DS18B20 中输出的数据在初始化读时序后仅有 15us 的有效时间。因此,主设备 在开始读时段后的 15us 之内必须释放总线,并且对总线进行采样。
写入一个字节
写入一位×8
读出一个字节
读出一位×8
温度存储格式
温度是以一个Byte的LSB和MSB共同存储。
其中MSBtye的前5位是符号位,都为0则为正,都为1则为负;LSByte的后四位为小数位。
所以要读取到完整的温度,先将LSByte和MSByte合并(MSB左移八位, | 上LSByte存储到int类型的变量中),但又因为LSB后四位为小数位,和正常的八位二进制相对比,等于将2的零次方向左移动了四位,扩大了16倍,所以要将int类型的变量除以16,但为保持精度(小数位),应除以16.0.
代码(不同模块)
使用STC89C52RC
/*
读写一位和一个字节模块
*/
#include <REGX52.H>
sbit OneWire_DQ = P3^7;
/**
* @brief 初始化
* @param 无
* @retval AckBit 1为从机不存在 0为从机存在(发送了一个存在脉冲)
*/
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char AckBit;
OneWire_DQ = 1;
OneWire_DQ = 0;
//Delay 500us
i = 247;while (--i);
OneWire_DQ = 1;
//Delay 70us
i = 32;while (--i);
AckBit = OneWire_DQ;
//Delay 500us
i = 247;while (--i);
return AckBit;
}
/**
* @brief 写入一位数据
* @param Bit 要写入的一位数据
* @retval 无
*/
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
OneWire_DQ = 0;
i = 4;while (--i); //Delay 10us
OneWire_DQ = Bit;
i = 24;while (--i); //Delay 50us
OneWire_DQ = 1;
}
/**
* @brief 接收一位数据
* @param 无
* @retval Bit 接收的一位数据
*/
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i;
unsigned char Bit;
OneWire_DQ = 0;
i = 2;while (--i); //Delay 5us
OneWire_DQ = 1;
i = 2;while (--i); //Delay 5us
Bit = OneWire_DQ;
i = 24;while (--i); //Delay 50us
return Bit;
}
/**
* @brief 发送一个字节的数据
* @param 要发送的一个字节的数据
* @retval 无
*/
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0; i<8; i++)
{
//低位在前
OneWire_SendBit(Byte & (0x01 << i));
}
}
/**
* @brief 接收一个字节的数据
* @param 无
* @retval Byte 接收的一个字节的数据
*/
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i;
unsigned char Byte = 0x00;
for(i=0; i<8; i++)
{
if(OneWire_ReceiveBit())
{
//低位在前
Byte |= 0x01 << i;
}
}
return Byte;
}
/*
DS18B20温度变换与温度读取
*/
#include <REGX52.H>
#include "OneWire.h"
#define DS18B02_SKIP_ROM 0xCC
#define DS18B02_CONVERT_T 0x44
#define DS18B02_READ_SCRATCHPAD 0xBE
/**
* @brief 温度转换
* @param 无
* @retval 无
*/
void DS18B20_ConvertT(void)
{
OneWire_Init();
OneWire_SendByte(DS18B02_SKIP_ROM);
OneWire_SendByte(DS18B02_CONVERT_T);
}
/**
* @brief 读出暂存寄存器
* @param 无
* @retval T 温度寄存器中的数据
*/
float DS18B20_ReadT(void)
{
unsigned char TLSB, TMSB;
int Temp;
float T;
OneWire_Init();
OneWire_SendByte(DS18B02_SKIP_ROM);
OneWire_SendByte(DS18B02_READ_SCRATCHPAD);
TLSB = OneWire_ReceiveByte();
TMSB = OneWire_ReceiveByte();
Temp = (TMSB << 8) | TLSB;
T = Temp / 16.0;
return T;
}
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "OneWire.h"
#include "DS18B20.h"
float T;
void main()
{
DS18B20_ConvertT();
Delay(1000);
LCD_Init();
while(1)
{
KeyNum = Key();
DS18B20_ConvertT();
T = DS18B20_ReadT();
if(T<0)
{
LCD_ShowChar(2,1,'-');
T = -T;
}
else
{
LCD_ShowChar(2,1,'+');
}
LCD_ShowNum(2,2,T,3);
LCD_ShowChar(2,5,'.');
LCD_ShowNum(2,6,(unsigned long)(TShow*10000)%10000,4);//取出小数点后四位
}
}
使用DS18B20的核心就是掌握时序的Delay以实现不同功能。
菜鸡扩展:如果1-Write上有多个DS18B20,则不能直接跳过ROM,要先搜索ROM(使得主设备确定总线上所有的从设备(好像要用到二叉搜索树算法)),再通过ROM编码去匹配ROM匹配不同的从机(发送64位的ROM编码,去匹配特定的从机),使得能让特定的从机执行特定的功能。
该文只是基于一个DS18B20,所以可以直接跳过ROM,或者能去直接读取ROM。