应用笔记 3684

如何使用I²C接口的DS2482 1-Wire®主控制器


摘要 : DS2482是I²C到1-Wire的桥接器件。DS2482可以使任何具备I²C通信功能的主机产生正确时序和具有摆率控制的1-Wire波形。本应用笔记是DS2482 I²C至1-Wire线驱动器的用户指南,详细介绍了通用1-Wire主控制器操作的通信过程。

引言

1-Wire网络包括一个主机和一个或多个从机器件,1-Wire主机可以由微处理器的一个I/O引脚构成,手动产生定时脉冲。DS2482 I²C至1-Wire网络的桥接器件可以产生详细的1-Wire通信时序,无需工程师参与设计。图1所示为DS2482配置的简化框图。本文介绍了采用DS2482实现应用程序接口(API)有效方法,支持基本的和扩展的1-Wire操作。详细介绍了对应于1-Wire操作的I²C通信。这些操作为执行当前和未来1-Wire器件的所有功能打下了全面的基础,但基于DS250x系列EPROM的器件编程除外。以这种方式概要介绍1-Wire操作,适合不依赖1-Wire主机的1-Wire应用。

本文仅作为DS2482数据资料的补充,并不能替代数据资料。DS2482可提供两种配置,单通道1-Wire主控制器(DS2482-100)和带有低功耗休眠模式的1-Wire主控制器(DS2482-101),以及八通道1-Wire主控制器(DS2482-800)。

图1. 实现I2C与1-Wire网络通信的DS2482桥接器功能简图
图1. 实现I²C与1-Wire网络通信的DS2482桥接器功能简图

1-Wire接口

下面给出几个基本的1-Wire函数,称之为原函数,也就是为了执行所有1-Wire操作,应用中必须具备的函数。第一个函数(OWReset)是使网络上所有1-Wire从器件复位,为接收来自1-Wire主控制器的指令做好准备。第二个函数(OWWriteBit)完成1-Wire主控制器向从器件写入一位的操作,而第三个函数(OWReadBit)完成从1-Wire从器件中读取一位的操作。由于必须由1-Wire主控制器启动所有的1-Wire位通信,所以“读取”实际上是在“写入”一位后采样得到的结果。几乎所有其他1-Wire操作都可以由这三个操作构成。例如,向1-Wire网络写1个字节相当于8次写一位操作。

1-Wire搜索算法也可以利用相同的三个原始函数构成。通1-Wire的三个命令,DS2482可以执行搜索功能,大大降低了搜索操作所需的通信量。同样,单字节的1-Wire通信命令要比八次逐位操作效率更高。

表1所示是三个基本原函数(OWReset、OWWriteBit/OWReadBit和OWWriteByte/OWReadByte)以及其它三个非常有用的函数(OWBlock、OWSearch和msDelay),它们构成了一系列主要的基本1-Wire操作。这些操作名称将在下文中使用。

表1. 基本的1-Wire操作
Operation Description
OWReset Sends the 1-Wire reset stimulus and check for the presence pulse of 1-Wire slave devices.
OWWriteBit/OWReadBit Sends to or receives from the 1-Wire network a single bit of data.
OWWriteByte/OWReadByte Sends to or receives from the 1-Wire network a single byte of data.
OWBlock Sends to and receives from the 1-Wire network multiple bytes of data.
OWSearch Performs the 1-Wire Search Algorithm (see application note 187).
msDelay Delays at least the specified number of milliseconds. Used for timing strong pullup operations.

许多1-Wire从器件可以工作在两种不同的通信速率下:标准速率和高速模式。所有器件都支持标准速率模式。高速速率大约是标准速率的10倍。DS2482同时支持这两种1-Wire速率。

1-Wire器件通常从1-Wire总线上获取部分或全部工作电源。不过有些器件在协议的特定操作中需要额外供电。例如,某个器件可能需要进行温度转换或执行SHA-1散列算法。这种操作的电源是通过使能1-Wire总线的强上拉提供的。这种供电方式下,不能进行正常通信。DS2482通过设置强上拉标志(SPU)位供电,这将在1-Wire的下一个字节/位通信完成后启动强上拉。DS2482-100和DS2482-101还具有一个外部引脚(PCTLZ),可控制大电流强上拉。

表2列出了用于1-Wire速率设定、供电和编程脉冲的扩展1-Wire操作。

