809 lines
23 KiB
C++
809 lines
23 KiB
C++
#include "DallasTemperature.h"
|
|
|
|
#if ARDUINO >= 100
|
|
#include "Arduino.h"
|
|
#else
|
|
extern "C" {
|
|
#include "WConstants.h"
|
|
}
|
|
#endif
|
|
|
|
// OneWire commands
|
|
#define STARTCONVO 0x44 // Tells device to take a temperature reading
|
|
#define COPYSCRATCH 0x48 // Copy scratchpad to EEPROM
|
|
#define READSCRATCH 0xBE // Read from scratchpad
|
|
#define WRITESCRATCH 0x4E // Write to scratchpad
|
|
#define RECALLSCRATCH 0xB8 // Recall from EEPROM to scratchpad
|
|
#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power
|
|
#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition
|
|
|
|
// Scratchpad locations
|
|
#define TEMP_LSB 0
|
|
#define TEMP_MSB 1
|
|
#define HIGH_ALARM_TEMP 2
|
|
#define LOW_ALARM_TEMP 3
|
|
#define CONFIGURATION 4
|
|
#define INTERNAL_BYTE 5
|
|
#define COUNT_REMAIN 6
|
|
#define COUNT_PER_C 7
|
|
#define SCRATCHPAD_CRC 8
|
|
|
|
// Device resolution
|
|
#define TEMP_9_BIT 0x1F
|
|
#define TEMP_10_BIT 0x3F
|
|
#define TEMP_11_BIT 0x5F
|
|
#define TEMP_12_BIT 0x7F
|
|
|
|
#define NO_ALARM_HANDLER ((AlarmHandler *)0)
|
|
|
|
// DSROM FIELDS
|
|
#define DSROM_FAMILY 0
|
|
#define DSROM_CRC 7
|
|
|
|
DallasTemperature::DallasTemperature() {
|
|
_wire = nullptr;
|
|
devices = 0;
|
|
ds18Count = 0;
|
|
parasite = false;
|
|
bitResolution = 9;
|
|
waitForConversion = true;
|
|
checkForConversion = true;
|
|
autoSaveScratchPad = true;
|
|
useExternalPullup = false;
|
|
#if REQUIRESALARMS
|
|
setAlarmHandler(NO_ALARM_HANDLER);
|
|
alarmSearchJunction = -1;
|
|
alarmSearchExhausted = 0;
|
|
#endif
|
|
}
|
|
|
|
DallasTemperature::DallasTemperature(OneWire* _oneWire) : DallasTemperature() {
|
|
setOneWire(_oneWire);
|
|
}
|
|
|
|
DallasTemperature::DallasTemperature(OneWire* _oneWire, uint8_t _pullupPin) : DallasTemperature(_oneWire) {
|
|
setPullupPin(_pullupPin);
|
|
}
|
|
|
|
void DallasTemperature::setOneWire(OneWire* _oneWire) {
|
|
_wire = _oneWire;
|
|
devices = 0;
|
|
ds18Count = 0;
|
|
parasite = false;
|
|
bitResolution = 9;
|
|
waitForConversion = true;
|
|
checkForConversion = true;
|
|
autoSaveScratchPad = true;
|
|
}
|
|
|
|
void DallasTemperature::setPullupPin(uint8_t _pullupPin) {
|
|
useExternalPullup = true;
|
|
pullupPin = _pullupPin;
|
|
pinMode(pullupPin, OUTPUT);
|
|
deactivateExternalPullup();
|
|
}
|
|
|
|
void DallasTemperature::begin(void) {
|
|
DeviceAddress deviceAddress;
|
|
|
|
for (uint8_t retry = 0; retry < MAX_INITIALIZATION_RETRIES; retry++) {
|
|
_wire->reset_search();
|
|
devices = 0;
|
|
ds18Count = 0;
|
|
|
|
delay(INITIALIZATION_DELAY_MS);
|
|
|
|
while (_wire->search(deviceAddress)) {
|
|
if (validAddress(deviceAddress)) {
|
|
devices++;
|
|
|
|
if (validFamily(deviceAddress)) {
|
|
ds18Count++;
|
|
|
|
if (!parasite && readPowerSupply(deviceAddress)) {
|
|
parasite = true;
|
|
}
|
|
|
|
uint8_t b = getResolution(deviceAddress);
|
|
if (b > bitResolution) {
|
|
bitResolution = b;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (devices > 0) break;
|
|
}
|
|
}
|
|
|
|
void DallasTemperature::activateExternalPullup() {
|
|
if (useExternalPullup) digitalWrite(pullupPin, LOW);
|
|
}
|
|
|
|
void DallasTemperature::deactivateExternalPullup() {
|
|
if (useExternalPullup) digitalWrite(pullupPin, HIGH);
|
|
}
|
|
|
|
bool DallasTemperature::validFamily(const uint8_t* deviceAddress) {
|
|
switch (deviceAddress[0]) {
|
|
case DS18S20MODEL:
|
|
case DS18B20MODEL:
|
|
case DS1822MODEL:
|
|
case DS1825MODEL:
|
|
case DS28EA00MODEL:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool DallasTemperature::validAddress(const uint8_t* deviceAddress) {
|
|
return (_wire->crc8(const_cast<uint8_t*>(deviceAddress), 7) == deviceAddress[7]);
|
|
}
|
|
|
|
bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index) {
|
|
if (index < devices) {
|
|
uint8_t depth = 0;
|
|
|
|
_wire->reset_search();
|
|
|
|
while (depth <= index && _wire->search(deviceAddress)) {
|
|
if (depth == index && validAddress(deviceAddress)) {
|
|
return true;
|
|
}
|
|
depth++;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint8_t DallasTemperature::getDeviceCount(void) {
|
|
return devices;
|
|
}
|
|
|
|
uint8_t DallasTemperature::getDS18Count(void) {
|
|
return ds18Count;
|
|
}
|
|
|
|
bool DallasTemperature::isConnected(const uint8_t* deviceAddress) {
|
|
ScratchPad scratchPad;
|
|
return isConnected(deviceAddress, scratchPad);
|
|
}
|
|
|
|
bool DallasTemperature::isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad) {
|
|
bool b = readScratchPad(deviceAddress, scratchPad);
|
|
return b && !isAllZeros(scratchPad) && (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
|
|
}
|
|
|
|
bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress) {
|
|
bool parasiteMode = false;
|
|
_wire->reset();
|
|
if (deviceAddress == nullptr) {
|
|
_wire->skip();
|
|
} else {
|
|
_wire->select(deviceAddress);
|
|
}
|
|
|
|
_wire->write(READPOWERSUPPLY);
|
|
if (_wire->read_bit() == 0) {
|
|
parasiteMode = true;
|
|
}
|
|
_wire->reset();
|
|
return parasiteMode;
|
|
}
|
|
|
|
bool DallasTemperature::isParasitePowerMode(void) {
|
|
return parasite;
|
|
}
|
|
|
|
bool DallasTemperature::isAllZeros(const uint8_t* const scratchPad, const size_t length) {
|
|
for (size_t i = 0; i < length; i++) {
|
|
if (scratchPad[i] != 0) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool DallasTemperature::readScratchPad(const uint8_t* deviceAddress, uint8_t* scratchPad) {
|
|
int b = _wire->reset();
|
|
if (b == 0) return false;
|
|
|
|
_wire->select(deviceAddress);
|
|
_wire->write(READSCRATCH);
|
|
|
|
for (uint8_t i = 0; i < 9; i++) {
|
|
scratchPad[i] = _wire->read();
|
|
}
|
|
|
|
b = _wire->reset();
|
|
return (b == 1);
|
|
}
|
|
|
|
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]);
|
|
}
|
|
|
|
if (autoSaveScratchPad) {
|
|
saveScratchPad(deviceAddress);
|
|
} else {
|
|
_wire->reset();
|
|
}
|
|
}
|
|
|
|
bool DallasTemperature::saveScratchPad(const uint8_t* deviceAddress) {
|
|
if (_wire->reset() == 0) return false;
|
|
|
|
if (deviceAddress == nullptr)
|
|
_wire->skip();
|
|
else
|
|
_wire->select(deviceAddress);
|
|
|
|
_wire->write(COPYSCRATCH, parasite);
|
|
|
|
// Specification: NV Write Cycle Time is typically 2ms, max 10ms
|
|
// Waiting 20ms to allow for sensors that take longer in practice
|
|
if (!parasite) {
|
|
delay(20);
|
|
} else {
|
|
activateExternalPullup();
|
|
delay(20);
|
|
deactivateExternalPullup();
|
|
}
|
|
|
|
return (_wire->reset() == 1);
|
|
}
|
|
|
|
bool DallasTemperature::recallScratchPad(const uint8_t* deviceAddress) {
|
|
if (_wire->reset() == 0) return false;
|
|
|
|
if (deviceAddress == nullptr)
|
|
_wire->skip();
|
|
else
|
|
_wire->select(deviceAddress);
|
|
|
|
_wire->write(RECALLSCRATCH, parasite);
|
|
|
|
// Specification: Strong pullup only needed when writing to EEPROM
|
|
unsigned long start = millis();
|
|
while (_wire->read_bit() == 0) {
|
|
if (millis() - start > 20) return false;
|
|
yield();
|
|
}
|
|
|
|
return (_wire->reset() == 1);
|
|
}
|
|
|
|
int32_t DallasTemperature::getTemp(const uint8_t* deviceAddress, byte retryCount) {
|
|
ScratchPad scratchPad;
|
|
byte retries = 0;
|
|
|
|
while (retries++ <= retryCount) {
|
|
if (isConnected(deviceAddress, scratchPad)) {
|
|
return calculateTemperature(deviceAddress, scratchPad);
|
|
}
|
|
}
|
|
|
|
return DEVICE_DISCONNECTED_RAW;
|
|
}
|
|
|
|
float DallasTemperature::getTempC(const uint8_t* deviceAddress, byte retryCount) {
|
|
return rawToCelsius(getTemp(deviceAddress, retryCount));
|
|
}
|
|
|
|
float DallasTemperature::getTempF(const uint8_t* deviceAddress) {
|
|
return rawToFahrenheit(getTemp(deviceAddress));
|
|
}
|
|
|
|
float DallasTemperature::getTempCByIndex(uint8_t index) {
|
|
DeviceAddress deviceAddress;
|
|
if (!getAddress(deviceAddress, index)) {
|
|
return DEVICE_DISCONNECTED_C;
|
|
}
|
|
return getTempC((uint8_t*)deviceAddress);
|
|
}
|
|
|
|
float DallasTemperature::getTempFByIndex(uint8_t index) {
|
|
DeviceAddress deviceAddress;
|
|
if (!getAddress(deviceAddress, index)) {
|
|
return DEVICE_DISCONNECTED_F;
|
|
}
|
|
return getTempF((uint8_t*)deviceAddress);
|
|
}
|
|
|
|
void DallasTemperature::setResolution(uint8_t newResolution) {
|
|
bitResolution = constrain(newResolution, 9, 12);
|
|
DeviceAddress deviceAddress;
|
|
_wire->reset_search();
|
|
for (uint8_t i = 0; i < devices; i++) {
|
|
if (_wire->search(deviceAddress) && validAddress(deviceAddress)) {
|
|
setResolution(deviceAddress, bitResolution, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool DallasTemperature::setResolution(const uint8_t* deviceAddress, uint8_t newResolution, bool skipGlobalBitResolutionCalculation) {
|
|
bool success = false;
|
|
|
|
if (deviceAddress[0] == DS18S20MODEL) {
|
|
success = true;
|
|
} else {
|
|
newResolution = constrain(newResolution, 9, 12);
|
|
uint8_t newValue = 0;
|
|
ScratchPad scratchPad;
|
|
|
|
if (isConnected(deviceAddress, scratchPad)) {
|
|
switch (newResolution) {
|
|
case 12: newValue = TEMP_12_BIT; break;
|
|
case 11: newValue = TEMP_11_BIT; break;
|
|
case 10: newValue = TEMP_10_BIT; break;
|
|
case 9:
|
|
default: newValue = TEMP_9_BIT; break;
|
|
}
|
|
|
|
if (scratchPad[CONFIGURATION] != newValue) {
|
|
scratchPad[CONFIGURATION] = newValue;
|
|
writeScratchPad(deviceAddress, scratchPad);
|
|
}
|
|
success = true;
|
|
}
|
|
}
|
|
|
|
if (!skipGlobalBitResolutionCalculation && success) {
|
|
bitResolution = newResolution;
|
|
if (devices > 1) {
|
|
DeviceAddress deviceAddr;
|
|
_wire->reset_search();
|
|
for (uint8_t i = 0; i < devices; i++) {
|
|
if (bitResolution == 12) break;
|
|
if (_wire->search(deviceAddr) && validAddress(deviceAddr)) {
|
|
uint8_t b = getResolution(deviceAddr);
|
|
if (b > bitResolution) bitResolution = b;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
uint8_t DallasTemperature::getResolution() {
|
|
return bitResolution;
|
|
}
|
|
|
|
uint8_t DallasTemperature::getResolution(const uint8_t* deviceAddress) {
|
|
if (deviceAddress[0] == DS18S20MODEL) return 12;
|
|
|
|
ScratchPad scratchPad;
|
|
if (isConnected(deviceAddress, scratchPad)) {
|
|
if (deviceAddress[0] == DS1825MODEL && scratchPad[CONFIGURATION] & 0x80) {
|
|
return 12;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
float DallasTemperature::toFahrenheit(float celsius) {
|
|
return (celsius * 1.8f) + 32.0f;
|
|
}
|
|
|
|
float DallasTemperature::toCelsius(float fahrenheit) {
|
|
return (fahrenheit - 32.0f) * 0.555555556f;
|
|
}
|
|
|
|
float DallasTemperature::rawToCelsius(int32_t raw) {
|
|
if (raw <= DEVICE_DISCONNECTED_RAW)
|
|
return DEVICE_DISCONNECTED_C;
|
|
return (float)raw * 0.0078125f; // 1/128
|
|
}
|
|
|
|
float DallasTemperature::rawToFahrenheit(int32_t raw) {
|
|
if (raw <= DEVICE_DISCONNECTED_RAW)
|
|
return DEVICE_DISCONNECTED_F;
|
|
return rawToCelsius(raw) * 1.8f + 32.0f;
|
|
}
|
|
|
|
int16_t DallasTemperature::celsiusToRaw(float celsius) {
|
|
return static_cast<int16_t>(celsius * 128.0f);
|
|
}
|
|
|
|
uint16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution) {
|
|
switch (bitResolution) {
|
|
case 9: return 94;
|
|
case 10: return 188;
|
|
case 11: return 375;
|
|
default: return 750;
|
|
}
|
|
}
|
|
|
|
uint16_t DallasTemperature::millisToWaitForConversion() {
|
|
return millisToWaitForConversion(bitResolution);
|
|
}
|
|
|
|
void DallasTemperature::setWaitForConversion(bool flag) {
|
|
waitForConversion = flag;
|
|
}
|
|
|
|
bool DallasTemperature::getWaitForConversion() {
|
|
return waitForConversion;
|
|
}
|
|
|
|
void DallasTemperature::setCheckForConversion(bool flag) {
|
|
checkForConversion = flag;
|
|
}
|
|
|
|
bool DallasTemperature::getCheckForConversion() {
|
|
return checkForConversion;
|
|
}
|
|
|
|
bool DallasTemperature::isConversionComplete() {
|
|
uint8_t b = _wire->read_bit();
|
|
return (b == 1);
|
|
}
|
|
|
|
void DallasTemperature::setAutoSaveScratchPad(bool flag) {
|
|
autoSaveScratchPad = flag;
|
|
}
|
|
|
|
bool DallasTemperature::getAutoSaveScratchPad() {
|
|
return autoSaveScratchPad;
|
|
}
|
|
|
|
DallasTemperature::request_t DallasTemperature::requestTemperatures() {
|
|
request_t req = {};
|
|
req.result = true;
|
|
|
|
_wire->reset();
|
|
_wire->skip();
|
|
_wire->write(STARTCONVO, parasite);
|
|
|
|
req.timestamp = millis();
|
|
if (!waitForConversion) return req;
|
|
|
|
blockTillConversionComplete(bitResolution, req.timestamp);
|
|
return req;
|
|
}
|
|
|
|
DallasTemperature::request_t DallasTemperature::requestTemperaturesByAddress(const uint8_t* deviceAddress) {
|
|
request_t req = {};
|
|
uint8_t deviceBitResolution = getResolution(deviceAddress);
|
|
if (deviceBitResolution == 0) {
|
|
req.result = false;
|
|
return req;
|
|
}
|
|
|
|
_wire->reset();
|
|
_wire->select(deviceAddress);
|
|
_wire->write(STARTCONVO, parasite);
|
|
|
|
req.timestamp = millis();
|
|
req.result = true;
|
|
|
|
if (!waitForConversion) return req;
|
|
|
|
blockTillConversionComplete(deviceBitResolution, req.timestamp);
|
|
return req;
|
|
}
|
|
|
|
DallasTemperature::request_t DallasTemperature::requestTemperaturesByIndex(uint8_t index) {
|
|
DeviceAddress deviceAddress;
|
|
getAddress(deviceAddress, index);
|
|
return requestTemperaturesByAddress(deviceAddress);
|
|
}
|
|
|
|
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution) {
|
|
unsigned long start = millis();
|
|
blockTillConversionComplete(bitResolution, start);
|
|
}
|
|
|
|
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution, unsigned long start) {
|
|
if (checkForConversion && !parasite) {
|
|
while (!isConversionComplete() && ((unsigned long)(millis() - start) < (unsigned long)MAX_CONVERSION_TIMEOUT)) {
|
|
yield();
|
|
}
|
|
} else {
|
|
unsigned long delayInMillis = millisToWaitForConversion(bitResolution);
|
|
activateExternalPullup();
|
|
delay(delayInMillis);
|
|
deactivateExternalPullup();
|
|
}
|
|
}
|
|
|
|
void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution, request_t req) {
|
|
if (req.result) {
|
|
blockTillConversionComplete(bitResolution, req.timestamp);
|
|
}
|
|
}
|
|
|
|
int32_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress, uint8_t* scratchPad) {
|
|
int32_t fpTemperature = 0;
|
|
|
|
// looking thru the spec sheets of all supported devices, bit 15 is always the signing bit
|
|
int32_t neg = 0x0;
|
|
if (scratchPad[TEMP_MSB] & 0x80)
|
|
neg = 0xFFF80000;
|
|
|
|
// detect MAX31850
|
|
if (deviceAddress[0] == DS1825MODEL && scratchPad[CONFIGURATION] & 0x80) {
|
|
if (scratchPad[TEMP_LSB] & 1) { // Fault Detected
|
|
if (scratchPad[HIGH_ALARM_TEMP] & 1) {
|
|
return DEVICE_FAULT_OPEN_RAW;
|
|
} else if (scratchPad[HIGH_ALARM_TEMP] >> 1 & 1) {
|
|
return DEVICE_FAULT_SHORTGND_RAW;
|
|
} else if (scratchPad[HIGH_ALARM_TEMP] >> 2 & 1) {
|
|
return DEVICE_FAULT_SHORTVDD_RAW;
|
|
} else {
|
|
return DEVICE_DISCONNECTED_RAW;
|
|
}
|
|
}
|
|
// We must mask out bit 1 (reserved) and 0 (fault) on TEMP_LSB
|
|
fpTemperature = (((int32_t)scratchPad[TEMP_MSB]) << 11)
|
|
| (((int32_t)scratchPad[TEMP_LSB] & 0xFC) << 3)
|
|
| neg;
|
|
} else {
|
|
fpTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 11)
|
|
| (((int16_t)scratchPad[TEMP_LSB]) << 3)
|
|
| neg;
|
|
}
|
|
|
|
/*
|
|
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[DSROM_FAMILY] == DS18S20MODEL) && (scratchPad[COUNT_PER_C] != 0)) {
|
|
fpTemperature = (((fpTemperature & 0xfff0) << 3) - 32
|
|
+ (((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7)
|
|
/ scratchPad[COUNT_PER_C])) | neg;
|
|
}
|
|
|
|
return fpTemperature;
|
|
}
|
|
|
|
#if REQUIRESALARMS
|
|
|
|
void DallasTemperature::setAlarmHandler(const AlarmHandler* handler) {
|
|
_AlarmHandler = handler;
|
|
}
|
|
|
|
void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress, int8_t 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);
|
|
}
|
|
}
|
|
|
|
void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress, int8_t 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);
|
|
}
|
|
}
|
|
|
|
int8_t DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress) {
|
|
ScratchPad scratchPad;
|
|
if (isConnected(deviceAddress, scratchPad))
|
|
return (int8_t)scratchPad[HIGH_ALARM_TEMP];
|
|
return DEVICE_DISCONNECTED_C;
|
|
}
|
|
|
|
int8_t DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress) {
|
|
ScratchPad scratchPad;
|
|
if (isConnected(deviceAddress, scratchPad))
|
|
return (int8_t)scratchPad[LOW_ALARM_TEMP];
|
|
return DEVICE_DISCONNECTED_C;
|
|
}
|
|
|
|
void DallasTemperature::resetAlarmSearch() {
|
|
alarmSearchJunction = -1;
|
|
alarmSearchExhausted = 0;
|
|
for (uint8_t i = 0; i < 7; i++) {
|
|
alarmSearchAddress[i] = 0;
|
|
}
|
|
}
|
|
|
|
bool DallasTemperature::alarmSearch(uint8_t* newAddr) {
|
|
uint8_t i;
|
|
int8_t lastJunction = -1;
|
|
uint8_t done = 1;
|
|
|
|
if (alarmSearchExhausted)
|
|
return false;
|
|
|
|
if (!_wire->reset())
|
|
return false;
|
|
|
|
_wire->write(ALARMSEARCH);
|
|
|
|
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);
|
|
|
|
if (a && nota)
|
|
return false;
|
|
|
|
if (!a && !nota) {
|
|
if (i == alarmSearchJunction) {
|
|
a = 1;
|
|
alarmSearchJunction = lastJunction;
|
|
} else if (i < alarmSearchJunction) {
|
|
if (alarmSearchAddress[ibyte] & ibit) {
|
|
a = 1;
|
|
} else {
|
|
a = 0;
|
|
done = 0;
|
|
lastJunction = i;
|
|
}
|
|
} else {
|
|
a = 0;
|
|
alarmSearchJunction = i;
|
|
done = 0;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress) {
|
|
ScratchPad scratchPad;
|
|
if (isConnected(deviceAddress, scratchPad)) {
|
|
int8_t temp = calculateTemperature(deviceAddress, scratchPad) >> 7;
|
|
return (temp <= (int8_t)scratchPad[LOW_ALARM_TEMP] ||
|
|
temp >= (int8_t)scratchPad[HIGH_ALARM_TEMP]);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool DallasTemperature::hasAlarm(void) {
|
|
DeviceAddress deviceAddress;
|
|
resetAlarmSearch();
|
|
return alarmSearch(deviceAddress);
|
|
}
|
|
|
|
void DallasTemperature::processAlarms(void) {
|
|
if (!hasAlarmHandler())
|
|
return;
|
|
|
|
resetAlarmSearch();
|
|
DeviceAddress alarmAddr;
|
|
|
|
while (alarmSearch(alarmAddr)) {
|
|
if (validAddress(alarmAddr)) {
|
|
_AlarmHandler(alarmAddr);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool DallasTemperature::hasAlarmHandler() {
|
|
return (_AlarmHandler != NO_ALARM_HANDLER);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if REQUIRESNEW
|
|
|
|
void* DallasTemperature::operator new(unsigned int size) {
|
|
void* p = malloc(size);
|
|
memset(p, 0, size);
|
|
return p;
|
|
}
|
|
|
|
void DallasTemperature::operator delete(void* p) {
|
|
free(p);
|
|
}
|
|
|
|
#endif
|
|
|
|
bool DallasTemperature::verifyDeviceCount(void) {
|
|
uint8_t actualCount = 0;
|
|
float temp;
|
|
|
|
requestTemperatures();
|
|
|
|
do {
|
|
temp = getTempCByIndex(actualCount);
|
|
if (temp > DEVICE_DISCONNECTED_C) {
|
|
actualCount++;
|
|
}
|
|
} while (temp > DEVICE_DISCONNECTED_C && actualCount < 255);
|
|
|
|
if (actualCount > devices) {
|
|
devices = actualCount;
|
|
begin();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void DallasTemperature::setUserData(const uint8_t* deviceAddress, int16_t data) {
|
|
// return when stored value == new value
|
|
if (getUserData(deviceAddress) == data)
|
|
return;
|
|
|
|
ScratchPad scratchPad;
|
|
if (isConnected(deviceAddress, scratchPad)) {
|
|
scratchPad[HIGH_ALARM_TEMP] = data >> 8;
|
|
scratchPad[LOW_ALARM_TEMP] = data & 255;
|
|
writeScratchPad(deviceAddress, scratchPad);
|
|
}
|
|
}
|
|
|
|
void DallasTemperature::setUserDataByIndex(uint8_t deviceIndex, int16_t data) {
|
|
DeviceAddress deviceAddress;
|
|
if (getAddress(deviceAddress, deviceIndex)) {
|
|
setUserData((uint8_t*)deviceAddress, data);
|
|
}
|
|
}
|
|
|
|
int16_t DallasTemperature::getUserData(const uint8_t* deviceAddress) {
|
|
int16_t data = 0;
|
|
ScratchPad scratchPad;
|
|
if (isConnected(deviceAddress, scratchPad)) {
|
|
data = scratchPad[HIGH_ALARM_TEMP] << 8;
|
|
data += scratchPad[LOW_ALARM_TEMP];
|
|
}
|
|
return data;
|
|
}
|
|
|
|
int16_t DallasTemperature::getUserDataByIndex(uint8_t deviceIndex) {
|
|
DeviceAddress deviceAddress;
|
|
getAddress(deviceAddress, deviceIndex);
|
|
return getUserData((uint8_t*)deviceAddress);
|
|
} |