BXAK 发表于 2012-5-7 23:38:52

转载:DS18B20多点测温网络的三种方法

原文:多个DS18B20 ROM自动搜索 展示

多点测温网络的三种方法:
㈠ 先读出每个DS18B20的64位ROM码,然后写到程序中进行匹配

方法:
   在硬件系统搭建完成时在总线上每次挂接一个DS18B20,对该DS18B20发送读取ROM序列号命令(0x33),这样DS18B20就按照从高位到低位的顺序发送8字节地址到总线上,单片机依次读取、保存即可得到一个DS18B20的序列号。然后在总线上单独挂接另一个DS18B20芯片得到该芯片的序列号。有了这些序列号后,将这些序列号固化在程序中(如数组、查表),当单片机向总线发送匹配ROM命令之后紧跟发送一个序列号,这样接下去的读取温度操作将只有ROM序列号匹配的那个DS18B20做出相应的操作。

㈡ 每一个I/O口可挂一个DS18B20,如一种快速查询多点DS18B20温度的方法

㈢ 利用SEARCH ROM 指令 动态搜索64位ROM码(二叉树遍历)

SEARCH ROM指令:发出search rom 指令后,ds18b20将所有的第一位0,0,0放到总线上,单片机读到的是相与的结果为0.接着ds18b20将所有器件的第一位的补码1,1,1放到总线上,单片机读到的数据是相与的结果为1.等待主机响应之后,继续将下一位及其反码,发送到总线上。
每次读ds18b20发出的两位会得到00,01,10,11的结果其含义如下:
   00:挂在总线上的ds18b20在这一位上有冲突, 即有的在这一位上为0, 有的在 这一位上为1。
   01:所有DS18B20此位数据均为0
   10:所有DS18B20此位数据均为1
   11:没有DS18B20
ROM 搜索过程是简单三步过程的重复:
      (1)读一位(2)读核位的补码
      (3)写所需的那一位的值:
       发0, 则选中这一位为0的ds18b20, 在此后的过程中, 仅这一位为0的ds18b20参与向总线收发数据。如发1, 则选中这一位为1的ds18b20, 在此后的过程中, 仅这一位为1的ds18b20参与向总线收发数据。
       总线主机在ROM 的每一位上完成这简单的三步过程。在全部过程完成之后总线主机便知道一个器件中ROM 的内容。

……

hamipeter 发表于 2012-5-12 00:50:15

沙发!!!

zhenglu891028 发表于 2012-5-15 17:57:09

谢谢奉献

jetli 发表于 2012-5-16 12:01:41

http://hi.baidu.com/liuqyi/item/6f30ca5c7928a916da16358e

有帖子力原程序么?{:sweat:},(3)搜索算法

BXAK 发表于 2012-5-16 13:14:45

本帖最后由 BXAK 于 2012-5-16 13:17 编辑

jetli 发表于 2012-5-16 12:01 static/image/common/back.gif
http://hi.baidu.com/liuqyi/item/6f30ca5c7928a916da16358e

有帖子力原程序么?,(3)搜索算法 ...

网上有,

有账号直接下源程序+仿真:
http://www.pudn.com/downloads346/sourcecode/embedded/detail1511016.html
http://download.csdn.net/detail/chenwen112/3233780

没账号只有参考程序:
ds18b20二叉树搜索算法

1 单总线技术

    单总线技术搜索ROM的过程是主设备获取单总线上从器件的注册码的过程,是一种简单的三步操作过程的重复,即先读一位,其次读该位的反码,然后再写一位,选中其中的一部分器件(详见参考文献)。重复执行这三步操作,可获得设备注册码其余各位。

    根据每两次读的数据可作如下判断:

    00:总线上有器件,且它们的注册码在该位既有“1”,也有“0”;

    01:总线上器件的注册码在该位是“1”;

    10:总线上器件的注册码在该位是“0”;

    11:总线上没有器件。