表2. 扩展的1-Wire操作
Operation Description
OWSpeed Sets the 1-Wire communication speed, either standard or overdrive. Note that this only changes the communication speed of the 1-Wire master; the 1-Wire slave device must be instructed to make the switch when going from normal to overdrive. The 1-Wire slave will always revert to standard speed when it encounters a standard-speed 1-Wire reset.
OWLevel Sets the 1-Wire power level (normal or power delivery).
OWReadBitPower Reads a single bit of data from the 1-Wire network and optionally applies power delivery immediately after the bit is complete.
OWWriteBytePower Sends a single byte of data to the 1-Wire network and applies power delivery immediately after the byte is complete.

主机配置

DS2482的主机应具有一个I²C通信口,本文并没有讲述主机的配置。然而,主机必须提供标准I²C接口操作。需要注意的是,主机接口具有包含一些I²C接口操作的高级函数。所需操作请参考表3

表3. 所需要的I²C主机操作
Operation Description
I2C_start I²C start command.
I2C_rep_start I²C repeated start command.
I2C_stop I²C stop command.
I2C_write Writes a byte to the I²C bus. The byte to write is passed to the function.
I2C_read Reads a byte from the I²C bus. The byte read is returned from the function.

配置DS2482

在尝试1-Wire操作之前,主机必须设置I²C至1-Wire线驱动器DS2482,并与其同步。要与DS2482通信,主机必须知道其从地址。图2所示为DS2482-100、DS2482-101和DS2482-800的从地址。

图2. DS2482的I2C从地址
图2. DS2482的I²C从地址

DS2482的I²C命令

下列符号说明来自于DS2482数据资料,以简写符号表示,用来说明器件的I²C通信过程。接下来,我们会重复这些通信过程,并为实现基本的和扩展的1-Wire操作提供附加注释和C语言例程。

I²C通信过程—符号说明
Symbol Description
S START Condition
AD, 0 Select DS2482 for Write Access
AD, 1 Select DS2482 for Read Access
Sr Repeated START Condition
P STOP Condition
A Acknowledged
A\ Not acknowledged
(Idle) Bus not busy
<byte> Transfer of one byte
DRST Command 'Device Reset', F0h
WCFG Command 'Write Configuration', D2h
CHSL Command 'Channel Select', C3h (DS2482-800 only)
SRP Command 'Set Read Pointer', E1h
1WRS Command '1-Wire Reset', B4h
1WWB Command '1-Wire Write Byte', A5h
1WRB Command '1-Wire Read Byte', 96h
1WSB Command '1-Wire Single Bit', 87h
1WT Command '1-Wire Triplet', 78h

数据方向表示法

Master-to-Slave Slave-to-Master

本文中许多图中的数据方向表示方法指出了通信方向是主机到从机(灰色),还是从机到主机(白色)。

DS2482配置操作

以下操作用于设置、配置DS2482,有些操作需要调用1-Wire操作的子程序。

DS2482检测

例1所示C程序提供检测和配置流程,写入DS2482的默认值包括1-Wire速率(标准)、强上拉(关断)、在线脉冲屏蔽(关断)和有源上拉(通)。该状态保持为通用变量,如果器件需要复位到该默认状态可以进行恢复。针对不同应用可以选择不同的默认值。

// DS2482 state
unsigned char I2C_address;
int c1WS, cSPU, cPPM, cAPU;
int short_detected;

//--------------------------------------------------------------------------
// DS2428 Detect routine that sets the I2C address and then performs a
// device reset followed by writing the configuration byte to default values:
//   1-Wire speed (c1WS) = standard (0)
//   Strong pullup (cSPU) = off (0)
//   Presence pulse masking (cPPM) = off (0)
//   Active pullup (cAPU) = on (CONFIG_APU = 0x01)
//
// Returns: TRUE if device was detected and written
//          FALSE device not detected or failure to write configuration byte
//
int DS2482_detect(unsigned char addr)
{
   // set global address
   I2C_address = addr;

   // reset the DS2482 ON selected address
   if (!DS2482_reset())
      return FALSE;

   // default configuration
   c1WS = FALSE;
   cSPU = FALSE;
   cPPM = FALSE;
   cAPU = CONFIG_APU;


   // write the default configuration setup
   if (!DS2482_write_config(c1WS | cSPU | cPPM | cAPU))
      return FALSE;

   return TRUE;
}
例1. DS2482检测

