# 1-Wire搜索算法

## 绪论

Maxim的每片1-Wire器件都有唯一的64位注册码，它存储在只读存储器(ROM)中。在1-Wire网络中，注册码用于1-Wire主机对从机器件进行逐一寻址。如果1-Wire网络中从机 器件的ROM码是未知的，可以通过搜索算法来找到此码。本文不仅详细地解释了搜索算法，而且 还提供了实现快速整合的例程。该算法适用于任何具有1-Wire接口特性的现有产品及未来产品。

## 搜索算法

 Bit (true) Bit (complement) Information Known 0 0 There are both 0s and 1s in the current bit position of the participating ROM numbers. This is a discrepancy. 0 1 There are only 0s in the bit of the participating ROM numbers. 1 0 There are only 1s in the bit of the participating ROM numbers. 1 1 No devices participating in search.

 Master Slave 1-Wire reset stimulus Produce presence pulse Write search command (normal or alarm) Each slave readies for search. Read 'AND' of bit 1 Each slave sends bit 1 of its ROM number. Read 'AND' of complement bit 1 Each slave sends complement bit 1 of its ROM number. Write bit 1 direction (according to algorithm) Each slave receives the bit written by master, if bit read is not the same as bit 1 of its ROM number then go into a wait state. Read 'AND' of bit 64 Each slave sends bit 64 of its ROM number. Read 'AND' of complement bit 64 Each slave sends complement bit 64 of its ROM number. Write bit 64 direction (according to algorithm) Each slave receives the bit written by master, if bit read is not the same as bit 64 of its ROM number then go into a wait state.

 Search Bit Position vs Last Discrepancy Path Taken = take the '1' path < take the same path as last time (from last ROM number found) > take the '0' path

DS2480B系列串口到1-Wire线路的驱动程序在硬件中实现了部分与本文档中相同的搜索算法；详 细资料请参阅DS2480B数据资料和应用笔记192，DS2480B串行接口1-Wire线驱动器的使用的详细介绍；从DS2490 USB口到1-Wire桥接器硬件电路 中实现了整个搜索过程。

## First

‘FIRST’操作是搜索1-Wire总线上的第一个从机器件。该操作是通过将LastDiscrepancy、 LastFamilyDiscrepancy和LastDeviceFlag置零，然后进行搜索完成的。最后ROM码从ROM_NO寄存器中读出。若1-Wire总线上没有器件，复位序列就检测不到应答脉冲，搜索过程中止。

## Next

‘NEXT’操作是搜索1-Wire总线上的下一个从机器件；一般情况下，此搜索操作是在‘FIRST’操作之后或上一次‘NEXT’操作之后进行；保持上次搜索后这些值的状态不变、执行又一次搜 索即可实现‘NEXT’操作。之后从ROM_NO寄存器中来读出新一个ROM码。若前一次搜索到 的是1-Wire上的最后一个器件，则返回一个无效标记FALSE，并且把状态设置成下一次调用搜 索算法时将是‘FIRST’操作的状态。

## 高级变量搜索

### Verify

‘VERIFY’操作用来检验已知ROM码的器件是否连接在1-Wire总线上，通过提供ROM码并对 该码进行目标搜索就可确定此器件是否在线。首先，将ROM_NO寄存器值设置为已知的ROM码 值，然后将LastDiscrepancy和LastDeviceFlag标志位分别设置为64 (40h)和0； 进行搜索操作， 然后读ROM_NO的输出结果；如果搜索成功并且ROM_NO中存储的仍是要搜索器件的ROM码 值，那么此器件就在1-Wire总线上。

### Target Setup

‘TARGET SETUP’操作就是用预置搜索状态的方式首先查找一个特殊的家族类型，每个1-Wire器件都有一个字节的家族码内嵌在ROM码中(参见图1)，主机可以通过家族码来识别器件所具 有的特性和功能。若1-Wire总线上有多片器件时，通常是将搜索目标首先定位在需注意的器件类 型上。为了将一个特殊的家族作为搜索目标，需要将所希望的家族码字节放到ROM_NO寄存器 的第一个字节中，并且将ROM_NO寄存器的复位状态置零，然后将LastDiscrepancy设置为64 (40h)；把LastDeviceFlag和LastFamilyDiscrepancy设置为0。在执行下一次搜索算法时就能找出 所期望的产品类型的第一个器件；并将此值存入ROM_NO寄存器。需要注意的是如果1-Wire总 线上没有挂接所期望的产品类型的器件，就会找出另一类型的器件，所以每次搜索完成后，都要 对ROM_NO寄存器中存储的结果进行校验。

### Family Skip Setup

‘FAMILY SKIP SETUP’操作用来设置搜索状态以便跳过搜索到的指定家族中的所有器件，此操 作只有在一个搜索过程结束后才能使用。通过把LastFamilyDiscrepancy复制到LastDiscrepancy， 并清除LastDeviceFlag即可实现该操作；在下一搜索过程就会找到指定家族中的下一个器件。如 果当前家族码分组是搜索过程中的最后一组，那么搜索过程结束并将LastDeviceFlag置位。

 LastDiscrepancy LastFamily- Discrepancy LastDeviceFlag ROM_NO FIRST 0 0 0 result NEXT leave unchanged leave unchanged leave unchanged result VERIFY 64 0 0 set with ROM to verify, check if same after search TARGET SETUP 64 0 0 set first byte to family code, set rest to zeros FAMILY SKIP SETUP copy from LastFamilyDiscrepancy 0 0 leave unchanged