2 二叉树搜索算法

    二叉树(binary tree)是n(n≥0)个结点的有限集合,由一个根结点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成,且左子树和右子树有严格的区分。

    遍历一棵二叉树就是按某种次序系统地访问二叉树上的所有结点,并且每个结点只允许访问一次。遍历运算的关键在于访问结点的次序,应保证二叉树上每个结点均被访问且仅被访问一次(详见参考文献)。

3 二叉树搜索算法的应用

    根据多个单总线器件注册码所构成的数据结构和二叉树的特点,可认为单总线上所有器件注册码构成了一个深度为64的二叉树(相关资料见参考文献),在遍历二叉树的过程中可根据读取的两次数据判断结点是左子结点、右子结点还是叶子结点,即:

    00:表示既存在左子结点,也存在右子结点,该位有“0”,也有“1”;

    01:表示只存在左子结点,该位为“0”;

    10:表示只存在右子结点,该位为“1”。

    11:表示不存在子结点,也就说明没有从器件挂接在总线上。

    在遍历二叉树时,记录所走的路径和搜索到的叶子结点数,可以得到从器件的注册码和从器件数量。

    第一次搜索从器件的注册码时,如果左子结点和右子结点都存在,需要记录该分叉结点的深度,并沿左子树的方向向下搜索,当搜索深度达到64时,获得一个从器件的注册码,并取出该搜索路径最后的分叉结点的深度,然后主器件执行第二次搜索过程。在该搜索过程中,如果结点的深度值小于最后一个分叉结点的深度,则发送上次搜索到的在最后一个分叉结点前的注册码的相应位;如果结点的深度值等于最后一个分叉结点的深度,则发送上次搜索到的在最后一个分叉结点处发送的数据的反码,并且删除该分叉结点的记录,如在后面的搜索中遇到分叉结点,同样需要记录分叉结点的深度。这样,每搜索到一个深度为64的叶子结点,就会得到一个从器件的注册码,一直搜索到记录中没有分叉结点为止。//============================================================
//工程名称:    DS18B20
//功能描述:    DS18B20底层for 89s52
//日期:         2009.7.4~6
//http://hi.baidu.com/lyb1900
//============================================================
#include<REG52.H>
#include<math.h>
#include<INTRINS.H>

#define uchar unsigned char
#define uintunsigned int;
unsigned charID0,ID1,ID2,ID3,ID4,ID5,ID6,ID7;//传感器2
//uchar serial1;
uchar serial;
uchar read_bit;
//uchar flag=0;
extern term;
sbit DQ=P1^7;          //ds18b20 数据端口
//uchar term;
//ROM操作指令////////////////////////////////////////////////////////////////
//读ROM
#define   READ_ROM                0x33
//匹配ROM
#define      MATCH_ROM               0x55
//跳过ROM
#define       SKIP_ROM                0xcc
//搜索ROM
#define       SEARCH_ROM               0xf0
//告警搜索
#define      ALARM_SEARCH            0xec

//存储器操作指令
//写暂存存储器
#define      WRITE_SCRATCHPAD       0x4e
//读暂存存储器
#define      READ_SCRATCHPAD      0xbe
//复制暂存存储器
#define      COPY_SCRATCHPAD      0x48
//温度变换
#define       CONVERT_TEMPERATURE   0x44
//重新调出
#define       RECALL_EPROM            0xb8
//读电源
#define       READ_POWER_SUPPLY    0xb4   
//////////////////////////////////////////////////////////////////////////////////////

