+++ /dev/null
-// This library is free software; you can redistribute it and/or\r
-// modify it under the terms of the GNU Lesser General Public\r
-// License as published by the Free Software Foundation; either\r
-// version 2.1 of the License, or (at your option) any later version.\r
-\r
-#include "DallasTemperature.h"\r
-#include "Arduino.h"\r
-extern "C" {\r
- \r
-}\r
-\r
-DallasTemperature::DallasTemperature(OneWire* _oneWire) \r
- #if REQUIRESALARMS\r
- : _AlarmHandler(&defaultAlarmHandler)\r
- #endif\r
-{\r
- _wire = _oneWire;\r
- devices = 0;\r
- parasite = false;\r
- conversionDelay = TEMP_9_BIT;\r
-}\r
-\r
-// initialize the bus\r
-void DallasTemperature::begin(void)\r
-{\r
- DeviceAddress deviceAddress;\r
-\r
- _wire->reset_search();\r
-\r
- while (_wire->search(deviceAddress))\r
- {\r
- if (validAddress(deviceAddress))\r
- { \r
- if (!parasite && readPowerSupply(deviceAddress)) parasite = true;\r
-\r
- ScratchPad scratchPad;\r
-\r
- readScratchPad(deviceAddress, scratchPad);\r
-\r
- if (deviceAddress[0] == DS18S20MODEL) conversionDelay = TEMP_12_BIT; // 750 ms\r
- else if (scratchPad[CONFIGURATION] > conversionDelay) conversionDelay = scratchPad[CONFIGURATION];\r
-\r
- devices++;\r
- }\r
- }\r
-}\r
-\r
-// returns the number of devices found on the bus\r
-uint8_t DallasTemperature::getDeviceCount(void)\r
-{\r
- return devices;\r
-}\r
-\r
-// returns true if address is valid\r
-bool DallasTemperature::validAddress(uint8_t* deviceAddress)\r
-{\r
- return (_wire->crc8(deviceAddress, 7) == deviceAddress[7]);\r
-}\r
-\r
-// finds an address at a given index on the bus\r
-// returns true if the device was found\r
-bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index)\r
-{\r
- uint8_t depth = 0;\r
-\r
- _wire->reset_search();\r
-\r
- while (depth <= index && _wire->search(deviceAddress))\r
- {\r
- if (depth == index && validAddress(deviceAddress)) return true;\r
- depth++;\r
- }\r
-\r
- return false;\r
-}\r
-\r
-// attempt to determine if the device at the given address is connected to the bus\r
-bool DallasTemperature::isConnected(uint8_t* deviceAddress)\r
-{\r
- ScratchPad scratchPad;\r
- return isConnected(deviceAddress, scratchPad);\r
-}\r
-\r
-// attempt to determine if the device at the given address is connected to the bus\r
-// also allows for updating the read scratchpad\r
-bool DallasTemperature::isConnected(uint8_t* deviceAddress, uint8_t* scratchPad)\r
-{\r
- readScratchPad(deviceAddress, scratchPad);\r
- return (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);\r
-}\r
-\r
-// read device's scratch pad\r
-void DallasTemperature::readScratchPad(uint8_t* deviceAddress, uint8_t* scratchPad)\r
-{\r
- // send the command\r
- _wire->reset();\r
- _wire->select(deviceAddress);\r
- _wire->write(READSCRATCH);\r
-\r
- // read the response \r
-\r
- // byte 0: temperature LSB\r
- scratchPad[TEMP_LSB] = _wire->read();\r
-\r
- // byte 1: temperature MSB\r
- scratchPad[TEMP_MSB] = _wire->read();\r
-\r
- // byte 2: high alarm temp\r
- scratchPad[HIGH_ALARM_TEMP] = _wire->read();\r
-\r
- // byte 3: low alarm temp\r
- scratchPad[LOW_ALARM_TEMP] = _wire->read();\r
-\r
- // byte 4:\r
- // DS18S20: store for crc\r
- // DS18B20 & DS1822: configuration register\r
- scratchPad[CONFIGURATION] = _wire->read();\r
-\r
- // byte 5:\r
- // internal use & crc\r
- scratchPad[INTERNAL_BYTE] = _wire->read();\r
-\r
- // byte 6:\r
- // DS18S20: COUNT_REMAIN\r
- // DS18B20 & DS1822: store for crc\r
- scratchPad[COUNT_REMAIN] = _wire->read();\r
- \r
- // byte 7:\r
- // DS18S20: COUNT_PER_C\r
- // DS18B20 & DS1822: store for crc\r
- scratchPad[COUNT_PER_C] = _wire->read();\r
- \r
- // byte 8:\r
- // SCTRACHPAD_CRC\r
- scratchPad[SCRATCHPAD_CRC] = _wire->read();\r
-\r
- _wire->reset();\r
-}\r
-\r
-// writes device's scratch pad\r
-void DallasTemperature::writeScratchPad(uint8_t* deviceAddress, const uint8_t* scratchPad)\r
-{\r
- _wire->reset();\r
- _wire->select(deviceAddress);\r
- _wire->write(WRITESCRATCH);\r
- _wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp\r
- _wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp\r
- // DS18S20 does not use the configuration register\r
- if (deviceAddress[0] != DS18S20MODEL) _wire->write(scratchPad[CONFIGURATION]); // configuration\r
- _wire->reset();\r
- // save the newly written values to eeprom\r
- _wire->write(COPYSCRATCH, parasite);\r
- if (parasite) delay(10); // 10ms delay \r
- _wire->reset();\r
-}\r
-\r
-// reads the device's power requirements\r
-bool DallasTemperature::readPowerSupply(uint8_t* deviceAddress)\r
-{\r
- bool ret = false;\r
- _wire->reset();\r
- _wire->select(deviceAddress);\r
- _wire->write(READPOWERSUPPLY);\r
- if (_wire->read_bit() == 0) ret = true;\r
- _wire->reset();\r
- return ret;\r
-}\r
-\r
-// returns the current resolution, 9-12\r
-uint8_t DallasTemperature::getResolution(uint8_t* deviceAddress)\r
-{\r
- if (deviceAddress[0] == DS18S20MODEL) return 9; // this model has a fixed resolution\r
-\r
- ScratchPad scratchPad;\r
- readScratchPad(deviceAddress, scratchPad);\r
- switch (scratchPad[CONFIGURATION])\r
- {\r
- case TEMP_12_BIT:\r
- return 12;\r
- break;\r
- case TEMP_11_BIT:\r
- return 11;\r
- break;\r
- case TEMP_10_BIT:\r
- return 10;\r
- break;\r
- case TEMP_9_BIT:\r
- return 9;\r
- break;\r
- }\r
-}\r
-\r
-// set resolution of a device to 9, 10, 11, or 12 bits\r
-void DallasTemperature::setResolution(uint8_t* deviceAddress, uint8_t newResolution)\r
-{\r
- ScratchPad scratchPad;\r
- if (isConnected(deviceAddress, scratchPad))\r
- {\r
- // DS18S20 has a fixed 9-bit resolution\r
- if (deviceAddress[0] != DS18S20MODEL)\r
- {\r
- switch (newResolution)\r
- {\r
- case 12:\r
- scratchPad[CONFIGURATION] = TEMP_12_BIT;\r
- break;\r
- case 11:\r
- scratchPad[CONFIGURATION] = TEMP_11_BIT;\r
- break;\r
- case 10:\r
- scratchPad[CONFIGURATION] = TEMP_10_BIT;\r
- break;\r
- case 9:\r
- default:\r
- scratchPad[CONFIGURATION] = TEMP_9_BIT;\r
- break;\r
- }\r
- writeScratchPad(deviceAddress, scratchPad);\r
- }\r
- }\r
-} \r
-\r
-// sends command for all devices on the bus to perform a temperature\r
-void DallasTemperature::requestTemperatures(void)\r
-{\r
- _wire->reset();\r
- _wire->skip();\r
- _wire->write(STARTCONVO, parasite);\r
-\r
- switch (conversionDelay)\r
- {\r
- case TEMP_9_BIT:\r
- delay(94);\r
- break;\r
- case TEMP_10_BIT:\r
- delay(188);\r
- break;\r
- case TEMP_11_BIT:\r
- delay(375);\r
- break;\r
- case TEMP_12_BIT:\r
- default:\r
- delay(750);\r
- break;\r
- }\r
-}\r
-\r
-// sends command for one device to perform a temperature by address\r
-void DallasTemperature::requestTemperaturesByAddress(uint8_t* deviceAddress)\r
-{\r
- _wire->reset();\r
- _wire->select(deviceAddress);\r
- _wire->write(STARTCONVO, parasite);\r
-\r
- switch (conversionDelay)\r
- {\r
- case TEMP_9_BIT:\r
- delay(94);\r
- break;\r
- case TEMP_10_BIT:\r
- delay(188);\r
- break;\r
- case TEMP_11_BIT:\r
- delay(375);\r
- break;\r
- case TEMP_12_BIT:\r
- default:\r
- delay(750);\r
- break;\r
- }\r
-}\r
-\r
-// sends command for one device to perform a temp conversion by index\r
-void DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex)\r
-{\r
- DeviceAddress deviceAddress;\r
- getAddress(deviceAddress, deviceIndex);\r
- requestTemperaturesByAddress(deviceAddress);\r
-}\r
-\r
-\r
-// Fetch temperature for device index\r
-float DallasTemperature::getTempCByIndex(uint8_t deviceIndex)\r
-{\r
- DeviceAddress deviceAddress;\r
- getAddress(deviceAddress, deviceIndex);\r
- return getTempC((uint8_t*)deviceAddress);\r
-}\r
-\r
-// Fetch temperature for device index\r
-float DallasTemperature::getTempFByIndex(uint8_t deviceIndex)\r
-{\r
- return DallasTemperature::toFahrenheit(getTempCByIndex(deviceIndex));\r
-}\r
-\r
-// reads scratchpad and returns the temperature in degrees C\r
-float DallasTemperature::calculateTemperature(uint8_t* deviceAddress, uint8_t* scratchPad)\r
-{\r
- int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];\r
-\r
- switch (deviceAddress[0])\r
- {\r
- case DS18B20MODEL:\r
- case DS1822MODEL:\r
- switch (scratchPad[CONFIGURATION])\r
- {\r
- case TEMP_12_BIT:\r
- return (float)rawTemperature * 0.0625;\r
- break;\r
- case TEMP_11_BIT:\r
- return (float)(rawTemperature >> 1) * 0.125;\r
- break;\r
- case TEMP_10_BIT:\r
- return (float)(rawTemperature >> 2) * 0.25;\r
- break;\r
- case TEMP_9_BIT:\r
- return (float)(rawTemperature >> 3) * 0.5;\r
- break;\r
- }\r
- break;\r
- case DS18S20MODEL:\r
- /*\r
- \r
- Resolutions greater than 9 bits can be calculated using the data from \r
- the temperature, COUNT REMAIN and COUNT PER °C registers in the \r
- scratchpad. Note that the COUNT PER °C register is hard-wired to 16 \r
- (10h). After reading the scratchpad, the TEMP_READ value is obtained \r
- by truncating the 0.5°C bit (bit 0) from the temperature data. The \r
- extended resolution temperature can then be calculated using the \r
- following equation:\r
- \r
- COUNT_PER_C - COUNT_REMAIN\r
- TEMPERATURE = TEMP_READ - 0.25 + --------------------------\r
- COUNT_PER_C\r
- */\r
- \r
- // Good spot. Thanks Nic Johns for your contribution\r
- return (float)(rawTemperature >> 1) - 0.25 +((float)(scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) / (float)scratchPad[COUNT_PER_C] ); \r
- break;\r
- }\r
-}\r
-\r
-// returns temperature in degrees C or DEVICE_DISCONNECTED if the \r
-// device's scratch pad cannot be read successfully.\r
-// the numeric value of DEVICE_DISCONNECTED is defined in \r
-// DallasTemperature.h. it is a large negative number outside the \r
-// operating range of the device\r
-float DallasTemperature::getTempC(uint8_t* deviceAddress)\r
-{\r
- // TODO: Multiple devices (up to 64) on the same bus may take some time to negotiate a response\r
- // What happens in case of collision?\r
-\r
- ScratchPad scratchPad;\r
- if (isConnected(deviceAddress, scratchPad)) return calculateTemperature(deviceAddress, scratchPad);\r
- return DEVICE_DISCONNECTED;\r
-}\r
-\r
-// returns temperature in degrees F\r
-float DallasTemperature::getTempF(uint8_t* deviceAddress)\r
-{\r
- return toFahrenheit(getTempC(deviceAddress));\r
-}\r
-\r
-// returns true if the bus requires parasite power\r
-bool DallasTemperature::isParasitePowerMode(void)\r
-{\r
- return parasite;\r
-}\r
-\r
-#if REQUIRESALARMS\r
-\r
-/*\r
-\r
-ALARMS:\r
-\r
-TH and TL Register Format\r
-\r
-BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0\r
- S 2^6 2^5 2^4 2^3 2^2 2^1 2^0\r
-\r
-Only bits 11 through 4 of the temperature register are used \r
-in the TH and TL comparison since TH and TL are 8-bit \r
-registers. If the measured temperature is lower than or equal \r
-to TL or higher than or equal to TH, an alarm condition exists \r
-and an alarm flag is set inside the DS18B20. This flag is \r
-updated after every temperature measurement; therefore, if the \r
-alarm condition goes away, the flag will be turned off after \r
-the next temperature conversion.\r
-\r
-*/\r
-\r
-// sets the high alarm temperature for a device in degrees celsius\r
-// accepts a float, but the alarm resolution will ignore anything \r
-// after a decimal point. valid range is -55C - 125C\r
-void DallasTemperature::setHighAlarmTemp(uint8_t* deviceAddress, char celsius)\r
-{\r
- // make sure the alarm temperature is within the device's range\r
- if (celsius > 125) celsius = 125;\r
- else if (celsius < -55) celsius = -55;\r
- \r
- ScratchPad scratchPad;\r
- if (isConnected(deviceAddress, scratchPad))\r
- { \r
- scratchPad[HIGH_ALARM_TEMP] = (uint8_t)celsius;\r
- writeScratchPad(deviceAddress, scratchPad);\r
- }\r
-}\r
-\r
-// sets the low alarm temperature for a device in degreed celsius\r
-// accepts a float, but the alarm resolution will ignore anything \r
-// after a decimal point. valid range is -55C - 125C\r
-void DallasTemperature::setLowAlarmTemp(uint8_t* deviceAddress, char celsius)\r
-{\r
- // make sure the alarm temperature is within the device's range\r
- if (celsius > 125) celsius = 125;\r
- else if (celsius < -55) celsius = -55;\r
-\r
- ScratchPad scratchPad;\r
- if (isConnected(deviceAddress, scratchPad))\r
- {\r
- scratchPad[LOW_ALARM_TEMP] = (uint8_t)celsius;\r
- writeScratchPad(deviceAddress, scratchPad);\r
- }\r
-}\r
-\r
-// returns a char with the current high alarm temperature or \r
-// DEVICE_DISCONNECTED for an address\r
-char DallasTemperature::getHighAlarmTemp(uint8_t* deviceAddress)\r
-{\r
- ScratchPad scratchPad;\r
- if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[HIGH_ALARM_TEMP];\r
- return DEVICE_DISCONNECTED;\r
-}\r
-\r
-// returns a char with the current low alarm temperature or \r
-// DEVICE_DISCONNECTED for an address\r
-char DallasTemperature::getLowAlarmTemp(uint8_t* deviceAddress)\r
-{\r
- ScratchPad scratchPad;\r
- if (isConnected(deviceAddress, scratchPad)) return (char)scratchPad[LOW_ALARM_TEMP];\r
- return DEVICE_DISCONNECTED;\r
-}\r
-\r
-// resets internal variables used for the alarm search\r
-void DallasTemperature::resetAlarmSearch()\r
-{\r
- alarmSearchJunction = -1;\r
- alarmSearchExhausted = 0;\r
- for(uint8_t i = 0; i < 7; i++)\r
- alarmSearchAddress[i] = 0;\r
-}\r
-\r
-// This is a modified version of the OneWire::search method. \r
-//\r
-// Also added the OneWire search fix documented here:\r
-// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295\r
-//\r
-// Perform an alarm search. If this function returns a '1' then it has\r
-// enumerated the next device and you may retrieve the ROM from the\r
-// OneWire::address variable. If there are no devices, no further\r
-// devices, or something horrible happens in the middle of the\r
-// enumeration then a 0 is returned. If a new device is found then\r
-// its address is copied to newAddr. Use \r
-// DallasTemperature::resetAlarmSearch() to start over.\r
-bool DallasTemperature::alarmSearch(uint8_t* newAddr)\r
-{\r
- uint8_t i;\r
- char lastJunction = -1;\r
- uint8_t done = 1;\r
- \r
- if (alarmSearchExhausted) return false;\r
- if (!_wire->reset()) return false;\r
-\r
- // send the alarm search command\r
- _wire->write(0xEC, 0);\r
- \r
- for(i = 0; i < 64; i++)\r
- {\r
- uint8_t a = _wire->read_bit( );\r
- uint8_t nota = _wire->read_bit( );\r
- uint8_t ibyte = i / 8;\r
- uint8_t ibit = 1 << (i & 7);\r
- \r
- // I don't think this should happen, this means nothing responded, but maybe if\r
- // something vanishes during the search it will come up.\r
- if (a && nota) return false;\r
-\r
- if (!a && !nota)\r
- {\r
- if (i == alarmSearchJunction)\r
- {\r
- // this is our time to decide differently, we went zero last time, go one.\r
- a = 1;\r
- alarmSearchJunction = lastJunction;\r
- }\r
- else if (i < alarmSearchJunction) \r
- {\r
- // take whatever we took last time, look in address\r
- if (alarmSearchAddress[ibyte] & ibit) a = 1;\r
- else\r
- {\r
- // Only 0s count as pending junctions, we've already exhasuted the 0 side of 1s\r
- a = 0;\r
- done = 0;\r
- lastJunction = i;\r
- }\r
- }\r
- else\r
- {\r
- // we are blazing new tree, take the 0\r
- a = 0;\r
- alarmSearchJunction = i;\r
- done = 0;\r
- }\r
- // OneWire search fix\r
- // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295\r
- }\r
-\r
- if (a) alarmSearchAddress[ibyte] |= ibit;\r
- else alarmSearchAddress[ibyte] &= ~ibit;\r
- \r
- _wire->write_bit(a);\r
- }\r
-\r
- if (done) alarmSearchExhausted = 1;\r
- for (i = 0; i < 8; i++) newAddr[i] = alarmSearchAddress[i];\r
- return true; \r
-}\r
-\r
-// returns true if device address has an alarm condition\r
-bool DallasTemperature::hasAlarm(uint8_t* deviceAddress)\r
-{\r
- ScratchPad scratchPad;\r
- if (isConnected(deviceAddress, scratchPad))\r
- {\r
- float temp = calculateTemperature(deviceAddress, scratchPad);\r
- \r
- // check low alarm\r
- if ((char)temp <= (char)scratchPad[LOW_ALARM_TEMP]) return true;\r
- \r
- // check high alarm\r
- if ((char)temp >= (char)scratchPad[HIGH_ALARM_TEMP]) return true;\r
- }\r
-\r
- // no alarm\r
- return false;\r
-}\r
-\r
-// returns true if any device is reporting an alarm condition on the bus\r
-bool DallasTemperature::hasAlarm(void)\r
-{\r
- DeviceAddress deviceAddress;\r
- resetAlarmSearch();\r
- return alarmSearch(deviceAddress);\r
-}\r
-\r
-// runs the alarm handler for all devices returned by alarmSearch()\r
-void DallasTemperature::processAlarms(void)\r
-{\r
- resetAlarmSearch();\r
- DeviceAddress alarmAddr;\r
-\r
- while (alarmSearch(alarmAddr))\r
- {\r
- if (validAddress(alarmAddr))\r
- _AlarmHandler(alarmAddr);\r
- }\r
-}\r
-\r
-// sets the alarm handler\r
-void DallasTemperature::setAlarmHandler(AlarmHandler *handler)\r
-{\r
- _AlarmHandler = handler;\r
-}\r
-\r
-// The default alarm handler\r
-void DallasTemperature::defaultAlarmHandler(uint8_t* deviceAddress)\r
-{\r
-}\r
-\r
-#endif\r
-\r
-// Convert float celsius to fahrenheit\r
-float DallasTemperature::toFahrenheit(float celsius)\r
-{\r
- return (celsius * 1.8) + 32;\r
-}\r
-\r
-// Convert float fahrenheit to celsius\r
-float DallasTemperature::toCelsius(float fahrenheit)\r
-{\r
- return (fahrenheit - 32) / 1.8;\r
-}\r
-\r
-#if REQUIRESNEW\r
-\r
-// MnetCS - Allocates memory for DallasTemperature. Allows us to instance a new object\r
-void* DallasTemperature::operator new(unsigned int size) // Implicit NSS obj size\r
-{\r
- void * p; // void pointer\r
- p = malloc(size); // Allocate memory\r
- memset((DallasTemperature*)p,0,size); // Initalise memory\r
-\r
- //!!! CANT EXPLICITLY CALL CONSTRUCTOR - workaround by using an init() methodR - workaround by using an init() method\r
- return (DallasTemperature*) p; // Cast blank region to NSS pointer\r
-}\r
-\r
-// MnetCS 2009 - Unallocates the memory used by this instance\r
-void DallasTemperature::operator delete(void* p)\r
-{\r
- DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer\r
- pNss->~DallasTemperature(); // Destruct the object\r
-\r
- free(p); // Free the memory\r
-}\r
-\r
-#endif\r