DS2482器件复位

图3是DS2482器件复位I²C通信的流程。例2给出了DS2482复位命令的C程序,可实现器件状态机逻辑的完全复位,并终止所有正在进行的1-Wire通信。器件的复位命令代码是F0h。

图3. 上电后进行器件复位。该实例包括可选的读访问,以检验命令是否成功执行。
图3. 上电后进行器件复位。该实例包括可选的读访问,以检验命令是否成功执行。

//--------------------------------------------------------------------------
// Perform a device reset on the DS2482
//
// Returns: TRUE if device was reset
//          FALSE device not detected or failure to perform reset
//
int DS2482_reset()
{
   unsigned char status;

   // Device Reset
   //   S AD,0 [A] DRST [A] Sr AD,1 [A] [SS] A\ P
   //  [] indicates from slave
   //  SS status byte to read to verify state

   I2C_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_DRST, EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);
   status = I2C_read(NACK);
   I2C_stop();

   // check for failure due to incorrect read back of status
   return ((status & 0xF7) == 0x10);
}
例2. 复位器件代码

DS2482写配置

图4所示为DS2482写配置的I²C通信例程;例3所示为实现DS2482写配置命令时序的C程序。写配置命令代码为D2h。

图4. 写配置寄存器,该实例中包括可选择的读操作,用于验证是否成功执行命令。
图4. 写配置寄存器,该实例中包括可选择的读操作,用于验证是否成功执行命令。

//--------------------------------------------------------------------------
// Write the configuration register in the DS2482. The configuration
// options are provided in the lower nibble of the provided config byte.
// The uppper nibble in bitwise inverted when written to the DS2482.
//
// Returns:  TRUE: config written and response correct
//           FALSE: response incorrect
//
int DS2482_write_config(unsigned char config)
{
   unsigned char read_config;

   // Write configuration (Case A)
   //   S AD,0 [A] WCFG [A] CF [A] Sr AD,1 [A] [CF] A\ P
   //  [] indicates from slave
   //  CF configuration byte to write

   I2C_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_WCFG, EXPECT_ACK);
   I2C_write(config | (~config << 4), EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);
   read_config = I2C_read(NACK);
   I2C_stop();

   // check for failure due to incorrect read back
   if (config != read_config)
   {
      // handle error
      // ...
      DS2482_reset();

      return FALSE;
   }

   return TRUE;
}
例3. DS2482写配置

DS2482通道选择

图5所示为实现DS2482-800通道选择的I²C通信实例,有效通道为0至7。注意,该操作不适合DS2482-100或DS2482-101。例4给出了执行DS2482-800通道选择命令的C程序,通道选择命令码为C3h。选择通道后,选中通道可执行所有1-Wire操作。

图5. 写通道选择寄存器,该实例中包括可选择的读操作,用于验证是否成功执行命令。
图5. 写通道选择寄存器,该实例中包括可选择的读操作,用于验证是否成功执行命令。

//--------------------------------------------------------------------------
// Select the 1-Wire channel on a DS2482-800.
//
// Returns: TRUE if channel selected
//          FALSE device not detected or failure to perform select
//
int DS2482_channel_select(int channel)
{
   unsigned char ch, ch_read, check;

   // Channel Select (Case A)
   //   S AD,0 [A] CHSL [A] CC [A] Sr AD,1 [A] [RR] A\ P
   //  [] indicates from slave
   //  CC channel value
   //  RR channel read back

   I2C_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_CHSL, EXPECT_ACK);

   switch (channel)
   {
      default: case 0: ch = 0xF0; ch_read = 0xB8; break;
      case 1: ch = 0xE1; ch_read = 0xB1; break;
      case 2: ch = 0xD2; ch_read = 0xAA; break;
      case 3: ch = 0xC3; ch_read = 0xA3; break;
      case 4: ch = 0xB4; ch_read = 0x9C; break;
      case 5: ch = 0xA5; ch_read = 0x95; break;
      case 6: ch = 0x96; ch_read = 0x8E; break;
      case 7: ch = 0x87; ch_read = 0x87; break;
   };

   I2C_write(ch, EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);
   check = I2C_read(NACK);
   I2C_stop();

   // check for failure due to incorrect read back of channel
   return (check == ch_read);
}
例4. DS2482-800通道选择

