65.9K
CodeProject 正在变化。 阅读更多。
Home

温度测量作为 1-Wire 技术应用示例

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (33投票s)

2009年2月2日

CPOL

4分钟阅读

viewsIcon

116881

downloadIcon

2036

本文介绍了如何使用 COneWire 类制作 DS9097E 适配器并通过其读取 DS18B20 传感器的数据。

引言

1-Wire 技术由 Dallas Semiconductor 公司发明[1]。它是一种设备通信总线系统,使用两根线进行数据传输:一根用于接地,另一根用于供电和数据。通信在主设备(PC、微型计算机)和从设备(存储器 EPROM、温度传感器、A/D 转换器、实时时钟等)之间进行。尽管 1-Wire 技术已经存在很久,但它仍在许多行业中得到应用。本文的目的是描述如何自行构建 DS9097E 适配器并与其进行通信。在互联网上,您可以找到许多与 1-Wire 设备通信的程序,但我的 COneWire 类的实现更有效,并且可以轻松地适应特定应用。我使用了 OpenGL 库来可视化温度测量。

DS9097E 适配器准备

如果您不擅长焊接电子元件,可以购买 DS9097E 适配器。但我认为自己动手做会是一次不错的且免费的体验。

所需元件

  • 5x7 针脚印刷电路板。
  • 两颗 BAT85 肖特基二极管。
  • 一颗 3.9V 齐纳二极管。
  • 一颗 6.2V 齐纳二极管。
  • 一颗 1.5K 欧姆电阻。
  • 一个 RS232 母头连接器。
  • 两芯电缆。
  • 一个或多个 DS18B20 温度传感器。

图 1 描述了电路图。连接二极管时要小心,因为它们有“+”和“-”极性。成品设备如图 2 所示。从图 2 可以看出,DS18B20 传感器有三个引脚,而我们只使用了两个,为什么呢?DS18B20 传感器有两种工作模式。第一种是“正常模式”,所有引脚都连接(地、数据输入/输出和供电电压)。第二种模式是地与供电连接,传感器使用“寄生电源”工作。图 3 显示了焊接好元件的成品电路板。

注意 1:先插入适配器,再开启电脑。

注意 2:如果适配器焊接错误,可能会损坏您的主板。

图 1. DS9097E 适配器的电路图。

图 2. 成品 DS9097E 适配器。

图 3. DS9097E 适配器内部。

上面介绍的 DS9097E 适配器应连接到串行端口(COM 端口)。如果您没有 COM 端口,可以使用 USB 转 RS232 转换器。它会创建一个虚拟 COM 端口,其功能与典型串行端口相同。

OpenGL 和 TMEX SDK 组件的安装

要使用本文中的程序,您需要先安装 GLUT 库[2]。头文件 gl.h、glut.h 和 glu.h 应该位于 c:\Program Files\Microsoft Visual Studio\Vc98\Include\GL。这可以在 glut.h 文件中更改。为了使用 1-Wire 设备,Dallas Semiconductor 公司[1]提供了自己的驱动程序。这些驱动程序包含在 TMEX SDK 库[3]中。在 COneWire 类中,我加载了“IBFS32.DLL”库并获取了库中函数的访问入口点。在程序的目录下,应该放置“IBFS32.DLL”以及“IB97E32.DLL”。在 TMEX SDK 文档中,您可以找到一个表格,其中列出了适用于不同操作系统的正确 DLL 文件。

COneWire 和 CDS18B20 类的实现

加载库并在 COneWire 的构造函数中设置初始值后,应该使用 StartSesion 函数。如果 1-Wire 设备通过 DS9097E 适配器连接到 COM 端口,该函数应提供设备的句柄。变量 iPortNum 和 iPortType 分别是 COM 端口号和端口类型,端口类型取决于适配器类型。可能的适配器类型在 OneWire.h 头文件中列出。

