Mercurial > code > home > repos > homeauto
diff service/arduinoNode/arduino-libraries/DallasTemperature/DallasTemperature.cpp @ 165:af4e9d9f0bd8
some external arduino libs, minus examples and docs
Ignore-this: 444126f11a1755109b3b29cbeaa6b9bd
author | drewp@bigasterisk.com |
---|---|
date | Sat, 11 Apr 2015 01:43:14 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/arduinoNode/arduino-libraries/DallasTemperature/DallasTemperature.cpp Sat Apr 11 01:43:14 2015 -0700 @@ -0,0 +1,760 @@ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// Version 3.7.2 modified on Dec 6, 2011 to support Arduino 1.0 +// See Includes... +// Modified by Jordan Hochenbaum + +#include "DallasTemperature.h" + +#if ARDUINO >= 100 +#include "Arduino.h" +#else +extern "C" { +#include "WConstants.h" +} +#endif + +DallasTemperature::DallasTemperature(OneWire* _oneWire) +#if REQUIRESALARMS + : _AlarmHandler(&defaultAlarmHandler) +#endif +{ + _wire = _oneWire; + devices = 0; + parasite = false; + bitResolution = 9; + waitForConversion = true; + checkForConversion = true; +} + +// initialise the bus +void DallasTemperature::begin(void) +{ + DeviceAddress deviceAddress; + + _wire->reset_search(); + devices = 0; // Reset the number of devices when we enumerate wire devices + + while (_wire->search(deviceAddress)) + { + if (validAddress(deviceAddress)) + { + if (!parasite && readPowerSupply(deviceAddress)) parasite = true; + + ScratchPad scratchPad; + + readScratchPad(deviceAddress, scratchPad); + + bitResolution = max(bitResolution, getResolution(deviceAddress)); + + devices++; + } + } +} + +// returns the number of devices found on the bus +uint8_t DallasTemperature::getDeviceCount(void) +{ + return devices; +} + +// returns true if address is valid +bool DallasTemperature::validAddress(const uint8_t* deviceAddress) +{ + return (_wire->crc8(deviceAddress, 7) == deviceAddress[7]); +} + +// finds an address at a given index on the bus +// returns true if the device was found +bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index) +{ + uint8_t depth = 0; + + _wire->reset_search(); + + while (depth <= index && _wire->search(deviceAddress)) + { + if (depth == index && validAddress(deviceAddress)) return true; + depth++; + } + + return false; +} + +// attempt to determine if the device at the given address is connected to the bus +bool DallasTemperature::isConnected(const uint8_t* deviceAddress) +{ + ScratchPad scratchPad; + return isConnected(deviceAddress, scratchPad); +} + +// attempt to determine if the device at the given address is connected to the bus +// also allows for updating the read scratchpad +bool DallasTemperature::isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad) +{ + readScratchPad(deviceAddress, scratchPad); + return (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]); +} + +// read device's scratch pad +void DallasTemperature::readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad) +{ + // send the command + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(READSCRATCH); + + // TODO => collect all comments & use simple loop + // byte 0: temperature LSB + // byte 1: temperature MSB + // byte 2: high alarm temp + // byte 3: low alarm temp + // byte 4: DS18S20: store for crc + // DS18B20 & DS1822: configuration register + // byte 5: internal use & crc + // byte 6: DS18S20: COUNT_REMAIN + // DS18B20 & DS1822: store for crc + // byte 7: DS18S20: COUNT_PER_C + // DS18B20 & DS1822: store for crc + // byte 8: SCRATCHPAD_CRC + // + // for(int i=0; i<9; i++) + // { + // scratchPad[i] = _wire->read(); + // } + + + // read the response + + // byte 0: temperature LSB + scratchPad[TEMP_LSB] = _wire->read(); + + // byte 1: temperature MSB + scratchPad[TEMP_MSB] = _wire->read(); + + // byte 2: high alarm temp + scratchPad[HIGH_ALARM_TEMP] = _wire->read(); + + // byte 3: low alarm temp + scratchPad[LOW_ALARM_TEMP] = _wire->read(); + + // byte 4: + // DS18S20: store for crc + // DS18B20 & DS1822: configuration register + scratchPad[CONFIGURATION] = _wire->read(); + + // byte 5: + // internal use & crc + scratchPad[INTERNAL_BYTE] = _wire->read(); + + // byte 6: + // DS18S20: COUNT_REMAIN + // DS18B20 & DS1822: store for crc + scratchPad[COUNT_REMAIN] = _wire->read(); + + // byte 7: + // DS18S20: COUNT_PER_C + // DS18B20 & DS1822: store for crc + scratchPad[COUNT_PER_C] = _wire->read(); + + // byte 8: + // SCTRACHPAD_CRC + scratchPad[SCRATCHPAD_CRC] = _wire->read(); + + _wire->reset(); +} + +// writes device's scratch pad +void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress, const uint8_t* scratchPad) +{ + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(WRITESCRATCH); + _wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp + _wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp + // DS1820 and DS18S20 have no configuration register + if (deviceAddress[0] != DS18S20MODEL) _wire->write(scratchPad[CONFIGURATION]); // configuration + _wire->reset(); + _wire->select(deviceAddress); //<--this line was missing + // save the newly written values to eeprom + _wire->write(COPYSCRATCH, parasite); + delay(20); // <--- added 20ms delay to allow 10ms long EEPROM write operation (as specified by datasheet) + if (parasite) delay(10); // 10ms delay + _wire->reset(); +} + +// reads the device's power requirements +bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress) +{ + bool ret = false; + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(READPOWERSUPPLY); + if (_wire->read_bit() == 0) ret = true; + _wire->reset(); + return ret; +} + + +// set resolution of all devices to 9, 10, 11, or 12 bits +// if new resolution is out of range, it is constrained. +void DallasTemperature::setResolution(uint8_t newResolution) +{ + bitResolution = constrain(newResolution, 9, 12); + DeviceAddress deviceAddress; + for (int i=0; i<devices; i++) + { + getAddress(deviceAddress, i); + setResolution(deviceAddress, bitResolution); + } +} + +// set resolution of a device to 9, 10, 11, or 12 bits +// if new resolution is out of range, 9 bits is used. +bool DallasTemperature::setResolution(const uint8_t* deviceAddress, uint8_t newResolution) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + // DS1820 and DS18S20 have no resolution configuration register + if (deviceAddress[0] != DS18S20MODEL) + { + switch (newResolution) + { + case 12: + scratchPad[CONFIGURATION] = TEMP_12_BIT; + break; + case 11: + scratchPad[CONFIGURATION] = TEMP_11_BIT; + break; + case 10: + scratchPad[CONFIGURATION] = TEMP_10_BIT; + break; + case 9: + default: + scratchPad[CONFIGURATION] = TEMP_9_BIT; + break; + } + writeScratchPad(deviceAddress, scratchPad); + } + return true; // new value set + } + return false; +} + +// returns the global resolution +uint8_t DallasTemperature::getResolution() +{ + return bitResolution; +} + +// returns the current resolution of the device, 9-12 +// returns 0 if device not found +uint8_t DallasTemperature::getResolution(const uint8_t* deviceAddress) +{ + // DS1820 and DS18S20 have no resolution configuration register + if (deviceAddress[0] == DS18S20MODEL) return 12; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + switch (scratchPad[CONFIGURATION]) + { + case TEMP_12_BIT: + return 12; + + case TEMP_11_BIT: + return 11; + + case TEMP_10_BIT: + return 10; + + case TEMP_9_BIT: + return 9; + } + } + return 0; +} + + +// sets the value of the waitForConversion flag +// TRUE : function requestTemperature() etc returns when conversion is ready +// FALSE: function requestTemperature() etc returns immediately (USE WITH CARE!!) +// (1) programmer has to check if the needed delay has passed +// (2) but the application can do meaningful things in that time +void DallasTemperature::setWaitForConversion(bool flag) +{ + waitForConversion = flag; +} + +// gets the value of the waitForConversion flag +bool DallasTemperature::getWaitForConversion() +{ + return waitForConversion; +} + + +// sets the value of the checkForConversion flag +// TRUE : function requestTemperature() etc will 'listen' to an IC to determine whether a conversion is complete +// FALSE: function requestTemperature() etc will wait a set time (worst case scenario) for a conversion to complete +void DallasTemperature::setCheckForConversion(bool flag) +{ + checkForConversion = flag; +} + +// gets the value of the waitForConversion flag +bool DallasTemperature::getCheckForConversion() +{ + return checkForConversion; +} + +bool DallasTemperature::isConversionAvailable(const uint8_t* deviceAddress) +{ + // Check if the clock has been raised indicating the conversion is complete + ScratchPad scratchPad; + readScratchPad(deviceAddress, scratchPad); + return scratchPad[0]; +} + + +// sends command for all devices on the bus to perform a temperature conversion +void DallasTemperature::requestTemperatures() +{ + _wire->reset(); + _wire->skip(); + _wire->write(STARTCONVO, parasite); + + // ASYNC mode? + if (!waitForConversion) return; + blockTillConversionComplete(bitResolution, NULL); +} + +// sends command for one device to perform a temperature by address +// returns FALSE if device is disconnected +// returns TRUE otherwise +bool DallasTemperature::requestTemperaturesByAddress(const uint8_t* deviceAddress) +{ + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(STARTCONVO, parasite); + + // check device + ScratchPad scratchPad; + if (!isConnected(deviceAddress, scratchPad)) return false; + + // ASYNC mode? + if (!waitForConversion) return true; + blockTillConversionComplete(getResolution(deviceAddress), deviceAddress); + + return true; +} + +// returns number of milliseconds to wait till conversion is complete (based on IC datasheet) +int16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution) +{ + switch (bitResolution) + { + case 9: + return 94; + case 10: + return 188; + case 11: + return 375; + default: + return 750; + } +} + +// Continue to check if the IC has responded with a temperature +void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution, const uint8_t* deviceAddress) +{ + int delms = millisToWaitForConversion(bitResolution); + if (deviceAddress != NULL && checkForConversion && !parasite) + { + unsigned long timend = millis() + delms; + while(!isConversionAvailable(deviceAddress) && (millis() < timend)); + } + else + { + delay(delms); + } +} + +// sends command for one device to perform a temp conversion by index +bool DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex) +{ + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + return requestTemperaturesByAddress(deviceAddress); +} + +// Fetch temperature for device index +float DallasTemperature::getTempCByIndex(uint8_t deviceIndex) +{ + DeviceAddress deviceAddress; + if (!getAddress(deviceAddress, deviceIndex)) + return DEVICE_DISCONNECTED_C; + return getTempC((uint8_t*)deviceAddress); +} + +// Fetch temperature for device index +float DallasTemperature::getTempFByIndex(uint8_t deviceIndex) +{ + DeviceAddress deviceAddress; + if (!getAddress(deviceAddress, deviceIndex)) + return DEVICE_DISCONNECTED_F; + return getTempF((uint8_t*)deviceAddress); +} + +// reads scratchpad and returns fixed-point temperature, scaling factor 2^-7 +int16_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress, uint8_t* scratchPad) +{ + int16_t fpTemperature = + (((int16_t) scratchPad[TEMP_MSB]) << 11) | + (((int16_t) scratchPad[TEMP_LSB]) << 3); + + /* + DS1820 and DS18S20 have a 9-bit temperature register. + + Resolutions greater than 9-bit can be calculated using the data from + the temperature, and COUNT REMAIN and COUNT PER °C registers in the + scratchpad. The resolution of the calculation depends on the model. + + While the COUNT PER °C register is hard-wired to 16 (10h) in a + DS18S20, it changes with temperature in DS1820. + + After reading the scratchpad, the TEMP_READ value is obtained by + truncating the 0.5°C bit (bit 0) from the temperature data. The + extended resolution temperature can then be calculated using the + following equation: + + COUNT_PER_C - COUNT_REMAIN + TEMPERATURE = TEMP_READ - 0.25 + -------------------------- + COUNT_PER_C + + Hagai Shatz simplified this to integer arithmetic for a 12 bits + value for a DS18S20, and James Cameron added legacy DS1820 support. + + See - http://myarduinotoy.blogspot.co.uk/2013/02/12bit-result-from-ds18s20.html + */ + + if (deviceAddress[0] == DS18S20MODEL) + fpTemperature = ((fpTemperature & 0xfff0) << 3) - 16 + + ( + ((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7) / + scratchPad[COUNT_PER_C] + ); + + return fpTemperature; +} + + +// returns temperature in 1/128 degrees C or DEVICE_DISCONNECTED_RAW if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_RAW is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +int16_t DallasTemperature::getTemp(const uint8_t* deviceAddress) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return calculateTemperature(deviceAddress, scratchPad); + return DEVICE_DISCONNECTED_RAW; +} + +// returns temperature in degrees C or DEVICE_DISCONNECTED_C if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_C is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +float DallasTemperature::getTempC(const uint8_t* deviceAddress) +{ + return rawToCelsius(getTemp(deviceAddress)); +} + +// returns temperature in degrees F or DEVICE_DISCONNECTED_F if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_F is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +float DallasTemperature::getTempF(const uint8_t* deviceAddress) +{ + return rawToFahrenheit(getTemp(deviceAddress)); +} + +// returns true if the bus requires parasite power +bool DallasTemperature::isParasitePowerMode(void) +{ + return parasite; +} + +#if REQUIRESALARMS + +/* + +ALARMS: + +TH and TL Register Format + +BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 + S 2^6 2^5 2^4 2^3 2^2 2^1 2^0 + +Only bits 11 through 4 of the temperature register are used +in the TH and TL comparison since TH and TL are 8-bit +registers. If the measured temperature is lower than or equal +to TL or higher than or equal to TH, an alarm condition exists +and an alarm flag is set inside the DS18B20. This flag is +updated after every temperature measurement; therefore, if the +alarm condition goes away, the flag will be turned off after +the next temperature conversion. + +*/ + +// sets the high alarm temperature for a device in degrees Celsius +// accepts a float, but the alarm resolution will ignore anything +// after a decimal point. valid range is -55C - 125C +void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress, char celsius) +{ + // make sure the alarm temperature is within the device's range + if (celsius > 125) celsius = 125; + else if (celsius < -55) celsius = -55; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + scratchPad[HIGH_ALARM_TEMP] = (uint8_t)celsius; + writeScratchPad(deviceAddress, scratchPad); + } +} + +// sets the low alarm temperature for a device in degrees Celsius +// accepts a float, but the alarm resolution will ignore anything +// after a decimal point. valid range is -55C - 125C +void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress, char celsius) +{ + // make sure the alarm temperature is within the device's range + if (celsius > 125) celsius = 125; + else if (celsius < -55) celsius = -55; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + scratchPad[LOW_ALARM_TEMP] = (uint8_t)celsius; + writeScratchPad(deviceAddress, scratchPad); + } +} + +// returns a char with the current high alarm temperature or +// DEVICE_DISCONNECTED for an address +char DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[HIGH_ALARM_TEMP]; + return DEVICE_DISCONNECTED_C; +} + +// returns a char with the current low alarm temperature or +// DEVICE_DISCONNECTED for an address +char DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[LOW_ALARM_TEMP]; + return DEVICE_DISCONNECTED_C; +} + +// resets internal variables used for the alarm search +void DallasTemperature::resetAlarmSearch() +{ + alarmSearchJunction = -1; + alarmSearchExhausted = 0; + for(uint8_t i = 0; i < 7; i++) + alarmSearchAddress[i] = 0; +} + +// This is a modified version of the OneWire::search method. +// +// Also added the OneWire search fix documented here: +// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 +// +// Perform an alarm search. If this function returns a '1' then it has +// enumerated the next device and you may retrieve the ROM from the +// OneWire::address variable. If there are no devices, no further +// devices, or something horrible happens in the middle of the +// enumeration then a 0 is returned. If a new device is found then +// its address is copied to newAddr. Use +// DallasTemperature::resetAlarmSearch() to start over. +bool DallasTemperature::alarmSearch(uint8_t* newAddr) +{ + uint8_t i; + char lastJunction = -1; + uint8_t done = 1; + + if (alarmSearchExhausted) return false; + if (!_wire->reset()) return false; + + // send the alarm search command + _wire->write(0xEC, 0); + + for(i = 0; i < 64; i++) + { + uint8_t a = _wire->read_bit( ); + uint8_t nota = _wire->read_bit( ); + uint8_t ibyte = i / 8; + uint8_t ibit = 1 << (i & 7); + + // I don't think this should happen, this means nothing responded, but maybe if + // something vanishes during the search it will come up. + if (a && nota) return false; + + if (!a && !nota) + { + if (i == alarmSearchJunction) + { + // this is our time to decide differently, we went zero last time, go one. + a = 1; + alarmSearchJunction = lastJunction; + } + else if (i < alarmSearchJunction) + { + // take whatever we took last time, look in address + if (alarmSearchAddress[ibyte] & ibit) a = 1; + else + { + // Only 0s count as pending junctions, we've already exhausted the 0 side of 1s + a = 0; + done = 0; + lastJunction = i; + } + } + else + { + // we are blazing new tree, take the 0 + a = 0; + alarmSearchJunction = i; + done = 0; + } + // OneWire search fix + // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 + } + + if (a) alarmSearchAddress[ibyte] |= ibit; + else alarmSearchAddress[ibyte] &= ~ibit; + + _wire->write_bit(a); + } + + if (done) alarmSearchExhausted = 1; + for (i = 0; i < 8; i++) newAddr[i] = alarmSearchAddress[i]; + return true; +} + +// returns true if device address might have an alarm condition +// (only an alarm search can verify this) +bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress) +{ + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + { + char temp = calculateTemperature(deviceAddress, scratchPad) >> 7; + + // check low alarm + if (temp <= (char)scratchPad[LOW_ALARM_TEMP]) return true; + + // check high alarm + if (temp >= (char)scratchPad[HIGH_ALARM_TEMP]) return true; + } + + // no alarm + return false; +} + +// returns true if any device is reporting an alarm condition on the bus +bool DallasTemperature::hasAlarm(void) +{ + DeviceAddress deviceAddress; + resetAlarmSearch(); + return alarmSearch(deviceAddress); +} + +// runs the alarm handler for all devices returned by alarmSearch() +void DallasTemperature::processAlarms(void) +{ + resetAlarmSearch(); + DeviceAddress alarmAddr; + + while (alarmSearch(alarmAddr)) + { + if (validAddress(alarmAddr)) + _AlarmHandler(alarmAddr); + } +} + +// sets the alarm handler +void DallasTemperature::setAlarmHandler(AlarmHandler *handler) +{ + _AlarmHandler = handler; +} + +// The default alarm handler +void DallasTemperature::defaultAlarmHandler(const uint8_t* deviceAddress) +{ +} + +#endif + +// Convert float Celsius to Fahrenheit +float DallasTemperature::toFahrenheit(float celsius) +{ + return (celsius * 1.8) + 32; +} + +// Convert float Fahrenheit to Celsius +float DallasTemperature::toCelsius(float fahrenheit) +{ + return (fahrenheit - 32) * 0.555555556; +} + +// convert from raw to Celsius +float DallasTemperature::rawToCelsius(int16_t raw) +{ + if (raw <= DEVICE_DISCONNECTED_RAW) + return DEVICE_DISCONNECTED_C; + // C = RAW/128 + return (float)raw * 0.0078125; +} + +// convert from raw to Fahrenheit +float DallasTemperature::rawToFahrenheit(int16_t raw) +{ + if (raw <= DEVICE_DISCONNECTED_RAW) + return DEVICE_DISCONNECTED_F; + // C = RAW/128 + // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32 + return ((float)raw * 0.0140625) + 32; +} + +#if REQUIRESNEW + +// MnetCS - Allocates memory for DallasTemperature. Allows us to instance a new object +void* DallasTemperature::operator new(unsigned int size) // Implicit NSS obj size +{ + void * p; // void pointer + p = malloc(size); // Allocate memory + memset((DallasTemperature*)p,0,size); // Initialise memory + + //!!! CANT EXPLICITLY CALL CONSTRUCTOR - workaround by using an init() methodR - workaround by using an init() method + return (DallasTemperature*) p; // Cast blank region to NSS pointer +} + +// MnetCS 2009 - Free the memory used by this instance +void DallasTemperature::operator delete(void* p) +{ + DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer + pNss->~DallasTemperature(); // Destruct the object + + free(p); // Free the memory +} + +#endif