DS2482的1-Wire操作

OWReset

1-Wire Reset命令(B4h)在1-Wire总线上执行1-Wire复位和1-Wire器件在线应答脉冲检测。通过状态寄存器中的在线应答脉冲检测(PPD)和短路检测(SD)字段,可以采样和报告1-Wire总线的状态。图6所示为1-Wire复位命令的I²C通信流程。例5为发送命令的C程序,将检查状态寄存器以确定在线应答脉冲状态。

图6. 1-Wire复位。开始或终止1-Wire通信。连续检测1-Wire的空闲(1WB = 0)、忙状态,直到1-Wire命令完成为止,等到1-Wire命令执行完成,然后读取结果。
图6. 1-Wire复位。开始或终止1-Wire通信。连续检测1-Wire的空闲(1WB = 0)、忙状态,直到1-Wire命令完成为止,等到1-Wire命令执行完成,然后读取结果。

//--------------------------------------------------------------------------
// Reset all of the devices on the 1-Wire Net and return the result.
//
// Returns: TRUE(1):  presence pulse(s) detected, device(s) reset
//          FALSE(0): no presence pulses detected
//
int OWReset(void)
{
   unsigned char status;
   int poll_count = 0;

   // 1-Wire reset (Case B)
   //   S AD,0 [A] 1WRS [A] Sr AD,1 [A] [Status] A [Status] A\ P
   //                                   \--------/
   //                       Repeat until 1WB bit has changed to 0
   //  [] indicates from slave

   I2C_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_1WRS, EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);

   // loop checking 1WB bit for completion of 1-Wire operation
   // abort if poll limit reached
   status = I2C_read(ACK);
   do
   {
      status = I2C_read(status & STATUS_1WB);
   }
   while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT));

   I2C_stop();

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      DS2482_reset();
      return FALSE;
   }

   // check for short condition
   if (status & STATUS_SD)
      short_detected = TRUE;
   else
      short_detected = FALSE;

   // check for presence detect
   if (status & STATUS_PPD)
      return TRUE;
   else
      return FALSE;
}
例5. OWReset代码

OWWriteBit/OWReadBit

1-Wire位命令(0x87)生成一个1-Wire位时隙。图7所示是1-Wire位命令的I²C通信C程序。图8时字节的位分配,V是发送位。例6给出了OWWriteBit、OWReadBit和OWTouchBit程序。

图7. 1-Wire位,在1-Wire总线上生成一个时隙,当1WB从1变为0时,状态寄存器保持1-Wire位命令的有效结果。
图7. 1-Wire位,在1-Wire总线上生成一个时隙,当1WB从1变为0时,状态寄存器保持1-Wire位命令的有效结果。

图8. 1-Wire的一个数据字节
图8. 1-Wire的一个数据字节

//--------------------------------------------------------------------------
// Send 1 bit of communication to the 1-Wire Net.
// The parameter 'sendbit' least significant bit is used.
//
// 'sendbit' - 1 bit to send (least significant byte)
//
void OWWriteBit(unsigned char sendbit)
{
   OWTouchBit(sendbit);
}

//--------------------------------------------------------------------------
// Reads 1 bit of communication from the 1-Wire Net and returns the
// result
//
// Returns:  1 bit read from 1-Wire Net
//
unsigned char OWReadBit(void)
{
   return OWTouchBit(0x01);
}

//--------------------------------------------------------------------------
// Send 1 bit of communication to the 1-Wire Net and return the
// result 1 bit read from the 1-Wire Net. The parameter 'sendbit'
// least significant bit is used and the least significant bit
// of the result is the return bit.
//
// 'sendbit' - the least significant bit is the bit to send
//
// Returns: 0:   0 bit read from sendbit
//          1:   1 bit read from sendbit
//
unsigned char OWTouchBit(unsigned char sendbit)
{
   unsigned char status;
   int poll_count = 0;

   // 1-Wire bit (Case B)
   //   S AD,0 [A] 1WSB [A] BB [A] Sr AD,1 [A] [Status] A [Status] A\ P
   //                                          \--------/
   //                           Repeat until 1WB bit has changed to 0
   //  [] indicates from slave
   //  BB indicates byte containing bit value in msbit

   I2C_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_1WSB, EXPECT_ACK);
   I2C_write(sendbit ? 0x80 : 0x00, EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);

   // loop checking 1WB bit for completion of 1-Wire operation
   // abort if poll limit reached
   status = I2C_read(ACK);
   do
   {
      status = I2C_read(status & STATUS_1WB);
   }
   while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT));

   I2C_stop();

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      DS2482_reset();
      return 0;
   }

   // return bit state
   if (status & STATUS_SBR)
      return 1;
   else
      return 0;
}
例6. 1-Wire位命令