////////////////////////////////////////////////////////////
// Initializing MicroLan for specified iPort, iPortType.
////////////////////////////////////////////////////////////
bool COneWire::StartSession()
{
    int result;
    if (hInst != NULL)
    {
        SHandle = TMExtendedStartSession(iPortNum,iPortType,NULL);
        if(SHandle > 0)
        {
            // must be called before any non-session functions can be called
            result = TMSetup(SHandle);
            if(result == 1)
            {
                // MicroLan is valid and setup
                iError = OW_NO_ERROR;
                return true;
            }
            else if(result == 0)
            {
                iError = OW_SETUP_FAILED;
                return false;
            }
            else if(result == 2)
            {
                iError = OW_SETUP_MICROLAN_SHORTED;
                return false;
            }
            else if(result == 3)
            {
                iError = OW_SETUP_MICROLAN_NOT_EXIST;
                return false;
            }
            else if(result == 4)
            {
                iError = OW_SETUP_NOT_SUPPORTED;
                return false;
            }
            else
            {
                iError = OW_SESSION_INVALID;
                return false;
            }
        }
        else if(SHandle == 0)
        {
            iError = OW_SESSION_PORT_NOT_AVAILABLE;
            return false;
        }
        else if(SHandle == -1)
        {
            iError = OW_SESSION_NO_DRIVER;
            return false;
        }
        else
        {
            iError = OW_FUN_TMExtendedStartSession;
            return false;
        }
    }
    iError = OW_SESSION_NO_DRIVER;
    return false;
}

当不再需要 1-Wire 设备时,应调用 EndSession 函数。然后,可以启动新的会话。

////////////////////////////////////////////////////////////
// Closing current session for 1-Wire devices.
////////////////////////////////////////////////////////////
bool COneWire::EndSession()
{
    int result;

    if(SHandle > 0)
    {
        result = TMEndSession(SHandle);
        SHandle = NULL;

        if(result == 1)
        {
            iError = OW_NO_ERROR;
            return true;
        }
        else if(result == 0)
        {
            iError = OW_SESSION_HANDLE_ALREADY_INVALID;
            return false;
        }
        else
        {
            iError = OW_FUN_TMEndSession;
            return false;
        }
    }
    else
    {
        iError = OW_SESSION_STOPPED;
        return false;
    }
}

当会话成功初始化后,应调用 FindDevices 函数。所有连接的 1-Wire 设备都会被检测到,并且它们的唯一 ROM 代码会被存储在 ROM 表中。FindDevices 函数还会检查获取到的 ROM 代码在数据发送过程中是否损坏。

////////////////////////////////////////////////////////////
// Finding all connected 1-Wire devices. The function
// returns number of all devices that were found.
////////////////////////////////////////////////////////////
int COneWire::FindDevices()
{
    int didsetup,result, <doce>DevId,i;

    if (SHandle > 0)
    {
        didsetup = 0;
        DevId = 0;
        while(1)
        {
            // check to see if TMSetup has been done once
            if (!didsetup)
            {
                result = TMSetup(SHandle);
                if(result == 1)
                    didsetup = 1;
                else if(result == 0)
                {
                    iError = OW_SETUP_FAILED;
                    return 0;
                }
                else if(result == 2)
                {
                    iError = OW_SETUP_MICROLAN_SHORTED;
                    return 0;
                }
                else if(result == 3)
                {
                    iError = OW_SETUP_MICROLAN_NOT_EXIST;
                    return 0;
                }
                else if(result == 4)
                {
                    iError = OW_SETUP_NOT_SUPPORTED;
                    return 0;
                }
                else
                {
                    iError = OW_SESSION_INVALID;
                    return 0;
                }
            }
            else
            {
                // only get the next rom after setup complete
                result = TMNext(SHandle,(void far*)StateBuffer);
                if (result > 0)
                {
                    ROM[DevId][0] = 0;
                    result = TMRom(SHandle,(void far *)StateBuffer,(short far *)ROM[DevId]);
                
                    //CRC check:
                    CRC8 = 0;
                    for(i=0;i<7;i++)
                    DoCrc((unsigned char)ROM[DevId][i]);
                    if(DoCrc((unsigned char)ROM[DevId][7]) != 0)
                    {
                        iError = OW_CRC_ERROR;
                        for (i = 0; i < 8; i++)
                        ROM[DevId][i] = 0;
                        return 0;
                    }
                    DevId++;
                }
                else
                    break;
            }
        }
    }
    else
    {
        iError = OW_SESSION_INVALID;
        return 0;
    }

    if(!DevId)
    {
        iError = OW_ZERO_DEVICES;
        return 0;
    }

    iError = OW_NO_ERROR;
    NumberOfDev = DevId;
    return NumberOfDev;
}

