摘要:在没有专用总线主机(如DS2480B、DS2490)的情况下,微处理器可以轻松地产生1-Wire时序信号。本应用笔记给出了一个采用‘C’语言编写、支持标准速率的1-Wire主机通信基本子程序实例。1-Wire总线的四个基本操作是:复位、写“1”、写“0”和读数据位。字节操作可以通过反复调用位操作实现,本文提供了通过各种传输线与1-Wire器件进行可靠通信的时间参数。
表1. 1-Wire操作
图1. 1-Wire时序图
表2. 1-Wire主机时序
有关表中这些值的详细计算,可参考:http://files.dalsemi.com/auto_id/public/an126.zip
注释:标准库中。当应用于其它平台时,可以采用合适的函数来替代它们。
代码中的tickDelay函数是一个用户编制的子程序,此函数用于产生一个1/4µs整数倍的延时。在不同的平台下,该函数的实现也是不同的,故在此不做具体描述。以下是tickDelay函数声明代码,以及一个SetSpeed函数,用于设定标准速度和高速模式的延时时间。
这些函数和tickDelay函数一起构成了1-Wire总线进行位、字节和块操作时所必需的全部函数。实例4给出了利用这些函数读取DS2432的SHA-1认证页的实例。
1-Wire公共开发包中含有大量针对特定器件编写的代码,由下列链接提供:
http://www.ibutton.com/software/1wire/wirekit.html
其它更详细的资料请参阅应用笔记155:"1-Wire软件资源指南"。
Maxim提供了采用Verilog和VHDL编写的1-Wire主机。
DS1WM
如需获取1-Wire主机的Verilog/VHDL代码,请提交技术支持申请。
合成的1-Wire主机工作方式在应用笔记120:"利用1-Wire主机通讯"和应用笔记119:"嵌入1-Wire主机"中进行了说明。
有多种1-Wire主机芯片可以作为微处理器的外设。串行、1-Wire线驱动器DS2480B能够很容易地与标准串行口连接。
关于DS2480B的操作,详见应用笔记192:"DS2480B串行接口1-Wire线驱动器的使用")。
这是为远距离1-Wire传输线专门设计的先进的1-Wire线驱动器,在应用笔记244:"性能优异的1-Wire网络驱动器"中,描述了专门为长线设计、更为精细的1-Wire线驱动器。
修订历史记录
07/06/00:1.0版—最初版本。
05/28/02:2.0版—纠正了1-Wire复位采样时间。增加了波形图、链接和更多的代码实例。
02/02/04:2.1版—增加了对高速模式的支持,给出了时序的最小值、最大值,更新了代码实例。
09/06/05:2.2版—修正代码例程说明中的PIO极性。
引言
在没有专用总线主机的情况下,微处理器可以轻松地产生1-Wire时序信号。本应用笔记给出了一个采用‘C’语言编写、支持标准速率的1-Wire主机通信基本子程序实例。此外,本文也讨论了高速通信模式。要使该实例中的代码正常运行,系统必须满足以下几点要求:- 微处理器的通信端口必须是双向的,其输出为漏极开路,且线上具有弱上拉。这也是所有1-Wire总线的基本要求。关于简单的1-Wire主机微处理器电路实例,请参见1-Wire网络可靠设计指南(应用笔记148)的附录A。
- 微处理器必须能产生标准速度1-Wire通信所需的精确1µs延时和高速通信所需要的0.25µs延时。
- 通信过程不能被中断。
表1. 1-Wire操作
Operation | Description | Implementation |
Write 1 bit | Send a '1' bit to the 1-Wire slaves (Write 1 time slot) | Drive bus low, delay A Release bus, delay B |
Write 0 bit | send a '0' bit to the 1-Wire slaves (Write 0 time slot) | Drive bus low, delay C Release bus, delay D |
Read bit | Read a bit from the 1-Wire slaves (Read time slot) | Drive bus low, delay A Release bus, delay E Sample bus to read bit from slave Delay F |
Reset | Reset the 1-Wire bus slave devices and ready them for a command | Delay G Drive bus low, delay H Release bus, delay I Sample bus, 0 = device(s) present, 1 = no device present Delay J |
图1. 1-Wire时序图
表2. 1-Wire主机时序
Parameter | Speed | Min (µs) | Recommended (µs) | Max (µs) | Notes |
A | Standard | 5 | 6 | 15 | 1, 2 |
Overdrive | 1 | 1.5 | 1.85 | 1, 3 | |
B | Standard | 59 | 64 | N/A | 2, 4 |
Overdrive | 7.5 | 7.5 | N/A | 3, 4 | |
C | Standard | 60 | 60 | 120 | 2, 5 |
Overdrive | 7 | 7.5 | 14 | 3, 5 | |
D | Standard | 8 | 10 | N/A | 2, 6 |
Overdrive | 2.5 | 2.5 | N/A | 3, 6 | |
E | Standard | 5 | 9 | 12 | 2, 7, 8 |
Overdrive | 0.5 | 0.75 | 0.85 | 3, 7, 8 | |
F | Standard | 50 | 55 | N/A | 2, 9 |
Overdrive | 6.75 | 7 | N/A | 3, 9 | |
G | Standard | 0 | 0 | 0 | |
Overdrive | 2.5 | 2.5 | N/A | 3, 14 | |
H | Standard | 480 | 480 | 640 | 2, 10, 15 |
Overdrive | 68 | 70 | 80 | 3, 10 | |
I | Standard | 63 | 70 | 78 | 2, 11 |
Overdrive | 7.2 | 8.5 | 8.8 | 3, 11 | |
J | Standard | 410 | 410 | N/A | 2, 12, 13 |
Overdrive | 39.5 | 40 | N/A | 3, 12 |
有关表中这些值的详细计算,可参考:http://files.dalsemi.com/auto_id/public/an126.zip
注释:
- 在产品数据资料中,表示为tW1L (写1低)减去ε (上升至VTH的时间)加上tF (下降至VTL的时间)。
- 假定网络为标准速度的中等距离网络,且上升和下降时间不超过3µs。
- 假定网络为高速的小型网络,且上升和下降时间不超过0.5µs。
- 数据资料中,表示为tSLOT (时隙时间)减去‘A’所代表的时间。
- 数据资料中,表示为tW0L (写0低)减去δ (上升至VIHMASTER的时间)加上tF (下降至VTL的时间)。
- 数据资料中,表示为tREC (恢复时间)加上δ (上升至VIHMASTER的时间)。
- 数据资料中,表示为tMSR (主机采样读时间)加上tF (下降至VTL的时间),再减去‘A’。
- 在该范围内,采样要尽可能晚,以便获得最长的恢复时间。
- 数据资料中,表示为tSLOT (时隙时间)减去‘A’,再减去‘E’。
- 数据资料中,表示为tRSTL (复位为低的时间)减去ε (上升至VTH的时间)加上tF (下降至VTL的时间)。
- 数据资料中,表示为tMSP (主机采样应答时间)加上ε (上升至VTH的时间)。
- 数据资料中,其最小值表示为tRSTL (复位低电平时间)减去‘I’所用的时间。
- 这里所提到的1-Wire复位操作没有把DS2404和DS1994使用的扩展应答(报警)脉冲序列考虑进去,关于这种特殊情况,请查看产品的数据资料。在1-Wire复位序列的未尾进行采样,可以验证1-Wire总线是否已返回到上拉电平。如果电平仍为0,则可能是1-Wire总线与地之间短路,或DS2404/DS1994发出了报警信号。
- 表示为tREC (恢复时间)减去‘D’所用的时间。在高速应用时,一些器件在tRSTL (低电平复位时间)之前要求额外的延时,以保证器件的寄生电源被完全充满。
- 对于低电压工作方式,有些器件可能需要更长的延时。关于合适的参数值,请参阅器件数据资料。
代码实例
下面代码实例都依赖于两个通用的‘C’函数outp和inp,从IO端口读写字节数据。他们通常位于// send 'databyte' to 'port' int outp(unsigned port, int databyte); // read byte from 'port' int inp(unsigned port);代码中的常量PORTADDRESS (图3)用来定义通信端口的地址。这里我们假定使用通信端口的第0位控制1-Wire总线。设定该位为1,将使1-Wire总线变为低电平;设定该位为0,1-Wire总线将被释放,此时1-Wire总线被电阻上拉,或被1-Wire从器件下拉。
代码中的tickDelay函数是一个用户编制的子程序,此函数用于产生一个1/4µs整数倍的延时。在不同的平台下,该函数的实现也是不同的,故在此不做具体描述。以下是tickDelay函数声明代码,以及一个SetSpeed函数,用于设定标准速度和高速模式的延时时间。
实例1. 1-Wire时序的生成
// Pause for exactly 'tick' number of ticks = 0.25us void tickDelay(int tick); // Implementation is platform specific // 'tick' values int A,B,C,D,E,F,G,H,I,J; //----------------------------------------------------------------------------- // Set the 1-Wire timing to 'standard' (standard=1) or 'overdrive' (standard=0). // void SetSpeed(int standard) { // Adjust tick values depending on speed if (standard) { // Standard Speed A = 6 * 4; B = 64 * 4; C = 60 * 4; D = 10 * 4; E = 9 * 4; F = 55 * 4; G = 0; H = 480 * 4; I = 70 * 4; J = 410 * 4; } else { // Overdrive Speed A = 1.5 * 4; B = 7.5 * 4; C = 7.5 * 4; D = 2.5 * 4; E = 0.75 * 4; F = 7 * 4; G = 2.5 * 4; H = 70 * 4; I = 8.5 * 4; J = 40 * 4; } }1-Wire基本操作的代码程序如实例2所示。
实例2. 基本的1-Wire函数
//----------------------------------------------------------------------------- // Generate a 1-Wire reset, return 1 if no presence detect was found, // return 0 otherwise. // (NOTE: Does not handle alarm presence from DS2404/DS1994) // int OWTouchReset(void) { int result; tickDelay(G); outp(PORTADDRESS,0x00); // Drives DQ low tickDelay(H); outp(PORTADDRESS,0x01); // Releases the bus tickDelay(I); result = inp(PORTADDRESS) & 0x01; // Sample for presence pulse from slave tickDelay(J); // Complete the reset sequence recovery return result; // Return sample presence pulse result } //----------------------------------------------------------------------------- // Send a 1-Wire write bit. Provide 10us recovery time. // void OWWriteBit(int bit) { if (bit) { // Write '1' bit outp(PORTADDRESS,0x00); // Drives DQ low tickDelay(A); outp(PORTADDRESS,0x01); // Releases the bus tickDelay(B); // Complete the time slot and 10us recovery } else { // Write '0' bit outp(PORTADDRESS,0x00); // Drives DQ low tickDelay(C); outp(PORTADDRESS,0x01); // Releases the bus tickDelay(D); } } //----------------------------------------------------------------------------- // Read a bit from the 1-Wire bus and return it. Provide 10us recovery time. // int OWReadBit(void) { int result; outp(PORTADDRESS,0x00); // Drives DQ low tickDelay(A); outp(PORTADDRESS,0x01); // Releases the bus tickDelay(E); result = inp(PORTADDRESS) & 0x01; // Sample the bit value from the slave tickDelay(F); // Complete the time slot and 10us recovery return result; }该程序包括了1-Wire总线的所有位操作,通过调用该程序可以构成以字节为处理对象的函数,见实例3。
实例3. 派生的1-Wire函数
//----------------------------------------------------------------------------- // Write 1-Wire data byte // void OWWriteByte(int data) { int loop; // Loop to write each bit in the byte, LS-bit first for (loop = 0; loop < 8; loop++) { OWWriteBit(data & 0x01); // shift the data byte for the next bit data >>= 1; } } //----------------------------------------------------------------------------- // Read 1-Wire data byte and return it // int OWReadByte(void) { int loop, result=0; for (loop = 0; loop < 8; loop++) { // shift the result to get it ready for the next bit result >>= 1; // if result is one, then set MS bit if (OWReadBit()) result |= 0x80; } return result; } //----------------------------------------------------------------------------- // Write a 1-Wire data byte and return the sampled result. // int OWTouchByte(int data) { int loop, result=0; for (loop = 0; loop < 8; loop++) { // shift the result to get it ready for the next bit result >>= 1; // If sending a '1' then read a bit else write a '0' if (data & 0x01) { if (OWReadBit()) result |= 0x80; } else OWWriteBit(0); // shift the data byte for the next bit data >>= 1; } return result; } //----------------------------------------------------------------------------- // Write a block 1-Wire data bytes and return the sampled result in the same // buffer. // void OWBlock(unsigned char *data, int data_len) { int loop; for (loop = 0; loop < data_len; loop++) { data[loop] = OWTouchByte(data[loop]); } } //----------------------------------------------------------------------------- // Set all devices on 1-Wire to overdrive speed. Return '1' if at least one // overdrive capable device is detected. // int OWOverdriveSkip(unsigned char *data, int data_len) { // set the speed to 'standard' SetSpeed(1); // reset all devices if (OWTouchReset()) // Reset the 1-Wire bus return 0; // Return if no devices found // overdrive skip command OWWriteByte(0x3C); // set the speed to 'overdrive' SetSpeed(0); // do a 1-Wire reset in 'overdrive' and return presence result return OWTouchReset(); }OWTouchByte函数可以同时完成读写1-Wire总线数据,通过该函数可以实现数据块的读写。在一些平台上执行效率更高, Maxim提供的API就采用了这种函数。通过OWTouchByte函数,OWBlock函数简化了1-Wire总线的数据块发送和接收。注意:OWTouchByte(0xFF)与OWReadByte()等效,OWTouchByte(data)与OWWriteByte(data)等效。
这些函数和tickDelay函数一起构成了1-Wire总线进行位、字节和块操作时所必需的全部函数。实例4给出了利用这些函数读取DS2432的SHA-1认证页的实例。
实例4. 读DS2432实例
//----------------------------------------------------------------------------- // Read and return the page data and SHA-1 message authentication code (MAC) // from a DS2432. // int ReadPageMAC(int page, unsigned char *page_data, unsigned char *mac) { int i; unsigned short data_crc16, mac_crc16; // set the speed to 'standard' SetSpeed(1); // select the device if (OWTouchReset()) // Reset the 1-Wire bus return 0; // Return if no devices found OWWriteByte(0xCC); // Send Skip ROM command to select single device // read the page OWWriteByte(0xA5); // Read Authentication command OWWriteByte((page << 5) & 0xFF); // TA1 OWWriteByte(0); // TA2 (always zero for DS2432) // read the page data for (i = 0; i < 32; i++) page_data[i] = OWReadByte(); OWWriteByte(0xFF); // read the CRC16 of command, address, and data data_crc16 = OWReadByte(); data_crc16 |= (OWReadByte() << 8); // delay 2ms for the device MAC computation // read the MAC for (i = 0; i < 20; i++) mac[i] = OWReadByte(); // read CRC16 of the MAC mac_crc16 = OWReadByte(); mac_crc16 |= (OWReadByte() << 8); // check CRC16... return 1; }
附加软件
本应用笔记给出了1-Wire总线操作的基本函数,这些基本函数都是构建复杂的1-Wire应用的基础。本文忽略的一个重要操作是1-Wire搜索。通过1-Wire搜索可以搜索到挂接在总线上的多个1-Wire从机器件的唯一ID号。在应用笔记187:"1-Wire搜索算法"一文中详细介绍了这种搜索方法,同时也给出了实现这些1-Wire基本函数的C程序代码。1-Wire公共开发包中含有大量针对特定器件编写的代码,由下列链接提供:
http://www.ibutton.com/software/1wire/wirekit.html
其它更详细的资料请参阅应用笔记155:"1-Wire软件资源指南"。
替换方案
如果对于某一特定应用,通过软件实现1-Wire主机方案不可行,则作为替换方案,可以采用1-Wire主机芯片或合成的1-Wire主机单元。Maxim提供了采用Verilog和VHDL编写的1-Wire主机。
DS1WM
如需获取1-Wire主机的Verilog/VHDL代码,请提交技术支持申请。
合成的1-Wire主机工作方式在应用笔记120:"利用1-Wire主机通讯"和应用笔记119:"嵌入1-Wire主机"中进行了说明。
有多种1-Wire主机芯片可以作为微处理器的外设。串行、1-Wire线驱动器DS2480B能够很容易地与标准串行口连接。
关于DS2480B的操作,详见应用笔记192:"DS2480B串行接口1-Wire线驱动器的使用")。
这是为远距离1-Wire传输线专门设计的先进的1-Wire线驱动器,在应用笔记244:"性能优异的1-Wire网络驱动器"中,描述了专门为长线设计、更为精细的1-Wire线驱动器。
修订历史记录
07/06/00:1.0版—最初版本。
05/28/02:2.0版—纠正了1-Wire复位采样时间。增加了波形图、链接和更多的代码实例。
02/02/04:2.1版—增加了对高速模式的支持,给出了时序的最小值、最大值,更新了代码实例。
09/06/05:2.2版—修正代码例程说明中的PIO极性。
评论
查看更多