/*************************************************************************************/
void delay(unsigned int i)//延时函数
{
while(i--);
}
/***************************************************************************************/
//18b20初始化函数
void Init_DS18B20(void)
{
unsigned char x=0;
DQ = 1;    //DQ复位
delay(8);//稍做延时
DQ = 0;    //单片机将DQ拉低
delay(80); //精确延时 大于 480us
DQ = 1;    //拉高总线
delay(10);
x=DQ;      //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
delay(5);
}
//18b20初始化函数
void Init_DS18B201(void)
{
unsigned char x=0;
DQ = 1;    //DQ复位
delay(8);//稍做延时
DQ = 0;    //单片机将DQ拉低
delay(80); //精确延时 大于 480us
DQ = 1;    //拉高总线
delay(10);
x=DQ;      //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
delay(5);
}
//读一个字节
unsigned char ReadOneChar(void)
{    unsigned char i,j;
unsigned char temp = 0;
// EA = 0;
for (i=0;i<8;i++)
{    DQ = 0;    _nop_(); _nop_();
DQ = 1;    j = 8; while(--j);
j = DQ;
temp>>=1;
if (j) temp|=0x80;
j = 25;while(--j); /* wait for rest of timeslot */
}
// EA = 1;
return(temp);
}

//写一个字节
void WriteOneChar(unsigned char val)
{    unsigned char i,j;
unsigned char temp;

for (i=0; i<8; i++)/* writes byte, one bit at a time */
{    temp = val&0x01;
DQ = 0;
if (temp) DQ = 1;
val>>=1;
j = 25; while(--j);
DQ = 1;
}
//    return (1);
}
//写一个字节
void WriteOneChar1(unsigned char val)
{    unsigned char i,j;
unsigned char temp;

for (i=0; i<8; i++)/* writes byte, one bit at a time */
{    temp = val&0x01;
DQ = 0;
if (temp) DQ = 1;
val>>=1;
j = 25; while(--j);
DQ = 1;
}
//    return (1);
}
//写一位
void WriteOneBit(uchar bitval)
{    unsigned char i;
DQ=0;
if(1==bitval&0x01) DQ=1;// return DQ high if write 1
i = 25; while(--i);
DQ=1;
}
//读一位
unsigned char ReadOneBit()
{    unsigned char i,c;
DQ = 0;
_nop_();
_nop_();
DQ=1;
i = 8;
while(--i);
c=(unsigned char ) DQ;
i = 25;while(--i);
return( c ); // return value of DQ line
}
/*
void ReadId()                                        //只有一个时读ROM信息
{
Init_DS18B20();
WriteOneChar(0x33);                        //只有一个时读ROM信息                  
ID0=ReadOneChar();
ID1=ReadOneChar();
ID2=ReadOneChar();
ID3=ReadOneChar();
ID4=ReadOneChar();
ID5=ReadOneChar();
ID6=ReadOneChar();
ID7=ReadOneChar();
}
void MatcnId()
{
Init_DS18B20();
WriteOneChar(0x33);
ID0=ReadOneChar();
ID1=ReadOneChar();
ID2=ReadOneChar();
ID3=ReadOneChar();
ID4=ReadOneChar();
ID5=ReadOneChar();
ID6=ReadOneChar();
ID7=ReadOneChar();
} */
////////////////////////////
void MatchRom(void)
{    unsigned char i;
Init_DS18B20();
WriteOneChar(MATCH_ROM);
for(i=0;i<8;i++)
{
WriteOneChar(serial);
}
/*    switch(term)
{

case 1:    for(i=0;i<8;i++)
{
WriteOneChar(serial);
}
case 2:    for(i=0;i<8;i++)
{
WriteOneChar(serial);
}
}*/
}
///////////////////////////////////////////////////////////////////////
//读取温度,为9位
unsigned char ReadTemperature(void)
{
unsigned char a=0;
unsigned char b=0;
unsigned char t=0;
//float tt=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
delay(250);
delay(250);
delay(250);
delay(250);
Init_DS18B20();
MatchRom();
//WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
a=ReadOneChar();
b=ReadOneChar();

b<<=4;
b+=(a&0xf0)>>4;
t=b;
//tt=t*0.0625;
//t= tt*10+0.5; //放大10倍输出并四舍五入
return(t);
}
///////////////////////////////////////////////Search Rom///////////////////////////////////////
void FindSerial()//查ds18b20注册号
{
uchar n;
uchar j=0; //存读取的位
//uchar m=0;
uchar k=0;
uchar k1=1;//存64位8组中第几组
uchar record=64;
//uchar end=0;
uchar ks=0;//已搜索器件注册码中一位
uchar mm=0;// 8组中第几组的第几位
uchar nn=0;//复制serial,循环8次   
uchar RSearch;



Init_DS18B201();//复位单总线
WriteOneChar1(SEARCH_ROM);//发搜索命令

while (1)
{
for (n=1;n<65;n++)//读深度为64的二叉树
{
k=(n-1)/8;    //每8位放到数组中
j=ReadOneBit();
j=j<<1;
j=j|ReadOneBit();
serial=serial>>1;
if(j==0x02)    //第一次为1,第二次为0
{
serial=serial|0x80;//存该位1
WriteOneBit(1);//发送1
read_bit=0;
}

if (j==0x01)//第一次为0,第二次为1
{
serial=serial&0x7f; //存该位0
WriteOneBit(0); //发送0   
read_bit=0;
}

if(j==0x00)//两次都为0,记录分叉点
//      if(j==0x03)//for proteus
{
if (n<record) //深度是小于record所标记
{
ks=(serial[(k1-1)]>>((n-1)%8))&0x01;/*发前一个已搜索器件注册码*/
WriteOneBit(ks);
serial=serial|0x80;//存该位
if (ks==0) {serial=serial&0x7f;}
read_bit=1;//记录
}
else if (n>record)//深度是大于record所标记的
{
WriteOneBit(0x00);
read_bit=1;//记录
serial=serial&0x7f;
}
else
{
ks=(n-1)/8;mm=(n-1)%8;
nn=serial[(k1-1)]>>mm;
if ((nn&0x01)==1)
{
serial=serial&0x7f;
WriteOneBit(0x00);
}
if ((nn&0x01)==0)
{
serial=serial|0x80;
WriteOneBit(0x01);
}
read_bit=0;//清记录
}
}
}
//for(nn=0;nn<8;nn++)
//    {serial1=serial;}
if (n>64)
{
for (RSearch=64;RSearch>0;RSearch--)//从末尾搜索记录
{
if (read_bit!=0)
{
record=RSearch;
n=1;
read_bit=0;
//            flag=1;
break;

}
else
{record=0;}//清记录
}
}
if (record!=0)//如有分叉点,重新搜索
{
Init_DS18B20();
//    flag=1;
WriteOneChar(SEARCH_ROM);//发搜索命令
k1+=1;
}
else
{break;}
}
}