OWWriteByte

1-Wire写字节命令(A5h)向1-Wire总线写入单个数据字节。在DS2482执行该命令之前,必须结束1-Wire的工作状态。图9所示为通过I²C写1-Wire字节的情况。例7中的程序在从该操作返回前检查1-Wire是否完成有效的操作。

图9. 1-Wire写字节。向1-Wire总线发送命令代码。当1WB从1变为0时,完成1-Wire写字节命令。
图9. 1-Wire写字节。向1-Wire总线发送命令代码。当1WB从1变为0时,完成1-Wire写字节命令。

//--------------------------------------------------------------------------
// Send 8 bits of communication to the 1-Wire Net and verify that the
// 8 bits read from the 1-Wire Net are the same (write operation).
// The parameter 'sendbyte' least significant 8 bits are used.
//
// 'sendbyte' - 8 bits to send (least significant byte)
//
// Returns:  TRUE: bytes written and echo was the same
//           FALSE: echo was not the same
//
void OWWriteByte(unsigned char sendbyte)
{
   unsigned char status;
   int poll_count = 0;

   // 1-Wire Write Byte (Case B)
   //   S AD,0 [A] 1WWB [A] DD [A] Sr AD,1 [A] [Status] A [Status] A\ P
   //                                          \--------/
   //                             Repeat until 1WB bit has changed to 0
   //  [] indicates from slave
   //  DD data to write

   I2C_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_1WWB, EXPECT_ACK);
   I2C_write(sendbyte, EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);

   // loop checking 1WB bit for completion of 1-Wire operation
   // abort if poll limit reached
   status = I2C_read(ACK);
   do
   {
      status = I2C_read(status & STATUS_1WB);
   }
   while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT));

   I2C_stop();

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      DS2482_reset();
   }
}
例7. OWWriteByte程序

OWReadByte

1-Wire读字节命令(96h)从1-Wire网络读取单个数据字节。在DS2482执行该命令之前,必须等1-Wire的工作状态结束。图10所示为I²C通信流程,1-Wire读字节命令程序如例8。发送读字节命令之前,必须检查1-Wire的工作状态是否结束。

图10. 1-Wire读字节。从1-Wire总线上读取一个字节。连续检测状态寄存器直到1WB位从1变为0。然后设置读指针指向读数据寄存器(代码E1h),并再次访问该器件,读取从1-Wire总线上得到的数据字节。
图10. 1-Wire读字节。从1-Wire总线上读取一个字节。连续检测状态寄存器直到1WB位从1变为0。然后设置读指针指向读数据寄存器(代码E1h),并再次访问该器件,读取从1-Wire总线上得到的数据字节。
//--------------------------------------------------------------------------
// Send 8 bits of read communication to the 1-Wire Net and return the
// result 8 bits read from the 1-Wire Net.
//
// Returns:  8 bits read from 1-Wire Net
//
unsigned char OWReadByte(void)
{
   unsigned char data, status;
   int poll_count = 0;

   // 1-Wire Read Bytes (Case C)
   //   S AD,0 [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A\
   //                                   \--------/
   //                     Repeat until 1WB bit has changed to 0
   //   Sr AD,0 [A] SRP [A] E1 [A] Sr AD,1 [A] DD A\ P
   //
   //  [] indicates from slave
   //  DD data read

   I2C_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_1WRB, EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);

   // loop checking 1WB bit for completion of 1-Wire operation
   // abort if poll limit reached
   status = I2C_read(ACK);
   do
   {
      status = I2C_read(status & STATUS_1WB);
   }
   while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT));

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      DS2482_reset();
      return 0;
   }

   I2C_rep_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_SRP, EXPECT_ACK);
   I2C_write(0xE1, EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);
   data =  I2C_read(NACK);
   I2C_stop();

   return data;
}
例8. OWReadByte程序

OWBlock

OWBlock用于执行一组1-Wire字节操作,对于1-Wire网络的数据块传输非常有用。例9所示为OWBlock例程。

