一、初始化,如图一
数据线拉低至少480us后再将其拉高,大约等待15~60us,就会收到60~240us的低电平的存在脉冲,其后数据线会恢复被拉高状态,在数据线被拉高到初始化结束经过的时间至少为480us,以下是我根据对初始化时序写的子程序,用的是51:
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
void delay1(uint z)//延时子程序
{ uint x,y;
for(x=10;x>0;x--)
/*z=1时,延时子程序用时约为61.5US*/
{
for(y=z;y>0;y--);
}
}
void reset()
{ uint i;
DQ=1;
i++;
DQ=0;
delay1(120);//软件仿真测试为495us
DQ=1;
for(i=65;i>0;i--)
{ //i这个数值可以改,for语句只是作为收到存在脉冲时的延时只要满足>60us就可以
if(!DQ)break;
//当收到存在脉冲时跳出循环
}
delay1(120);
//大于480us
}
其实这个子程序并没考虑到干扰,因为假设在初始化过程有低电平脉冲的干扰,那么即使ds18b20没有发送低电平,也会认为初始化成功。
一、二、写时隙
(1)写1时隙,如上右图:主控器将数据线拉低至少1us,并在拉低后的15us内再将其拉高,整个过程大于60us,子程序如下
uchar bit1_write18b20()
{uint i=0;
DQ=1;
i++;
DQ=0;
for(i=0;i<1;i++);
//for(i=0;i<1;i++)约为12.94us
DQ=1;
for(i=0;i<4;i++);
//约为51us,整个过程大于60us
return(DQ);
}
(2)写0时隙,如上左图,主控器将数据线拉低至少60us后将其拉高,子程序如下:
uchar bit0_write18b20()
{uint i=0;
DQ=1;
i++;
DQ=0;
for(i=0;i<5;i++);//大于60us
return(DQ);
}
一、三、读时隙
我发 很多人被时序图的阴影部分吓到了,其实这表示数据线的在这个时间段状态不确定,整个时序图的意思是主控制器将数据线拉高至少1us后,再将其拉低,在拉低后15us内的数据有效,整个时隙时间要大于60us.
虽然pdf中,用两个时序图分别表示读0时隙和读1时隙,实际上读一位数的子程序只要一个,数据线拉低后1us,将数据线拉高,在15us内储存数据,再延时,使其满足总时间大于60us,下面给个例子:
uchar bit_read18b20(void)
{ uint i;
uint k;
DQ=1;
k++;
DQ=0;
for(i=0;i<1;i++);
/*for(i=0;i<1;i++)约为12.94us*/
DQ=1;
/*60us*/
return(DQ);
}
一、四、写、读一个字节数子程序:
/*写一字节数*/
void byte_write18b20(uint w)
{ uint i=0;
bit b;
for(;i<8;i++)
{
b=w&0x01;
if(b)bit1_write18b20();
else bit0_write18b20();
w=w>>1;
}
}
/*读一字节*/
uchar byte_read18b20(void)
{
uchar i;
uint k;
uchar
value=0;
for(i=0;i<8;i++)
{
if(bit_read18b20())value|=(0x01<<i);
for(k=0;k<6;k++);
//延时使其满足读时隙时间
}
return(value);
}
五、温度转换和显示那些子程序有很多,在这里就不重复了,接下来再写几个其他的子程序(单个ds18b20):
(1)/*电源模式读取*/
unsigned int Readpower( )
{
unsigned int t=0;
reset();
byte_write18b20(0xCC);//skip rom
byte_write18b20(0xB4);
t=bit_read18b20();
return(t);
}
(2)/*将快速暂存寄存器的TH,TL和配置寄存器复制到EEPROM*/
void copyRam()
{
reset();
byte_write18b20(0xCC);
byte_write18b20(0x48);
}
说明:这个指令与WRITE SCRATCHPAD(4Eh)指令结合可以将所要设置的温度上下限值写入ds18b20中的eeprom中,实现断电后所设置的数值仍然保存,可已通过这种方式做一个可报警的温度计,下面给个例子:
void send(uchar TH,ucharTL)//将要写的温度上下限值存入EEPROM
{
reset();
byte_write18b20(0xCC);
byte_write18b20(0x4E);
byte_write18b20(TH);
byte_write18b20(TL);
byte_write18b20(0x00);
reset();
byte_write18b20(0xCC);
byte_write18b20(0x48);
reset();
}
(3)读单个ds18b20的序列号子程序
uint a[7];
uint b[7];
void num_read()
{
reset();
byte_write18b20(0x33);
for(i=0;i<8;i++)
{
g=byte_read18b20();
a=g/16;
//16进制存入,这个是为了方便我用来显示的,只作参考
b=g%16;
}
}
对于ds18b20,有一点遗憾的是alarm search(ECh)指令并没有试出来,据说是当ds18b20的温度超过所设置的温度范围时,会返回唯一的ID即序列号,但无论我怎么弄,读取的数值各个位都是一,也有可能是我只用一个ds18b20的原因,希望有用过ds18b20的大侠指教一下alarm search的用法
|