目标: DS18B20数字温度计(二)
2.温度读取操作
DS18B20 时序包括如下几种:初始化时序、写(0和1)时序、(0和1)时序。DS18B20发送所有的命令和数据都是字节的低位在前。
- 初始化
和I2C的寻址类似,1-Wire总线开始也需要检测这条总线上是否存在DS18B20这个器件。如果这条总线上存在DS18B20,总线会根据时序要求返回一个低电平脉冲,如果不存在的话,也就不会返回脉冲,即总线保持为高电平,所以习惯上称之为检测存在脉冲。
初始化时序此外,获取存在脉冲不仅仅是检测是否存在DS18B20,还要通过这个脉冲过程通知DS18B20准备好,单片机要进行操作它了
大家注意看图,实粗线是我们 单片机IO口拉低这个引脚,虚粗线是 DS18B20拉低这个引脚,细线是单片机和DS18B20释放总线后,依靠上拉电阻的作用把IO口引脚拉上去的。这个我们前边提到过了,51单片机释放总线就是给高电平即可。
存在脉冲检验过程,首先我们单片机要拉低这个引脚,持续时间在480us---960us(实粗线),然后单片机释放总线,就是给这个引脚高电平,持续时间在15--60us(细弧线),然后ds18b20会主动拉低这个引脚持续60--240us(虚粗线),然后ds18b20会主动释放总线,该引脚就会被上拉电阻拉成高电平
- 第一步,拉低DS18B20这个引脚,持续500us;
- 第二步,延时60us;
- 第三步,读取存在脉冲,并且等待存在脉冲结束。
uchar Ds18b20Init() //ds18b20的初始化
{
uchar i;
DSPORT = 0;
delay_10tus(50); //延时约500us(实粗线)
DSPORT = 1; //单片机释放总线就是给其高电平
delay_10tus(6); //延时是60us(细弧线)
while(DSPORT)
{
delay_1ms(1);
i++;
if(i>3) return0; //又等了3ms DSPROT还是高电平则返回0表示初始化失败
}
return 1; //DSPROT是低电平(虚粗线)表示初始化成功
}
程序中细弧线处明明是延时15--60us,为什么我们却延时60us呢?举个例子,你妈喊你去吃饭,说在15到60分钟内弄好饭,那什么时候去才能稳稳的吃到饭呢?当然是在60分钟后,饭一定弄好了,这也是同样的道理,60u后一定可以判断DSPROT的状态了。
-
写时序
写时序脉冲
前60us是写入0 , 后60us是写入1。
当给ds18b20写入0时单片机直接将引脚拉低60--120us即可。图中的意思是单片机先拉低15us后,ds18b20会在15--60us之间来读取这一位,最早会在15us处读取,所以图中MIN对应的15us处,典型值是30us的时刻读取(TYP处),最多不会超过60us(MAX处),DS18B20必然读取完毕,所以持续时间超过60us即可。
当要给DS18B20写入‘1’的时候,单片机先将这个引脚拉低,拉低时间大于1us,然后马上释放总线,即拉高引脚,并且持续时间也要大于60us。和写‘0’类似的是,DS18B20会在15到60us之间来读取这个‘1’。
可以看出来,DS18B20的时序比较严格,写的过程中最好不要有中断打断,但是在两个“位”之间的间隔,是大于1小于无穷的,那在这个时间段,我们是可以开中断来处理其他程序的。发送一个字节的数据程序如下。
- 第一步,拉低DS18B20这个引脚,持续2us;
- 第二步,判断输入的数据是0还是1,并延时60--120us
- 第三步,释放总线
- 第四步,数据右移
void Ds18b20WriteByte(uchar dat)
{
EA = 0; //关闭总中断
uint i,j;
for(j=0;j<8;j++){
DSPORT = 0;
_nop_();
_nop_(); //写入1时最少1us所以直接延时2us
DSPORT = dat&0x01; //判断数值最后一位是0还是1
delay_10tus(6); //延时60us
DSPORT = 1; //释放总线,至少1us给总线恢复时间才能接着写入第二个数值
dat >>= 1; //数值向右移一位为下次判断最后一位是0还是1做准备
}
EA = 1; //开启总中断
}
-
读时序
读时序脉冲
当要读取DS18B20的数据的时候,我们的单片机首先要拉低这个引脚,并且至少保持1us的时间,然后释放引脚,释放完毕后要尽快读取。从拉低这个引脚到读取引脚状态,不能超过15us。
大家从图可以看出来,主机采样时间,也就是控制器采样,是在15us之内必须完成的。
- 第一步,拉低DS18B20这个引脚,持续2us;
- 第二步,立马释放总线,进行读取操作
- 第三步,读取数据,从最低位开始
- 第四步,数据位置调整
uchar Ds18b20ReadByte() //单片机读取ds18b20的数据
{
uchar byte,bi;
uint i ,j;
EA = 0;
for(j=0;j<8;j++){
DSPROT = 0; //先拉低总线
_nop_();
_nop_(); //延时2us
DSPROT = 1; //释放总线
_nop_();
_nop_(); //延时2us等待数据稳定
bi = DSPROT; //读取数据,从最低位开始读取,不能延时太久不然数据会失效
byte = (byte>>1) | (bi<<7);
delay_10tus(6); //读取完之后等待60us再接着读取下一个数
}
return byte;
EA = 1;
}
byte = (byte>>1) | (bi<<7);是什么意思?比如一开始byte 是0000 0000,bi得到的是数据的最低位假如是1 则是0000 0001,那么byte>>1是0000 0000, bi<<7是1000 0000,两个一或成了1000 0000.
那么假如第二次bi还是拿到了1,是0000 0001,那么byte>>1由上面可知变成0100 0000,那么(byte>>1) | (bi<<7)是1100 0000,然后1100 0000又给了byte,这样循环8次,直到最先获取的1移到最后一位位置,for循环正好停止
网友评论