OneWire Temperature library for interfacing DS18B20

Dependents:   DallasTemperature project1

OneWireThermometer.cpp

Committer:
Wimpie
Date:
2011-04-17
Revision:
0:ad90c2e86a63

File content as of revision 0:ad90c2e86a63:

/*
* OneWireThermometer. Base class for Maxim One-Wire Thermometers.
* Uses the OneWireCRC library.
*
* Copyright (C) <2010> Petras Saduikis <petras@petras.co.uk>
*
* This file is part of OneWireThermometer.
*
* OneWireThermometer is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OneWireThermometer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OneWireThermometer.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "OneWireThermometer.h"
#include "OneWireDefs.h"
#include "DebugTrace.h"

DebugTrace pc(ON, TO_SERIAL);

// constructor specifies standard speed for the 1-Wire comms
OneWireThermometer::OneWireThermometer(PinName pin, bool crcOn, bool useAddr, bool parasitic, int device_id, unsigned char *ROMaddress)
        :oneWire(pin, STANDARD) {
    _useCRC=crcOn;
    _useAddress=useAddr;
    _useParasiticPower=parasitic;
    _deviceId= device_id;
    _resolution=twelveBit;

    if (_useAddress) {
        for (int i = 0; i < ADDRESS_SIZE; i++)
            _ROMCode[i]=ROMaddress[i];
    } else {
        for (int i = 0; i < ADDRESS_SIZE; i++)
            _ROMCode[i]=0;
    }

    // NOTE: the power-up resolution of a DS18B20 is 12 bits. The DS18S20's resolution is always
    // 9 bits + enhancement, but we treat the DS18S20 as fixed to 12 bits for calculating the
    // conversion time Tconv.

}

bool OneWireThermometer::initialize() {

    int OneWireFound;
    int OneWireSameAddress;
    int i;
    BYTE _dummyaddress[8];


    if (_useAddress) {
        pc.traceOut("Scan for device with address ");
        for (i = 0; i < ADDRESS_SIZE; i++) {
            pc.traceOut("%x ", (int)_ROMCode[i]);
        }
        pc.traceOut("\r\n");
    }
    OneWireSameAddress=0;

    oneWire.resetSearch();
    do {
        OneWireFound=(oneWire.search(_dummyaddress));
        if (OneWireFound) {

            if (!_useAddress) {
                pc.traceOut("Device found with Address = ");
                for (i = 0; i < ADDRESS_SIZE; i++) {
                    pc.traceOut("%x ", (int)_dummyaddress[i]);
                }
            }
            OneWireSameAddress=1;

            if (_useAddress) {
                for (i = 0; i < ADDRESS_SIZE; i++) {
                    if (!((OneWireSameAddress) && (_ROMCode[i] ==_dummyaddress[i])))
                        OneWireSameAddress=0;
                }
            } else {
                for (i = 0; i < ADDRESS_SIZE; i++) {
                    _ROMCode[i] =_dummyaddress[i];
                }
            }

            /*           if (OneWireSameAddress) {
                           pc.traceOut("-> Address valid!\r\n");

                       } else {
                           pc.traceOut("-> Address NOT valid.\r\n");
                       }*/

        } else {

            pc.traceOut("No more addresses.\r\n");
            oneWire.resetSearch();
            wait_ms(250);  //500
        }
    } while (OneWireFound && !OneWireSameAddress);

    if (!OneWireSameAddress) {
        pc.traceOut("-> No Valid ROM Code found.\r\n");
        return false;
    }

    if (OneWireCRC::crc8(_ROMCode, ADDRESS_CRC_BYTE) != _ROMCode[ADDRESS_CRC_BYTE]) { // check address CRC is valid
        pc.traceOut("CRC is not valid!\r\n");
        // wait_ms(500);
        return false;
    }

    if (_ROMCode[0] != _deviceId) {
        // Make sure it is a one-wire thermometer device
        if (DS18B20_ID == _deviceId)
            pc.traceOut("You need to use a DS1820 or DS18S20 for correct results.\r\n");
        else if (DS18S20_ID == _deviceId)
            pc.traceOut("You need to use a DS18B20 for correct results.\r\n");
        else
            pc.traceOut("Device is not a DS18B20/DS1820/DS18S20 device.\r\n");

        //  wait_ms(500);
        return false;
    } else {
        if (DS18B20_ID == _deviceId) pc.traceOut("DS18B20 present and correct.\r\n");
        if (DS18S20_ID == _deviceId) pc.traceOut("DS1820/DS18S20 present and correct.\r\n");
    }


    return true;
}

// NOTE ON USING SKIP ROM: ok to use before a Convert command to get all
// devices on the bus to do simultaneous temperature conversions. BUT can
// only use before a Read Scratchpad command if there is only one device on the
// bus. For purpose of this library it is assumed there is only one device
// on the bus.

void OneWireThermometer::resetAndAddress() {
    oneWire.reset();                // reset device
    if (_useAddress) {
        oneWire.matchROM(_ROMCode);  // select which device to talk to
    } else {
        oneWire.skipROM();          // broadcast
    }
}

bool OneWireThermometer::readAndValidateData(BYTE* data) {
    bool dataOk = true;

    resetAndAddress();
    oneWire.writeByte(DS18X20_READSCRATCH);    // read Scratchpad

    // pc.traceOut("read = ");
    for (int i = 0; i < THERMOM_SCRATCHPAD_SIZE; i++) {
        // we need all bytes which includes CRC check byte
        data[i] = oneWire.readByte();
        //   pc.traceOut("%x ", (int)data[i]);
    }
    //pc.traceOut("\r\n");

    // Check CRC is valid if you want to
    if (_useCRC && !(OneWireCRC::crc8(data, THERMOM_CRC_BYTE) == data[THERMOM_CRC_BYTE])) {
        // CRC failed
        pc.traceOut("CRC FAILED... \r\n");
        dataOk = false;
    }

    return dataOk;
}

float OneWireThermometer::readTemperature() {
    BYTE data[THERMOM_SCRATCHPAD_SIZE];
    float realTemp = -999;
    int i = 0;

    do {

        resetAndAddress();
        oneWire.writeByte(CONVERT);     // issue Convert command

        if (_useParasiticPower) {
            // wait while converting - Tconv (according to resolution of reading)
            wait_ms(CONVERSION_TIME[_resolution]);
        } else {
            // TODO
            // after the Convert command, the device should respond by transmitting 0
            // while the temperature conversion is in progress and 1 when the conversion is done
            // - as were are not checking this (TODO), we use Tconv, as we would do for
            // parasitic power
            wait_ms(CONVERSION_TIME[_resolution]);
        }

        if (readAndValidateData(data)) {  // issue Read Scratchpad commmand and get data
            realTemp = calculateTemperature(data);
            i++;
        }
    } while ((realTemp==-999) && (i<5));

    return realTemp;
}