Dallas Semiconductor 公司[1]提供的所有 1-Wire 设备都包含两组命令。第一组是所有设备通用的(例如,设备查找、跳过 ROM 命令),第二组仅适用于一种 1-Wire 设备(例如,温度转换)。这就是为什么我编写了基类 COneWire 和其派生类 CDS18B20。ReadTemperature 函数修改两个变量 CurrTemp 和 PrevTemp。它还检查发送到 PC 的数据是否损坏。

////////////////////////////////////////////////////////////
// Procedure for reading temperature from specified device.
////////////////////////////////////////////////////////////
bool CDS18B20::ReadTemperature()
{
    unsigned char DATA[10];
    unsigned long st;
    int i;

    if (TMAccess(SHandle,&StateBuffer) != 1)
    {
        iError = OW_NO_PRESENCE;
        return false;
    }

    if(!Reset())
    {
        iError = OW_NO_PRESENCE;
        return false;
    }

    TMTouchByte(SHandle,0x55);

    if(!SendROM())
    {
        iError = OW_NO_PRESENCE;
        return false;
    }

    TMOneWireLevel(SHandle,0,1,2);
    TMTouchByte(SHandle,0x44);
    st = GetTickCount() + 1000; 
    while (GetTickCount() < st)
    TMValidSession(SHandle);
    TMOneWireLevel(SHandle,0,0,0);
    if(!Reset())
    {
        iError = OW_NO_PRESENCE;
        return false;
    }

    TMTouchByte(SHandle,0x55);
    if(!SendROM())
    {
        iError = OW_NO_PRESENCE;
        return false;
    }

    TMTouchByte(SHandle,0xBE);

    // check CRC8
    CRC8 = 0;
    for(i=0;i<8;i++)
    {
        DATA[i] = (unsigned char)TMTouchByte(SHandle,(short)0xFF);
        DoCrc(DATA[i]);
    }
    
    if(DoCrc((unsigned char)TMTouchByte(SHandle,(short)0xFF)) != 0)
    {
        iError = OW_CRC_ERROR;
        return false;
    }

    iError = OW_NO_ERROR;
    PrevTemp = CurrTemp;
  
    // TLSB -> DATA[0], TMSB -> DATA[1]
    CurrTemp = ((float)DATA[0] + ((float)DATA[1]*256.0f))/16.0f;
    return true;
}

用法

// connecting to com port 1
CDS18B20 term("IBFS32.DLL",OW_ADAPTER_DS9097E,1);

void main()
{
    Resolution res;
    short th,tl;

    if(term.StartSession())
    {
        if(!term.FindDevices())
        exit(-1);
        term.SetDevice(0); // selecting the firs device
        term.ReadScratchpad(&res,&tl,&th);
           // setting resolution to 12-bit, 
           // low temp. alarm 0 deg., high temp. alarm 20 deg.
        if(res != DS18B20_RES_12)
        // if resolution in DS18B20 is less than 12 then change it
        {
            term.WriteScratchpad(DS18B20_RES_12,0x0,0x14);
            term.CopyScratchpadToEEPROM(); // copies settings to EEPROM
        }
    }
    
    /* ... */

    while(!_kbhit())
    {
        if(term.ReadTemperature() && 
          (term.GetCurrTemp() != term.GetPrevTemp()))
        {
            /* display temperature */
        }
    }

    term.EndSession();
}

结论

COneWire 类能够与不同种类的 1-Wire 设备进行通信。它提供了许多有用的函数,用于发送和接收命令、读写暂存器等等。本文介绍了 1-Wire 设备的常见应用,例如测量最重要的物理参数——温度。

参考文献

  1. iButton
  2. GLUT - OpenGL 工具包
  3. iButton®:适用于 Windows 的 1-Wire® SDK
© . All rights reserved.