//--------------------------------------------------------------------------
// The 'OWBlock' transfers a block of data to and from the
// 1-Wire Net. The result is returned in the same buffer.
//
// 'tran_buf' - pointer to a block of unsigned
//              chars of length 'tran_len' that will be sent
//              to the 1-Wire Net
// 'tran_len' - length in bytes to transfer
//
void OWBlock(unsigned char *tran_buf, int tran_len)
{
   int i;

   for (i = 0; i < tran_len; i++)
      tran_buf[i] = OWTouchByte(tran_buf[i]);
}

//--------------------------------------------------------------------------
// Send 8 bits of communication to the 1-Wire Net and return the
// result 8 bits read from the 1-Wire Net. The parameter 'sendbyte'
// least significant 8 bits are used and the least significant 8 bits
// of the result are the return byte.
//
// 'sendbyte' - 8 bits to send (least significant byte)
//
// Returns:  8 bits read from sendbyte
//
unsigned char OWTouchByte(unsigned char sendbyte)
{
   if (sendbyte == 0xFF)
      return OWReadByte();
   else
   

{ OWWriteByte(sendbyte); return sendbyte; } }
例9. OWBlock程序

OWSearch/1-Wire的三合一命令

1-Wire搜索命令用于搜索1-Wire网络中每个器件唯一的64位注册码,这个唯一的注册码通常在数据资料中用ROM码表示,因为它存储在只读存储器。搜索从1-Wire复位开始,随后是搜索命令。所有1-Wire器件应答的搜索命令是F0h。搜索命令之后,1-Wire主机将进行二叉树搜索,找到一个器件。二叉树搜索通过以下操作判断64位的每一位:首先读一位,读取该位的补码,然后写入一位以确定留在搜索中的器件。这三个单独的位操作时序称为三合一操作。DS2482带有一个简短命令,利用该三合一命令可以更高效地执行1-Wire搜索。

三合一命令(78h)可在1-Wire总线上产生3个时隙,其中包括两个读时隙和一个写时隙。状态寄存器中的方向字节(DIR)决定了写时隙的类型(图11)。例10介绍了完整的1-Wire搜索过程,采用1-Wire三合一命令。调用OWFirst,然后重复调用OWNext,可以查找到1-Wire网络的所有器件。有关1-Wire搜索算法的详细介绍请参考应用笔记187,“1-Wire搜索算法”。

图11. 1-Wire三合一命令,在1-Wire总线上实现搜索ROM功能。完成该1-Wire功能需要空闲时间。然后在读模式下访问器件,通过1-Wire三合一命令得到结果。
图11. 1-Wire三合一命令,在1-Wire总线上实现搜索ROM功能。完成该1-Wire功能需要空闲时间。然后在读模式下访问器件,通过1-Wire三合一命令得到结果。

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

//--------------------------------------------------------------------------
// Find the 'first' devices on the 1-Wire network
// 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 network
// Return TRUE  : device found, ROM number in ROM_NO buffer
//        FALSE : device not found, end of search
//
int OWNext()
{
   // leave the search state alone
   return OWSearch();
}

