在没有专用总线主机的情况下,微处理器可以轻松地产生1-Wire?时序信号。本应用笔记给出了一个采用‘C’语言编写、支持标准速率的1-Wire主机通信基本子程序实例。此外,本文也讨论了高速通信模式。要使该实例中的代码正常运行,系统必须满足以下几点要求:
1.微处理器的通信端口必须是双向的,其输出为漏极开路,且线上具有弱上拉。这也是所有1-Wire总线的基本要求。 2.微处理器必须能产生标准速度1-Wire通信所需的精确1μs延时和高速通信所需要的0.25μs延时。 3.通信过程不能被中断。 |
1-Wire总线有四种基本操作:复位、写1位、写0位和读位操作。在产品资料中,将完成一位传输的时间称为一个时隙。于是字节传输可以通过多次调用位操作来实现,下表1是各个位操作的简要说明以及实现这些操作所必须的步骤列表。图1为其时序波形图。表2给出了通常线路条件下1-Wire主机与1-Wire器件通信的最短、最长和推荐时间。如果与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 |
表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'代码中的常量PORTADDRESS (图3)用来定义通信端口的地址。这里我们假定使用通信端口的第0位控制1-Wire总线。设定该位为1,将使1-Wire总线变为低电平;设定该位为0,1-Wire总线将被释放,此时1-Wire总线被电阻上拉,或被1-Wire从器件下拉。
int outp(unsigned port, int databyte);
// read byte from 'port'
int inp(unsigned port);
代码中的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;
}
}
实例2. 基本的1-Wire函数
//-----------------------------------------------------------------------------该程序包括了1-Wire总线的所有位操作,通过调用该程序可以构成以字节为处理对象的函数,见实例3。
// 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;
}
实例3. 派生的1-Wire函数
//-----------------------------------------------------------------------------OWTouchByte函数可以同时完成读写1-Wire总线数据,通过该函数可以实现数据块的读写。在一些平台上执行效率更高, Dallas Semiconductor提供的API就采用了这种函数。通过OWTouchByte函数,OWBlock函数简化了1-Wire总线的数据块发送和接收。注意:OWTouchByte(0xFF)与OWReadByte()等效, OWTouchByte(data)与 OWWriteByte(data)等效。
// 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();
}
这些函数和tickDelay函数一起构成了1-Wire总线进行位、字节和块操作时所必需的全部函数。实例4给出了利用这些函数读取DS2432的SHA-1认证页的实例。
读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 = 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 = 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号。详见《1-Wire搜索算法》一文。
用户387625 2008-11-21 13:55
用户222124 2008-8-8 08:15