jetli 发表于 2012-5-16 14:10:06

{:dizzy:}去pudn 把那个代码下载了。顺手上传。

brwang1983 发表于 2013-4-17 09:54:59

学习了,感谢。

jsszdfdn 发表于 2013-4-23 16:39:39

太好了!谢谢楼主

zhouxy0901 发表于 2013-5-4 10:14:21

第一次学单片机就是测温,最后毕业了还是测温!沙发!

benqme 发表于 2013-5-4 10:19:29

学习了谢谢了

qq511153186 发表于 2013-5-5 11:22:42

好帖,做了单个的,多点的一直不会做,参考

beihu 发表于 2014-5-15 11:35:08

谢谢分享!

mk_avatar 发表于 2014-8-23 14:13:28

mark!~~~~~

mk_avatar 发表于 2014-8-23 15:03:41

mark~~~~~~

只为那梦的轮回 发表于 2014-11-18 13:03:53

mark.............

yinhe 发表于 2014-12-7 17:15:45

记录一下,非常有用

yinhe 发表于 2014-12-7 17:16:34

记录一下,非常有用{:smile:}

yinhe 发表于 2014-12-7 17:18:13

记录一下,非常有用{:smile:}

yinhe 发表于 2014-12-7 17:41:46

记录一下,非常有用{:smile:}

yinhe 发表于 2014-12-7 17:42:19

记录一下,非常有用{:smile:}
页: [1]
查看完整版本: 转载:DS18B20多点测温网络的三种方法