//--------------------------------------------------------------------------
// The 'OWSearch' function does a general search. This function
// continues from the previous search state. The search state
// can be reset by using the 'OWFirst' function.
// This function contains one parameter 'alarm_only'.
// When 'alarm_only' is TRUE (1) the find alarm command
// 0xEC is sent instead of the normal search command 0xF0.
// Using the find alarm command 0xEC will limit the search to only
// 1-Wire devices that are in an 'alarm' state.
//
// Returns:   TRUE (1) : when a 1-Wire device was found and its
//                       Serial Number placed in the global ROM
//            FALSE (0): when no new device was found.  Either the
//                       last search was the last device or there
//                       are no devices on the 1-Wire Net.
//
int OWSearch()
{
   int id_bit_number;
   int last_zero, rom_byte_number, search_result;
   int id_bit, cmp_id_bit;
   unsigned char rom_byte_mask, search_direction, status;

   // initialize for search
   id_bit_number = 1;
   last_zero = 0;
   rom_byte_number = 0;
   rom_byte_mask = 1;
   search_result = FALSE;
   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
      {
         // if this discrepancy if before the Last Discrepancy
         // on a previous next then pick the same as last time
         if (id_bit_number < LastDiscrepancy)
         {
            if ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0)
               search_direction = 1;
            else
               search_direction = 0;
         }
         else
         {
            // if equal to last pick 1, if not then pick 0
            if (id_bit_number == LastDiscrepancy)
               search_direction = 1;
            else
               search_direction = 0;
         }

         // Perform a triple operation on the DS2482 which will perform
         // 2 read bits and 1 write bit
         status = DS2482_search_triplet(search_direction);

         // check bit results in status byte
         id_bit = ((status & STATUS_SBR) == STATUS_SBR);
         cmp_id_bit = ((status & STATUS_TSB) == STATUS_TSB);
         search_direction =
         	((status & STATUS_DIR) == STATUS_DIR) ? (byte)1 : (byte)0;

         // check for no devices on 1-Wire
         if ((id_bit) && (cmp_id_bit))
            break;
         else
         {
            if ((!id_bit) && (!cmp_id_bit) && (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
            // with mask rom_byte_mask
            if (search_direction == 1)
               ROM_NO[rom_byte_number] |= rom_byte_mask;
            else
               ROM_NO[rom_byte_number] &= (byte)~rom_byte_mask;

            // increment the byte counter id_bit_number
            // and shift the mask rom_byte_mask
            id_bit_number++;
            rom_byte_mask <<= 1;

            // if the mask is 0 then go to new SerialNum byte rom_byte_number
            // and reset mask
            if (rom_byte_mask == 0)
            {
               calc_crc8(ROM_NO[rom_byte_number]);  // accumulate the CRC
               rom_byte_number++;
               rom_byte_mask = 1;
            }
         }
      }
      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] == 0))
   {
      LastDiscrepancy = 0;
      LastDeviceFlag = FALSE;
      LastFamilyDiscrepancy = 0;
      search_result = FALSE;
   }

   return search_result;
}

//--------------------------------------------------------------------------
// Use the DS2482 help command '1-Wire triplet' to perform one bit of a
//1-Wire search.
//This command does two read bits and one write bit. The write bit
// is either the default direction (all device have same bit) or in case of
// a discrepancy, the 'search_direction' parameter is used.
//
// Returns – The DS2482 status byte result from the triplet command
//
unsigned char DS2482_search_triplet(int search_direction)
{
   unsigned char status;
   int poll_count = 0;

   // 1-Wire Triplet (Case B)
   //   S AD,0 [A] 1WT [A] SS [A] Sr AD,1 [A] [Status] A [Status] A\ P
   //                                         \--------/
   //                           Repeat until 1WB bit has changed to 0
   //  [] indicates from slave
   //  SS indicates byte containing search direction bit value in msbit

   I2C_start();
   I2C_write(I2C_address | I2C_WRITE, EXPECT_ACK);
   I2C_write(CMD_1WT, EXPECT_ACK);
   I2C_write(search_direction ? 0x80 : 0x00, EXPECT_ACK);
   I2C_rep_start();
   I2C_write(I2C_address | I2C_READ, EXPECT_ACK);

   // loop checking 1WB bit for completion of 1-Wire operation
   // abort if poll limit reached
   status = I2C_read(ACK);
   do
   {
      status = I2C_read(status & STATUS_1WB);
   }
   while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT));

   I2C_stop();

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      DS2482_reset();
      return 0;
   }

   // return status byte
   return status;
}
例10. OWSearch程序

扩展的1-Wire工作模式

OWSpeed

例11给出了如何用DS2482改变1-Wire总线速率的例程,所有1-Wire器件默认工作在标准通信速率,有些器件可以通过Overdrive-Match-ROM或Overdrive-Skip-ROM命令转移到高速工作模式。一旦器件工作在高速模式,所有1-Wire通信将采用高速时序。标准速率的1-Wire复位命令将使所有器件恢复到标准速率。

//--------------------------------------------------------------------------
// Set the 1-Wire Net communication speed.
//
// 'new_speed' - new speed defined as
//                MODE_STANDARD   0x00
//                MODE_OVERDRIVE  0x01
//
// Returns:  current 1-Wire Net speed
//
int OWSpeed(int new_speed)
{
   // set the speed
   if (new_speed == MODE_OVERDRIVE)
      c1WS = CONFIG_1WS;
   else
      c1WS = FALSE;

   // write the new config
   DS2482_write_config(c1WS | cSPU | cPPM | cAPU);

   return new_speed;
}
例11. OWSpeed程序

