Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

Temperature Measurement as an Example of a 1-Wire Technology Application

4.86/5 (35 votes)
2 Feb 2009CPOL4 min read 115.8K   2K  
The article describes how to make a DS9097E adapter and read the temperature from a DS18B20 sensor by using the COneWire class.

Image 1

Introduction

The 1-Wire technology was invented by Dallas Semiconductor Corp.[1] It was designed for a device communication bus system that provides data transmission using two wires: the first for ground, and the second for power and data. The communication is realized between master devices (PC, microcomputer) and slave devices (memory EPROM, temperature sensor, A/D converter, Real Time clock etc.). Although the 1-Wire technology is old, it is still applied in many branches of the industry. The concept of the article is to describe how to construct own the DS9097E adapter and communicate with it. In the Internet, you can find many programs to communicate with 1-Wire devices, but my implementation of the COneWire class is more effective, and it could be easily adopted for the specific applications. For visualization of temperature measurement, I have used the OpenGL library.

Preparation of the DS9097E adapter

If you don't feel up to soldering electronic elements, you could buy the DS9097E adapter. But, I think that doing something by your own could be a good experience and costless.

Elements needed:

  • Printed circuit board 5x7 pins.
  • Two Schockley diodes BAT85.
  • One 3,9 V Zener diode.
  • One 6,2 V Zener diode.
  • One resistor 1,5 KOhm.
  • One RS232 female connector.
  • Two-core cable.
  • One or more DS18B20 temperature sensors.

In Fig. 1, the schematic diagram is described. Be careful while connecting diodes, because they have polarity "+" and "-". The Ready device is presented in Fig. 2. From Fig. 2, you can see that the DS18B20 sensor has three pins whereas we have used only two, why? The DS18B20 sensors could work in two modes. In the first "normal mode", all the pins are connected (ground, data in/out, and power supply voltage). In the second one, where the ground is connected with the power supply, the sensor works using "parasite power". On Fig. 3, the ready circuit board with the soldered elements is shown.

Notice 1: Plug adapter first, then turn on the computer.

Notice 2: If you solder the adapter wrong, it could damage your motherboard.

Image 2

Fig. 1. Schematic diagram of the DS9097E adapter.

Image 3

Fig. 2. Ready DS9097E adapter.

Image 4

Fig. 3. Inside the DS9097E adapter.

The DS9097E adapter which was described in the previous paragraph should be connected to the serial port (COM port). If you do not have any COM-port, you could use a USB to RS232 converter. It will create a virtual COM-port which works as a typical serial port.

Installation of OpenGL and TMEX SDK components

To use the program presented in the article, you should first install the GLUT library[2]. The header files gl.h, glut.h, and glu.h are supposed to be in c:\Program Files\Microsoft Visual Studio\Vc98\Include\GL. It could be changed in the glut.h file. To use 1-Wire devices, Dallas Semiconductor Corp.[1] provides their own drivers. These drivers are included in the TMEX SDK libraries[3]. In the COneWire class, I load the "IBFS32.DLL" library and get access points to the functions included in the library. In the program's directory, "IBFS32.DLL" as well as "IB97E32.DLL" should be placed. In the TMEX SDK documentation, you could find a table where proper DLL files are assigned for different Operating Systems.

Implementation of the COneWire and CDS18B20 classes

After loading the library and setting the initial values in the constructor of COneWire, the StartSesion function should be used. If a 1-Wire device is connected to the COM port by the DS9097E adapter, the function ought to provide a handle to the device. The variables iPortNum and iPortType are the number of the COM-port and the port type which depends on the adapter type. Possible adapter types are listed in the OneWire.h header file.

C++
////////////////////////////////////////////////////////////
// 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;
}

When 1-Wire devices are no longer necessary, the EndSession function should be called. Then, it is possible to start a new session.

C++
////////////////////////////////////////////////////////////
// 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;
    }
}

When a session is initialized successfully, the FindDevices function should be called. All connected 1-Wire devices are detected and their unique ROM codes stored in the ROM table. The FindDevices function also checks whether the obtained ROM code has not been corrupted during data sending.

C++
////////////////////////////////////////////////////////////
// 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;
}

All 1-Wire devices provided by the Dallas Semiconductor Corp.[1] contain two groups of commands. The first one is common for all devices (i.e., devices finding, skip ROM command) and the second is suitable only for one 1-Wire device (i.e., temperature conversion). That is why I have written the base class COneWire and the CDS18B20, an inferior class. The function ReadTemperature modifies two variables, CurrTemp and PrevTemp. It also checks if the data received by the PC was not corrupted.

C++
////////////////////////////////////////////////////////////
// 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;
}

Usage

C++
// 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();
}

Conclusions

The COneWire class enables to communicate with different kinds of 1-Wire devices. It provides many useful functions for sending and receiving commands, writing and reading the scratchpad, and many others. The article described the common applications of 1-Wire devices, like the measurement of the most important physical parameter - temperature.

Bibliography

  1. iButton
  2. GLUT - The OpenGL Utility Toolkit
  3. iButton®: 1-Wire® SDK for Windows

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)