## 附录

```// TMEX API TEST BUILD DECLARATIONS
#define TMEXUTIL
#include "ibtmexcw.h"
long session_handle;
// END TMEX API TEST BUILD DECLARATIONS

// definitions
#define FALSE 0
#define TRUE  1

// method declarations
int  OWFirst();
int  OWNext();
int  OWVerify();
void OWTargetSetup(unsigned char family_code);
void OWFamilySkipSetup();
int  OWReset();
void OWWriteByte(unsigned char byte_value);
void OWWriteBit(unsigned char bit_value);
int  OWSearch();
unsigned char docrc8(unsigned char value);

// global search state
unsigned char ROM_NO[8];
int LastDiscrepancy;
int LastFamilyDiscrepancy;
int LastDeviceFlag;
unsigned char crc8;

//--------------------------------------------------------------------------
// Find the 'first' devices on the 1-Wire bus
// Return TRUE  : device found, ROM number in ROM_NO buffer
//        FALSE : no device present
//
int OWFirst()
{
// reset the search state
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;

return OWSearch();
}

//--------------------------------------------------------------------------
// Find the 'next' devices on the 1-Wire bus
// Return TRUE  : device found, ROM number in ROM_NO buffer
//
int OWNext()
{
// leave the search state alone
return OWSearch();
}

//--------------------------------------------------------------------------
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
// search state.
// Return TRUE  : device found, ROM number in ROM_NO buffer
//
int OWSearch()
{
int id_bit_number;
int last_zero, rom_byte_number, search_result;
int id_bit, cmp_id_bit;

// initialize for search
id_bit_number = 1;
last_zero = 0;
rom_byte_number = 0;
search_result = 0;
crc8 = 0;

// if the last call was not the last one
if (!LastDeviceFlag)
{
// 1-Wire reset
if (!OWReset())
{
// reset the search
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
return FALSE;
}

// issue the search command
OWWriteByte(0xF0);

// loop to do the search
do
{
// read a bit and its complement

// check for no devices on 1-wire
if ((id_bit == 1) && (cmp_id_bit == 1))
break;
else
{
// all devices coupled have 0 or 1
if (id_bit != cmp_id_bit)
search_direction = id_bit;  // bit write value for search
else
{
// if this discrepancy if before the Last Discrepancy
// on a previous next then pick the same as last time
if (id_bit_number < LastDiscrepancy)
search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
else
// if equal to last pick 1, if not then pick 0
search_direction = (id_bit_number == LastDiscrepancy);

// if 0 was picked then record its position in LastZero
if (search_direction == 0)
{
last_zero = id_bit_number;

// check for Last discrepancy in family
if (last_zero < 9)
LastFamilyDiscrepancy = last_zero;
}
}

// set or clear the bit in the ROM byte rom_byte_number
if (search_direction == 1)
else

// serial number search direction write bit
OWWriteBit(search_direction);

// increment the byte counter id_bit_number
id_bit_number++;

// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
{
docrc8(ROM_NO[rom_byte_number]);  // accumulate the CRC
rom_byte_number++;
}
}
}
while(rom_byte_number < 8);  // loop until through all ROM bytes 0-7

// if the search was successful then
if (!((id_bit_number < 65) || (crc8 != 0)))
{
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
LastDiscrepancy = last_zero;

// check for last device
if (LastDiscrepancy == 0)
LastDeviceFlag = TRUE;

search_result = TRUE;
}
}

// if no device found then reset counters so next 'search' will be like a first
if (!search_result || !ROM_NO[0])
{
LastDiscrepancy = 0;
LastDeviceFlag = FALSE;
LastFamilyDiscrepancy = 0;
search_result = FALSE;
}

return search_result;
}

//--------------------------------------------------------------------------
// Verify the device with the ROM number in ROM_NO buffer is present.
// Return TRUE  : device verified present
//        FALSE : device not present
//
int OWVerify()
{
unsigned char rom_backup[8];
int i,rslt,ld_backup,ldf_backup,lfd_backup;

// keep a backup copy of the current state
for (i = 0; i < 8; i++)
rom_backup[i] = ROM_NO[i];
ld_backup = LastDiscrepancy;
ldf_backup = LastDeviceFlag;
lfd_backup = LastFamilyDiscrepancy;

// set search to find the same device
LastDiscrepancy = 64;
LastDeviceFlag = FALSE;

if (OWSearch())
{
// check if same device found
rslt = TRUE;
for (i = 0; i < 8; i++)
{
if (rom_backup[i] != ROM_NO[i])
{
rslt = FALSE;
break;
}
}
}
else
rslt = FALSE;

// restore the search state
for (i = 0; i < 8; i++)
ROM_NO[i] = rom_backup[i];
LastDiscrepancy = ld_backup;
LastDeviceFlag = ldf_backup;
LastFamilyDiscrepancy = lfd_backup;

// return the result of the verify
return rslt;
}

//--------------------------------------------------------------------------
// Setup the search to find the device type 'family_code' on the next call
// to OWNext() if it is present.
//
void OWTargetSetup(unsigned char family_code)
{
int i;

// set the search state to find SearchFamily type devices
ROM_NO[0] = family_code;
for (i = 1; i < 8; i++)
ROM_NO[i] = 0;
LastDiscrepancy = 64;
LastFamilyDiscrepancy = 0;
LastDeviceFlag = FALSE;
}

//--------------------------------------------------------------------------
// Setup the search to skip the current device type on the next call
// to OWNext().
//
void OWFamilySkipSetup()
{
// set the Last discrepancy to last family discrepancy
LastDiscrepancy = LastFamilyDiscrepancy;
LastFamilyDiscrepancy = 0;

// check for end of list
if (LastDiscrepancy == 0)
LastDeviceFlag = TRUE;
}

//--------------------------------------------------------------------------
// 1-Wire Functions to be implemented for a particular platform
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
// Reset the 1-Wire bus and return the presence of any device
// Return TRUE  : device present
//        FALSE : no device present
//
int OWReset()
{
// platform specific
// TMEX API TEST BUILD
return (TMTouchReset(session_handle) == 1);
}

//--------------------------------------------------------------------------
// Send 8 bits of data to the 1-Wire bus
//
void OWWriteByte(unsigned char byte_value)
{
// platform specific

// TMEX API TEST BUILD
TMTouchByte(session_handle,byte_value);
}

//--------------------------------------------------------------------------
// Send 1 bit of data to teh 1-Wire bus
//
void OWWriteBit(unsigned char bit_value)
{
// platform specific

// TMEX API TEST BUILD
TMTouchBit(session_handle,(short)bit_value);
}

//--------------------------------------------------------------------------
// Read 1 bit of data from the 1-Wire bus
// Return 1 : bit read is 1
//        0 : bit read is 0
//
{
// platform specific

// TMEX API TEST BUILD
return (unsigned char)TMTouchBit(session_handle,0x01);

}

// TEST BUILD
static unsigned char dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95,  1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93,  3,128,222, 60, 98,
190,224,  2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89,  7,
219,133,103, 57,186,228,  6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135,  4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91,  5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73,  8, 86,180,234,105, 55,213,139,
87,  9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};

//--------------------------------------------------------------------------
// Calculate the CRC8 of the byte value provided with the current
// global 'crc8' value.
// Returns current global crc8 value
//
unsigned char docrc8(unsigned char value)
{
// See Application Note 27

// TEST BUILD
crc8 = dscrc_table[crc8 ^ value];
return crc8;
}

//--------------------------------------------------------------------------
// TEST BUILD MAIN
//
int main(short argc, char **argv)
{
short PortType=5,PortNum=1;
int rslt,i,cnt;

// TMEX API SETUP
// get a session
session_handle = TMExtendedStartSession(PortNum,PortType,NULL);
if (session_handle <= 0)
{
printf("No session, %d\n",session_handle);
exit(0);
}

// setup the port
rslt = TMSetup(session_handle);
if (rslt != 1)
{
printf("Fail setup, %d\n",rslt);
exit(0);
}
// END TMEX API SETUP

// find ALL devices
printf("\nFIND ALL\n");
cnt = 0;
rslt = OWFirst();
while (rslt)
{
// print device found
for (i = 7; i >= 0; i--)
printf("%02X", ROM_NO[i]);
printf("  %d\n",++cnt);

rslt = OWNext();
}

// find only 0x1A
printf("\nFIND ONLY 0x1A\n");
cnt = 0;
OWTargetSetup(0x1A);
while (OWNext())
{
// check for incorrect type
if (ROM_NO[0] != 0x1A)
break;

// print device found
for (i = 7; i >= 0; i--)
printf("%02X", ROM_NO[i]);
printf("  %d\n",++cnt);
}

// find all but 0x04, 0x1A, 0x23, and 0x01
printf("\nFIND ALL EXCEPT 0x10, 0x04, 0x0A, 0x1A, 0x23, 0x01\n");
cnt = 0;
rslt = OWFirst();
while (rslt)
{
// check for incorrect type
if ((ROM_NO[0] == 0x04) || (ROM_NO[0] == 0x1A) ||
(ROM_NO[0] == 0x01) || (ROM_NO[0] == 0x23) ||
(ROM_NO[0] == 0x0A) || (ROM_NO[0] == 0x10))
OWFamilySkipSetup();
else
{
// print device found
for (i = 7; i >= 0; i--)
printf("%02X", ROM_NO[i]);
printf("  %d\n",++cnt);
}

rslt = OWNext();
}

// TMEX API CLEANUP
// release the session
TMEndSession(session_handle);
// END TMEX API CLEANUP
}
```

01/30/02版1.0—初始版本。
05/16/03版1.1—修改内容：Search ROM命令修改为F0 (十六进制)。