DS18B20
具体信息见数据手册:厂商Dallas Semiconductor DS18B20 数据手册
一、DS18B20介绍
DALLAS公司的DS18B20数字温度传感器是“一线总线”的典型代表,DS18B20的温度测量范围为-55℃+125℃,在-10℃+85℃范围内,精度为±0.5℃。采用“一线总线”方式传输,可以大大提高系统的抗干扰能力,所以DS18B20广泛 用于温度采集及监控领域。
目前单片机应用系统常用的串行器件有:
- 一线总线器件——DS18B20温度传感器
- 二线总线器件——iic总线器件(如采用iic形式的oled显示屏)
- 三线总线器件——DS1302时钟芯片(即SPI总线器件)
二、单总线及其扩展
1、DS18B20的引脚
实物模块图如下:
(1)VCC:供电电源输入端
(2)DQ:数字信号输入输出端
(3)GND:电源地
2、内部结构
DS18B20温度传感器主要由64位ROM、高速缓冲存储器、CRC生成器、温度敏感器件、高低温触发器及配置寄存器等部件组成。
(1)DS18B20的64位ROM
每个DS18B20都有64位的ROM,出厂之前ROM固化有确定的内容。
低八位(固定为28H)是产品类型标识号,接着的48位是该DS18B20的序列号,高8位是前面56位的循环冗余检验码。由于每个DS18B20都有自己的序列号,这样就可以实现一根总线上挂接多个DS18B20的目的。
(2)DS18B20的内存映射
在DS18B20的内部有9个字节高速缓冲存储单元。如下图所示。
- 第1及第2字节存放转换完成的温度值
- 第3及第4字节分别存放上下限报警值TH和TL
- 第5字节为配置寄存器
- 第6、7、8字节为工厂保留字节
- 第9字节是前8字节的CRC检验码(用于提高传输的可靠性)
另外在DS18B20的内部还用3个EEPROM单元存放上下限报警值TH、TL和配置寄存器的设定值。数据先写入高速缓冲存储器,然后再传给EEPROM单元。
(3)配置寄存器
配置寄存器字节的最高位D7为测试模式位,出厂时为0,用户不要改动。D6D5位用于设置DS18B20的转换分辨率,分辨率有9、10、11和12位四种选择,对应的转换时间分别为:93.73ms、187.5ms、275ms和750ms。其余的低5位为保留位(均为1)。
(出厂时默认值为7FH,即分辨率为12位 )
3、DS18B20的温度值格式
DS18B20中温度敏感元件完成对温度的检测,转换后的温度值以带符号扩展的二进制补码(16位)形式存储在高速缓冲存储器的第1和第2字节中。温度值以0.0625℃/LSB形式表达。(LSB即Least Significant Bit,意为最低有效位)。采样值与温度值的关系:
二进制采样值 | 十六进制表示 | 十进制温度/℃ |
---|---|---|
0000 0111 1101 0000 | 07D0 H | +125 |
0000 0001 1001 0001 | 0191 H | +25.0625 |
0000 0000 1010 0010 | 00A2 H | +10.125 |
0000 0000 0000 1000 | 0008 H | +0.5 |
0000 0000 0000 0000 | 0000 H | 0 |
1111 1111 1111 1000 | FFF8 H | -0.5 |
1111 1111 0101 1110 | FF5E H | -10.125 |
1111 1110 0110 1111 | FE6F H | -25.0625 |
1111 1100 1001 0000 | FC90 H | -55 |
12位分辨率时的温度值格式如下图:
当符号位S为0时,表示温度为正,只要将二进制采样值转换为十进制数就可以得到十进制表示的温度值;
当符号位S为1时,表示温度为负(用补码表示),这时要对读取的采样值取补(取反加1),再转换为十进制数才能得到十进制表示的温度值。
三、DS18B20的操作命令
1、ROM操作命令
ROM命令主要用于一线总线上接有多个DS18B20的情况,ROM操作命令与总线上具体DS18B20器件的序列号相关。
ROM操作命令:
指令 | 代码 | 说明 |
---|---|---|
读 ROM | 33 H | 读总线上DS18B20的序列号 |
匹配 ROM | 55 H | 依序列号访问确定的DS18B20器件 |
跳过 ROM | CC H | 只使用RAM命令,操作在线的DS18B20器件 |
搜索 ROM | F0 H | 对总线上的多个DS18B20进行识别 |
报警搜索 | EC H | 主机搜索越限报警的DS18B20器件 |
2、RAM操作命令
单片机利用ROM操作命令,与总线上指定的DS18B20器间建立起联系后,就可以对这个指定器件实施RAM操作命令。
这些操作命令允许单片机写入或读出DS18B20器件缓冲器的内容。
指令 | 代码 | 说明 |
---|---|---|
温度转换 | 44 H | 启动DS18B20开始转换 |
读缓冲器 | BE H | 读缓冲器的9个字节数据 |
写缓冲器 | 4E H | 向DS18B20写TH、TL及配置寄存器数据 |
复制缓冲器 | 48 H | 将缓冲器的TH、TL和配置寄存器值送EEPROM |
回读EEPROM | B8 H | 将EEPROM中的TH、TL和配置寄存器值送缓冲器 |
读供电方式 | B4 H | 检测供电方式:寄生或外接方式 |
四、操作时序
在一线总线传输数据时,逻辑0用一段持续的低电平表示,逻辑1用一段持续的高电平表示。单片机向DS18B20器件传输数据时产生写时隙,单片机从DS18B20器件读取数据时产生读间隙。读间隙和写间隙均以单片机驱动总线产生低电平开始。
1、初始化时序
单片机与DS18B20器件进行通信是以初始化开始的,初始化序列包括单片机产生复位脉冲和DS18B20器件回应的应答脉冲。当DS18B20发送存在脉冲响应复位时,它指示主机它在总线上并准备好操作。
在初始化序列中,总线主机通过将1线主机拉低至少480us来发送(Tx)复位脉冲。然后单片机释放总线,进入接收模型(Rx)。当总线释放时,上拉电阻将1线总线拉高。当DS18B20检测到上升沿时,它等待15us到60us,DS18B20器件收到单片机发来的复位脉冲后,向总线回应应答脉冲,应答脉冲会使总线拉低60~240us。
2、读写时序
总线在写时隙向DS18B20写入数据,并在读时隙从DS18B20读取数据。每个时隙都有一位数据通过。
1、写时序
写时隙有两种类型:写1时隙和写0时隙。这两种写时隙都是由主机拉低单线总线发起的。总线使用写1时隙向DS18B20写入逻辑1,使用写0时隙向DS18B20写入0。
所有写时隙必须至少有60us的持续时间,并且每个写时隙之间至少有1us的恢复时间。对于写0时隙,单片机拉低总线并保持低电平至少60us,然后释放总线;对于写1时隙,单片机拉低总线,然后在15us内要释放总线。
DS18B20在master启动写时隙后,在一个持续时间从15us到60us的窗口中对1-WIRE总线进行采样。如果总线在采样窗口期间是高,则1被写入DS18B20。
3、读时序
DS18B20只能在单片机发出读取时隙向单片机传输数据。因此,单片机必须在发出Read Scratchpad [BE H]或Read Power Supply [B4 H]命令后立即生成读时隙,以便DS18B20能够提供所请求的数据。此外单片机可以在发出Convert T [44 H]或Recall E2 [B8 H]命令后生成读时点,以了解操作状态。
所有读时隙的持续时间必须至少为60us,时隙之间的恢复时间必须至少为1us。一个读时隙是由主设备将1-wire总线拉低一个最小逻辑单元,然后释放总线发起的。在主机启动读取时隙后,DS18B20将开始在总线上发送1或0。DS18B20通过使总线保持高电平来发送1,通过拉低总线来发送0。当发送0时,DS18B20将在时隙结束时释放总线,总线将被上拉电阻拉回其空闲状态。
输出DS18B20的数据在下降沿启动读取时隙对15us有效,所以单片机应在15us内采样总线电平。
五、参考程序(针对51的)
DS18B20.c
#include "reg52.h"
#include "DS18B20.h"
#include "delay.h"
//IO接口定义
sbit DQ = P2^6; //定义DS18B20端口DQ
unsigned char RomCode[8];
int Real_temp; //实际温度值
/*******************************************************************/
/* */
/*初始化ds1820 */
/* */
/*******************************************************************/
unsigned char Init_DS18B20(void)
{
unsigned char presence = 0;
DQ = 1; //DQ复位
Delay(8); //稍做延时
DQ = 0; //单片机将DQ拉低
Delay(80); //精确延时 大于 480us
DQ = 1; //拉高总线
Delay(8);
presence = DQ; //如果=0则初始化成功 =1则初始化失败
Delay(4);
DQ = 1;
return(presence); //返回信号,0=presence,1= no presence
}
/*******************************************************************/
/* */
/* 读一个字节 */
/* */
/*******************************************************************/
unsigned char ReadOneChar(void)
{
unsigned char i = 0;
unsigned char dat = 0;
for (i = 8; i > 0; i--)
{
DQ = 0; // 给脉冲信号
dat >>= 1;
DQ = 1; // 给脉冲信号
if(DQ)
dat |= 0x80;
Delay(4);
}
return (dat);
}
/*******************************************************************/
/* */
/* 写一个字节 */
/* */
/*******************************************************************/
void WriteOneChar(unsigned char dat)
{
unsigned char i = 0;
for (i = 8; i > 0; i--)
{
DQ = 0;
DQ = dat&0x01;
Delay(4);
DQ = 1;
dat>>=1;
}
Delay(4);
}
/*******************************************************************/
/* */
/* 温度报警值写入DS18B20 */
/* */
/*******************************************************************/
void Write_Temperature_alarm(unsigned char Temp_h , unsigned char Temp_l)
{
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0x4e); //将设定的温度报警值写入 DS18B20
WriteOneChar(Temp_h); //写TH
WriteOneChar(Temp_l); //写TL
WriteOneChar(0x7f); //12位精确度
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0x48); //把暂存器里的温度报警值拷贝到EEROM
}
/*******************************************************************/
/* */
/* 读取64位序列码 */
/* */
/*******************************************************************/
void Read_RomCord(void)
{
unsigned char j;
Init_DS18B20();
WriteOneChar(0x33); // 读序列码的操作
for (j = 0; j < 8; j++)
{
RomCode[j] = ReadOneChar() ;
}
}
/*******************************************************************/
/* */
/*DS18B20的CRC8校验程序 */
/* */
/*******************************************************************/
unsigned char CRC8()
{
unsigned char i,x;
unsigned char crcbuff,crc;
crc=0;
for(x = 0; x <8; x++)
{
crcbuff=RomCode[x];
for(i = 0; i < 8; i++)
{
if(((crc ^ crcbuff)&0x01)==0)
crc >>= 1;
else {
crc ^= 0x18; //CRC=X8+X5+X4+1
crc >>= 1;
crc |= 0x80;
}
crcbuff >>= 1;
}
}
return crc;
}
/*******************************************************************/
/* */
/* 读取温度 */
/* */
/*******************************************************************/
unsigned char Read_Temperature(void)
{
unsigned char i;
unsigned char temp_comp;
unsigned char temp_data[2];
unsigned char temp_alarm[2];
unsigned int t;
t = Init_DS18B20();
if(t) return Real_temp;
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0x44); //启动温度转换
t = Init_DS18B20();
if(t) return Real_temp;
// WriteOneChar(0x55); //匹配ROM命令
// for(i=0;i<8;i++)
// WriteOneChar(RomCode[i]);
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
temp_data[0] = ReadOneChar(); //温度低8位
temp_data[1] = ReadOneChar(); //温度高8位
temp_alarm[0] = ReadOneChar(); //温度报警TH
temp_alarm[1] = ReadOneChar(); //温度报警TL
temp_comp=((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4);//取温度整数值
return temp_comp;
}
DS18B20.h
#ifndef _DS18B20_H_
#define _DS18B20_H_
unsigned char ReadOneChar(void);
void WriteOneChar(unsigned char dat);
void Write_Temperature_alarm(unsigned char Temp_h , unsigned char Temp_l);
void Read_RomCord(void);
unsigned char CRC8();
unsigned char Read_Temperature(void);
int ReadTemperature(void);
extern Real_temp;
#endif
delay.c
#include "delay.h"
/*******************************************************************************
* 函 数 名 :Delayms
* 函数功能 :实现 ms级的延时
* 输 入 :ms
* 输 出 :无
*******************************************************************************/
void Delayms(unsigned int ms)
{
unsigned int i,j;
for(i=0;i<ms;i++)
#if FOSC == 11059200L
for(j=0;j<114;j++);
#elif FOSC == 12000000L
for(j=0;j<123;j++);
#elif FOSC == 24000000L
for(j=0;j<249;j++);
#else
for(j=0;j<114;j++);
#endif
}
/*******************************************************************/
/* */
/*us级延时函数 */
/* */
/*******************************************************************/
void Delay(unsigned int num)
{
for(;num>0;num--);
}
delay.h
#ifndef _DELAY_H_
#define _DELAY_H_
#define uint unsigned int
#define uchar unsigned char
//#define FOSC 11059200L //晶振设置,默认使用11.0592M Hz
#define FOSC 12000000L //晶振设置,使用12M Hz
//#define FOSC 24000000L //晶振设置,使用24M Hz
void Delayms(unsigned int ms); // 11.0592MHz
void Delay(unsigned int num);
#endif