DS18B20
1. DS18B20硬件设计
DS18B20供电的范围为3.0V~5.0V,也可以通过数据线供电;其分辨率可以被使用者选择为9~12位,分辨率越高,转换需要时间越长。
根据供电方式不同,DS18B20有两种典型的硬件电路接法,分别为寄生电源模式和外部电源供电模式。寄生电源的控制回路中,当总线为高电平时,电源由单总线通过VDD引脚,部分能量存储在寄生电源储能电容C内,当数据总线处于低电平时释放能量以提供给器件能量。但是,当DS18B20正在执行温度转换或从高速暂存器向EEPROM传送数据时,工作电流可能达到1.5Ma;该电流可能会引起连接单总线的弱上拉电路的不可能接受的压降,这需要更大的电流,而此时储能电容无法提供。为了保存此时DS18B20有足够的供电,当进行温度转换或者拷贝数据到EEPROM操作时,必须给单总线提供一个强上拉。
图1 寄生电源供电模式
图2 外部电源供电模式
每个DS18B20都有一个独特的64为序列号,从而允许多只DS18B20同时链接在一根单线总线上,因此可以用一个微控制器覆盖在一大片区域的DS18B20。
2. DS18B20时序
DS18B20工作协议流程一般为:初始化àROM操作指令à存储器操作指令à数据传输;其工作时序包括:初始化时序、写时序和读时序。
1) 初始化时序
微控制器首先发出一个480~960us的低电平脉冲,然后释放总线变为高电平,并在随后的480us时间内对总线进行监测,如果有低电平出现说明总线上有器件已经做出应答,如无低电平出现一直都是高电平说明总线上无期间应答。
而作为器件的DS18B20在一上电后就一直在监测总线上是否有480~960us的低电平出现,如果有,在总线转为高电平后等待15~60us将总线点平拉低60~240us做出响应存在脉冲,高度主机本器件已经做好准备,否则就一直检测等待。
图3 复位时序
void DS18B20_Reset(void)
{
DS18B20_IO_OUT();//输出
DS18B20_DQ_Low;
delay_us(480);//延时480微妙
DS18B20_DQ_High;
delay_us(480);//延时480微妙
}
2) 写时序
写周期最少为60us,最长不超过120us,写周期一开始作为主机先将总线拉低15us表示写周期开始,随后若干主机想写0,则继续拉低低电平最少60us直至写周期结束,然后释放总线为高电平;若主机想写1,在一开始拉低总线点平1us后就释放总线为高电平,一直到写周期结束。
而作为从机的DS18B20则在检测到总线被拉低后等待15us然后从15us到45us开始对总线采样,在采样期间内总线为高电平则为1,若采样期间总线为低电平则为0。
图4 写时序
void DS18B20_Write_Byte(u8 dat)
{
u8 i=0;
DS18B20_IO_OUT();//输出
for(i=0;i<8;i++)
{
DS18B20_DQ_Low; //拉低
delay_us(15);//延时15微妙
if((dat&0x01)==1)
{
DS18B20_DQ_High;
}
else
{
DS18B20_DQ_Low;
}
delay_us(60);//延时60微妙
DS18B20_DQ_High;
dat>>=1;//准备下一位数据的发送
}
}
3) 读时序
对于读数据操作时序也可分为读0和读1时序两个过程,读时序是从主机把单总线拉低之后,在1us之后就得释放单总线为高电平,以让DS18B20将数据传输到单总线上。DS18B20在检测到总线被拉低1us后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束;若是送出1则释放总线为高电平。
主机在一开始拉低总线1us后释放总线,然后在包括前面的拉低总线点平1us在内的15us时间内完成对总线进行采样检测,采样期内为低电平在确认为0,采样期间总线为高电平则确认为1,完成一个读时序,至少需要60us才能完成。
图5 读时序
u8 DS18B20_Read_Byte(void)
{
u8i=0,TempData=0;
for(i=0;i<8;i++)
{
TempData>>=1;
DS18B20_IO_OUT();//输出
DS18B20_DQ_Low; //拉低
delay_us(4);//延时4微妙
DS18B20_DQ_High;
delay_us(10);//延时10微妙
DS18B20_IO_IN();
if(GPIO_ReadInputDataBit(GPIO_DS18B20,IO_DS18B20)==1)
{
TempData|=0x80;//读数据 从低位开始
}
delay_us(45);//延时45微妙
}
returnTempData;
}
3. DS18B20的操作方法
DS18B20单线通信功能是通过分时完成的,有严格的时序概念。系统对于DS18B20的各种操作必须按照协议进行,根据DS18B20的协议规定,微控制器控制DS18B20完成温度转换必须要经过如下四个步骤:
1) 每次读写前对DS18B20进行复位初始化;
2) 发送一条ROM指令;
3) 发送存储器指令;
一般程序中对单个DS18B20进行温度转换和温度读取的流程如下:
1) 主机复位;
2) 主机写跳过ROM操作命令(CCH);
3) 主机写转换温度的操作指令,然后释放总线至少1s,让DS18B20完成转换操作。再此,需要注意的是每个命令字节在写的时候都是低字节先写。
4) 主机发送复位操作并接受DS18B20的应答脉冲;
5) 主机写跳过ROM操作命令(CCH);
6) 主机发出读取RAM的命令(BEH),随后依次读取DS18B20发出的从第0到第8共9个字节。如果只想读取温度数据,可以在读取前两个数据后不再理会后面DS18B20发出的数据即可,同样读取的数据也是地位在前。
图6 DS18B20存储器图,上电状态取决于该EEPROM中的参数值
double DS18B20_Get_wd(void)
{
u8TL=0,TH=0;
u16temp=0;
doublewd=0;
DS18B20_Reset();//复位
DS18B20_Write_Byte(0xCC);//跳过ROM命令
DS18B20_Write_Byte(0x44);//温度转换命令
delay_ms(800);//延时800毫秒
DS18B20_Reset();//复位
DS18B20_Write_Byte(0xCC);//跳过ROM命令
DS18B20_Write_Byte(0xBE);//读温度命令
TL=DS18B20_Read_Byte();//LSB
TH=DS18B20_Read_Byte();//MSB
temp=TH;
temp=(temp<<8)+TL;
if((temp&0xF800)==0xF800)//负温度判断
{
temp=~temp;
temp=temp+1;
wd=temp*(-0.0625);
}
else
{
wd=temp*0.0625;
}
return wd;
}
4. 高低温报警和测量精度的读取
void DS18B20_return_TH_TL_CONF( void )
{
chardata,data_TH,data_TL,CONF;
DS18B20_Reset();
DS18B20_write_byte(0xcc); //忽略rom指令
DS18B20_write_byte(0xbe); //读取温度转换值
data = DS18B20_read_byte();
data = DS18B20_read_byte();
data_TH = DS18B20_read_byte();
data_TL = DS18B20_read_byte();
CONF =DS18B20_read_byte();
printf("过温报警的温度为:%d℃\r\n",data_TH);
printf("低温报警的温度为:%d℃\r\n",-(data_TL-128));
CONF&=0x60 ;
CONF=CONF>>5;
switch(CONF) {
case0:
printf("DS18B20的测量精度为9位,精度为0.5℃\r\n");
break;
case1:
printf("DS18B20的测量精度为10位,精度为0.25℃\r\n");
break;
case2:
printf("DS18B20的测量精度为11位,精度为0.125℃\r\n");
break;
case3:
printf("DS18B20的测量精度为12位,精度为0.0625℃\r\n");
break;
default:
printf("error!!\r\n");
break;
}
}
void DS18B20_write_TH_TL_CONF(u8 TH,u8 TL,u8mode)
{
u8 dat;
switch(mode){
case0:
dat=31;
break;
case1:
dat=63;
break;
case2:
dat=95;
break;
case3:
dat=127;
break;
default:
printf("mode error!!\r\n");
dat=127;
break;
}
TL=TL+128;
DS18B20_Reset();
DS18B20_write_byte(0xcc); //忽略rom指令
DS18B20_write_byte(0x4e); //写入暂存寄存器 ,过温和低温报警值
DS18B20_write_byte(TH);//写入20°为过温报警值
DS18B20_write_byte(TL);//写入-20°为低温报警值
DS18B20_write_byte(dat); //写入精度
DS18B20_Reset();
DS18B20_write_byte(0xcc); //忽略rom指令
DS18B20_write_byte(0x48); //将写入的暂存寄存器拷入EEPROM
}