OWLevel

例12给出了如何用DS2482改变1-Wire总线电平的程序,DS2482可以在执行一次位或字节通信后使能强上拉。随后,OWLevel程序将1-Wire网络返回到标准上拉,利用OWWriteBytePower或OWReadBitPower操作使能强上拉。

//--------------------------------------------------------------------------
// Set the 1-Wire Net line level pullup to normal. The DS2482 only
// allows enabling strong pullup on a bit or byte event. Consequently this
// function only allows the MODE_STANDARD argument. To enable strong pullup
// use OWWriteBytePower or OWReadBitPower.
//
// 'new_level' - new level defined as
//                MODE_STANDARD     0x00
//
// Returns:  current 1-Wire Net level
//
int OWLevel(int new_level)
{
   // function only will turn back to non-strong pullup
   if (new_level != MODE_STANDARD)
      return MODE_STRONG;

   // clear the strong pullup bit in the global config state
   cSPU = FALSE;

   // write the new config
   DS2482_write_config(c1WS | cSPU | cPPM | cAPU);

   return MODE_STANDARD;
}
例12. OWLevel程序

OWReadBitPower

例13是OWReadBitPower所使用的程序,用于读取一个1-Wire位并执行供电功能。当配置寄存器中的强上拉(SPU)位使能时,在下一位或字节通信完成后,DS2482将有源拉高1-Wire总线。该操作可通过是否获得相应的响应来验证读位的正确性,如果响应不正确,1-Wire电平将返回到标准的上拉状态。

//--------------------------------------------------------------------------
// Send 1 bit of communication to the 1-Wire Net and verify that the
// response matches the 'applyPowerResponse' bit and apply power delivery
// to the 1-Wire net.  Note that some implementations may apply the power
// first and then turn it off if the response is incorrect.
//
// 'applyPowerResponse' - 1 bit response to check, if correct then start
//                        power delivery
//
// Returns:  TRUE: bit written and response correct, strong pullup now on
//           FALSE: response incorrect
//
int OWReadBitPower(int applyPowerResponse)
{
   unsigned char rdbit;

   // set strong pullup enable
   cSPU = CONFIG_SPU;

   // write the new config
   if (!DS2482_write_config(c1WS | cSPU | cPPM | cAPU))
      return FALSE;

   // perform read bit
   rdbit = OWReadBit();

   // check if response was correct, if not then turn off strong pullup
   if (rdbit != applyPowerResponse)
   {
      OWLevel(MODE_STANDARD);
      return FALSE;
   }

   return TRUE;
}
例13. OWReadBitPower程序

OWWriteBytePower

例14为OWWriteBytePower所采用的程序,用于写入1-Wire字节并执行强上拉供电功能。当配置寄存器中的强上拉(SPU)位使能时,在下一位或字节通信完成后,DS2482将由源拉高1-Wire总线。

//--------------------------------------------------------------------------
// Send 8 bits of communication to the 1-Wire Net and verify that the
// 8 bits read from the 1-Wire Net are the same (write operation).
// The parameter 'sendbyte' least significant 8 bits are used. After the
// 8 bits are sent change the level of the 1-Wire net.
//
// 'sendbyte' - 8 bits to send (least significant bit)
//
// Returns:  TRUE: bytes written and echo was the same, strong pullup now on
//           FALSE: echo was not the same
//
int OWWriteBytePower(int sendbyte)
{
   // set strong pullup enable
   cSPU = CONFIG_SPU;

   // write the new config
   if (!DS2482_write_config(c1WS | cSPU | cPPM | cAPU))
      return FALSE;

   // perform write byte
   OWWriteByte(sendbyte);

   return TRUE;
}
例14. OWWriteBytePower程序

结论

DS2482已经过测试,可成功完成I²C接口至1-Wire网络的转换。本文给出了基于DS2482 I²C 1-Wire线驱动器的完整的1-Wire接口方案,该接口适用于所有1-Wire器件,所提供的例程可以在任何一个具有I²C通信口的主机上轻松实现。另外还提供可供下载的完整的C语言执行程序。测试平台是CMAXQUSB评估套件

修订历史
11/2005版本1.0–首次发布。
9/2008版本2.0–修改程序以使用低电平I²C通信子程序,修改相应的文字内容。