摘要:本应用笔记从理论上逐步阐述了如何充分利用1-Wire®功能,并列举了一些示例。1-Wire主机已被设计到客户的ASIC芯片中,主控CPU用于读取1-Wire温度传感器的数值。所提供的源代码用于1WM对4个温度传感器发送温度转换指令,并提供转换温度。假设读者已经了解DS18B20温度传感器、DS1WM 1-Wire主机以及Dallas Semiconductor的1-Wire协议。
引言
DS1WM 1-Wire主机为单总线控制器,专为简化主控CPU与周边1-Wire器件之间的单总线通讯而设计,利用DS1WM不必考虑位时序。本应用笔记从理论上逐步阐述了如何充分利用1-Wire功能,并列举了一些示例。假设读者已经了解DS18B20温度传感器、DS1WM 1-Wire主机以及Dallas Semiconductor 1-Wire通讯协议,详细资料请参考:Book of iButton Standards (PDF), DS1WM数据资料, DS18B20数据资料, 应用笔记119:嵌入1-Wire主机。
 图1. 示例电路
图1是以下示例所参考的电路配置,1-Wire主机已被设计到客户的ASIC芯片中,主控CPU通过它对4个DS18B20温度传感器发送温度转换命令,并读取转换的温度值。1-Wire总线和INTR均上拉一个5k电阻,50MHz的系统时钟通过CLK引脚为1-Wire主机提供时钟信号。1-Wire主机已被映射到CPU的端口地址存储器中。
概述
本示例的程序采用C语言编写,主程序为:GetTemperatures,它完成1-Wire主机的初始化,搜索1-Wire总线上的所有器件,并指定它们测量温度,然后将测量值送回CPU并存储。如果总线上没有1-Wire器件,则退出主程序并返回值“1”,否则,则返回值0。其它函数将在下面详细描述。程序中的常数BASE是1-Wire主机被映射到CPU地址空间中的地址。TEMPS和ROMS是全局变量。
//individual Serial #s and readings
#define DEVICES 4
int ROMS[DEVICES][8];
int TEMPS[DEVICES];
int GetTemperatures(int BASE)
{
// init. the 1-Wire Master
Initialize(BASE);
// exit if no devices can be found
if(Reset(BASE)) return(1);
// find all individual Serial#s
FindROMs(BASE);
// Convert temp. and read devices
ConvertT(BASE);
ReadTemps(BASE);
return(0);
}
运行程序
主控制器首先向时钟分频寄存器写入合适的控制字,使DS1WM得到正确的时序,初始化1-Wire主机。50MHz输入时钟对应的数字是:0x0Fh (见DS1WM数据资料)。主控制器初始化INTR是通过向中断使能寄存器写入0x3Dh实现的。这样,当有数据发送或复位完成后,INTR引脚将产生低电平中断请求信号。
void Initialize(int BASE)
{
// Divide the clock
outp(BASE+4,0x0F);
// Generate INTs on reset and send
outp(BASE+3,0x09);
}
主控制器必须确定1-Wire总线上是否有器件,为此,通过向命令寄存器写入0x01,产生一个复位信号,等待中断信号产生。收到中断信号后,CPU读取中断寄存器的值,如果第2位为低,则表明总线上有器件存在,否则,说明没有1-Wire器件或总线有故障,需采取适当措施。WaitforInterrupt()函数本文并未做定义,用户可以自行定义该等待程序,保证主程序执行需要完成的任务。
int Reset(int BASE)
{
outp(BASE,0x02); // send reset
WaitforInterrupt();
if(inp(BASE+2) & 0x02)
return(1); //no presence found
else
return(0); //presence found
}
主控制器必须获知1-Wire总线上每个器件的ROM序列号,通过运行Search ROM算法获得1-Wire器件的序列号。主机向从机发送Search ROM命令,使1-Wire主机进入搜索模式;然后,主机基于前一次搜索读到的ROM代码发送16位搜索值,第一次运行时,该搜索值为0x00,返回的16位值包含新搜索到的ROM代码,用于产生下次搜索所需参数。
重复搜索过程,直到发现相同的序列号为止。本示例中查找到4个器件,由于存储空间只分配存储4个ROM码,因此只需4次就能完成该循环。RecoverROM函数将产生新的发送数据,并从最近收到的数据中提取新的ROM代码。完整的RecoverROM函数附在本应用笔记后,搜索程序的详细描述见DS1WM数据资料。
int FindROMs(int BASE)
{
int loop;
int dev;
int TData[16];
int RData[16];
// reset RecoverROM and generate the
// starting TData
RecoverROM(NULL,TData,NULL);
//run once for each device
for(dev=0;dev<4;dev++)
{
outp(BASE,0x01); // send reset
WaitforInterrupt();
outp(BASE+1,0xF0); // send SeachROM
WaitforInterrupt();
// enter Accelerator mode
outp(BASE,0x02);
// transmit the TDATA and receive
// the RDATA.
for(loop=0;loop<16;loop++)
{
outp(BASE+1,TData[loop]);
WaitforInterrupt();
inp(BASE+1,RData[loop]);
}
//decode recovered ROM and generate
//next Search value
RecoverROM(RDATA,TData,ROMS[dev]);
}
}
寻找到的唯一序列号可用于以后每个1-Wire器件的数据读取,利用该序列号不再需要给所有器件发送读写命令。通过写入0x44h,主控制器命令所有从机器件执行温度转换命令。总线复位后,温度转换命令紧随Skip ROM (0xCC) 命令,可以同时发送到所有的1-Wire器件。
int ConvertT(int BASE)
{
outp(BASE,0x01); // send reset
WaitforInterrupt();
outp(BASE+1,0xCC); // skip ROM
WaitforInterrupt();
outp(BASE+1,0x44); // convert Temp.
WaitforInterrupt();
DS18B20温度转换速度很快,无须等待时间。主控制器必须逐个访问从机器件读取它们的温度。总线复位后,主控制器发送一个Match ROM命令和64位序列号,然后是读取缓存器命令。之后,主控制器读取2个字节的温度信息,注意:在1-Wire总线上读数时,必须先发送0xFFh。由这2个字节得到一个16位的温度值。该流程对每个器件重复循环一次。
int ReadTemps(int BASE)
{
int dev,loop;
int LSB,MSB;
for(dev=0;dev<4;dev++)
{
outp(BASE,0x01); // send reset
WaitforInterrupt();
outp(BASE+1,0x55); // match ROM
WaitforInterrupt();
// send 8 bytes of ROM code
for(loop=0;loop<8;loop++)
{
outp(BASE+1,ROMS[dev][loop]);
WaitforInterrupt();
}
outp(BASE+1,0xBE); // read memory
WaitforInterrupt();
outp(BASE+1,0xFF); // read LSB
WaitforInterrupt();
LSB = inp(BASE+1);
outp(BASE+1,0xFF); // read MSB
WaitforInterrupt();
MSB = inp(BASE+1);
TEMPS[dev] = MSB<<8 + LSB;
}
}
程序运行完成后,GetTemperatures函数要么返回一个值“1”,表明总线上无器件;要么返回一个值“0”,利用从4个1-Wire器件获得的数字,更新ROM代码和温度值。
如果已知器件的ROM代码,可以跳过整个Search ROM程序。如果总线上只有一个器件,其ROM序列号不必搜索,每次处理时,执行Skip ROM命令。
如果无法提供中断请求信号线,则WaitforInterrupt函数可以编写成通过查询中断寄存器完成命令。然而这样一来,CPU必须等待1-Wire主机完成其操作。
RecoverROM源代码
下面提供的源代码包含用于产生16字节发送值的用户代码,并从Search ROM过程中获得的16个字节中提取最新的ROM码。
该函数需要16字节接收数据、16字节发送数据和8字节ROM码的指针。如果总线上仍有未知器件,该函数将返回值“0”,当总线上所有器件均被找到时则返回值“1”,这一特性在上述例子中未采用。
该函数没有出错检验,因此,如果总线上无器件,则发现的ROM代码是错误的。
/////////////////////////////////////////////////////////////////////////////////
// RecoverROM performs two functions. Given 16 bytes of receive data taken from
// the 1-Wire Master during a Search ROM function, it will extract the ROM code
// found into an 8 byte array and it will generate the next 16 bytes to be trans-
// mitted during the next Search ROM.
// RecoverROM must be initialized by sending a NULL pointer in ReceivedData. It
// will write 16 bytes of zeros into TransmitData and clear the discrepancy tree.
// The discrepancy tree keeps track of which ROM discrepancies have already been
// explored.
// RecoverROM also returns a value telling whether there are any more ROM codes to
// be found. If a zero is returned, there are still discrepancies. If a one is
// returned all ROMs on the bus have been found. Running RecoverROM again in this
// case will result in repeating ROM codes already found
////////////////////////////////////////////////////////////////////////////////
int RecoverROM(int* ReceiveData, int* TransmitData, int* ROMCode)
{
int loop;
int result;
int TROM[64]; // the transmit value being generated
int RROM[64]; // the ROM recovered from the received data
int RDIS[64]; // the discrepancy bits in the received data
static int TREE[64]; // used to keep track of which discrepancy bits have
// already been flipped.
// If receivedata is NULL, this is the first run. Transmit data should be all
// zeros, and the discrepancy tree must also be reset.
if(ReceiveData == NULL)
{
for(loop = 0; loop < 64; loop++) TREE[loop] = 0;
for(loop = 0; loop < 16; loop++) TransmitData[loop] = 0;
return 1;
}
// de-interleave the received data into the new ROM code and the discrepancy bits
for(loop = 0; loop < 16; loop++)
{
if((ReceiveData[loop] & 0x02) == 0x00) RROM[loop*4] = 0; else RROM[loop*4 ] = 1;
if((ReceiveData[loop] & 0x08) == 0x00) RROM[loop*4+1] = 0; else RROM[loop*4+1] = 1;
if((ReceiveData[loop] & 0x20) == 0x00) RROM[loop*4+2] = 0; else RROM[loop*4+2] = 1;
if((ReceiveData[loop] & 0x80) == 0x00) RROM[loop*4+3] = 0; else RROM[loop*4+3] = 1;
if((ReceiveData[loop] & 0x01) == 0x00) RDIS[loop*4] = 0; else RDIS[loop*4 ] = 1;
if((ReceiveData[loop] & 0x04) == 0x00) RDIS[loop*4+1] = 0; else RDIS[loop*4+1] = 1;
if((ReceiveData[loop] & 0x10) == 0x00) RDIS[loop*4+2] = 0; else RDIS[loop*4+2] = 1;
if((ReceiveData[loop] & 0x40) == 0x00) RDIS[loop*4+3] = 0; else RDIS[loop*4+3] = 1;
}
// initialize the transmit ROM to the recovered ROM
for(loop = 0; loop < 64; loop++) TROM[loop] = RROM[loop];
// work through the new transmit ROM backwards setting every bit to 0 until the
// most significant discrepancy bit which has not yet been flipped is found.
// The transmit ROM bit at that location must be flipped.
for(loop = 63; loop >= 0; loop--)
{
// This is a new discrepancy bit. Set the indicator in the tree, flip the
// transmit bit, and then break from the loop.
if((TREE[loop] == 0) && (RDIS[loop] == 1) && (TROM[loop] == 0))
{
TREE[loop] = 1;
TROM[loop] = 1;
break;
}
if((TREE[loop] == 0) && (RDIS[loop] == 1) && (TROM[loop] == 1))
{
TREE[loop] = 1;
TROM[loop] = 0;
break;
}
// This bit has already been flipped, remove it from the tree and continue
// setting the transmit bits to zero.
if((TREE[loop] == 1) && (RDIS[loop] == 1)) TREE[loop] = 0;
TROM[loop] = 0;
}
result = loop; // if loop made it to -1, there are no more discrepancy bits
// and the search can end.
// Convert the individual transmit ROM bit into a 16 byte format
// every other bit is don't care.
for(loop = 0; loop < 16; loop++)
{
TransmitData[loop] = (TROM[loop*4]<<1) +
(TROM[loop*4+1]<<3) +
(TROM[loop*4+2]<<5) +
(TROM[loop*4+3]<<7);
}
// Convert the individual recovered ROM bits into an 8 byte format
for(loop = 0; loop < 8; loop++)
{
ROMCode[loop] = (RROM[loop*8]) +
(RROM[loop*8+1]<<1) +
(RROM[loop*8+2]<<2) +
(RROM[loop*8+3]<<3) +
(RROM[loop*8+4]<<4) +
(RROM[loop*8+5]<<5) +
(RROM[loop*8+6]<<6) +
(RROM[loop*8+7]<<7);
}
if(result == -1) return 1; // There are no DIS bits that haven't been flipped
// Tell the main loop the seach is over
return 0; // else continue
}
1-Wire是Maxim Integrated Products, Inc.的注册商标。
我们期待您的反馈! 喜欢?不喜欢?有待改善?或为我们提供建议?请与我们联系 — 我们将根据您的意见或建议改善我们的工作。
网页评价或提供建议
自动更新
需要自动接收最新发布的应用笔记吗?请订阅EE-Mail™ (English only)。
| 更多信息 | |
APP 120: Sep 03, 2004
|
|
|
|
下载,PDF格式 (46kB)
AN120,
AN 120,
APP120,
Appnote120,
Appnote 120
|
|