DallasTemperature.cpp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033
  1. // This library is free software; you can redistribute it and/or
  2. // modify it under the terms of the GNU Lesser General Public
  3. // License as published by the Free Software Foundation; either
  4. // version 2.1 of the License, or (at your option) any later version.
  5. #include "DallasTemperature.h"
  6. #if ARDUINO >= 100
  7. #include "Arduino.h"
  8. #else
  9. extern "C" {
  10. #include "WConstants.h"
  11. }
  12. #endif
  13. // OneWire commands
  14. #define STARTCONVO 0x44 // Tells device to take a temperature reading and put it on the scratchpad
  15. #define COPYSCRATCH 0x48 // Copy scratchpad to EEPROM
  16. #define READSCRATCH 0xBE // Read from scratchpad
  17. #define WRITESCRATCH 0x4E // Write to scratchpad
  18. #define RECALLSCRATCH 0xB8 // Recall from EEPROM to scratchpad
  19. #define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power
  20. #define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition
  21. // Scratchpad locations
  22. #define TEMP_LSB 0
  23. #define TEMP_MSB 1
  24. #define HIGH_ALARM_TEMP 2
  25. #define LOW_ALARM_TEMP 3
  26. #define CONFIGURATION 4
  27. #define INTERNAL_BYTE 5
  28. #define COUNT_REMAIN 6
  29. #define COUNT_PER_C 7
  30. #define SCRATCHPAD_CRC 8
  31. // DSROM FIELDS
  32. #define DSROM_FAMILY 0
  33. #define DSROM_CRC 7
  34. // Device resolution
  35. #define TEMP_9_BIT 0x1F // 9 bit
  36. #define TEMP_10_BIT 0x3F // 10 bit
  37. #define TEMP_11_BIT 0x5F // 11 bit
  38. #define TEMP_12_BIT 0x7F // 12 bit
  39. #define MAX_CONVERSION_TIMEOUT 750
  40. // Alarm handler
  41. #define NO_ALARM_HANDLER ((AlarmHandler *)0)
  42. DallasTemperature::DallasTemperature() {
  43. #if REQUIRESALARMS
  44. setAlarmHandler(NO_ALARM_HANDLER);
  45. #endif
  46. useExternalPullup = false;
  47. }
  48. DallasTemperature::DallasTemperature(OneWire* _oneWire) : DallasTemperature() {
  49. setOneWire(_oneWire);
  50. }
  51. bool DallasTemperature::validFamily(const uint8_t* deviceAddress) {
  52. switch (deviceAddress[DSROM_FAMILY]) {
  53. case DS18S20MODEL:
  54. case DS18B20MODEL:
  55. case DS1822MODEL:
  56. case DS1825MODEL:
  57. case DS28EA00MODEL:
  58. return true;
  59. default:
  60. return false;
  61. }
  62. }
  63. /*
  64. * Constructs DallasTemperature with strong pull-up turned on. Strong pull-up is mandated in DS18B20 datasheet for parasitic
  65. * power (2 wires) setup. (https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf, p. 7, section 'Powering the DS18B20').
  66. */
  67. DallasTemperature::DallasTemperature(OneWire* _oneWire, uint8_t _pullupPin) : DallasTemperature(_oneWire) {
  68. setPullupPin(_pullupPin);
  69. }
  70. void DallasTemperature::setPullupPin(uint8_t _pullupPin) {
  71. useExternalPullup = true;
  72. pullupPin = _pullupPin;
  73. pinMode(pullupPin, OUTPUT);
  74. deactivateExternalPullup();
  75. }
  76. void DallasTemperature::setOneWire(OneWire* _oneWire) {
  77. _wire = _oneWire;
  78. devices = 0;
  79. ds18Count = 0;
  80. parasite = false;
  81. bitResolution = 9;
  82. waitForConversion = true;
  83. checkForConversion = true;
  84. autoSaveScratchPad = true;
  85. }
  86. // initialise the bus
  87. void DallasTemperature::begin(void) {
  88. DeviceAddress deviceAddress;
  89. _wire->reset_search();
  90. devices = 0; // Reset the number of devices when we enumerate wire devices
  91. ds18Count = 0; // Reset number of DS18xxx Family devices
  92. while (_wire->search(deviceAddress)) {
  93. if (validAddress(deviceAddress)) {
  94. devices++;
  95. if (validFamily(deviceAddress)) {
  96. ds18Count++;
  97. if (!parasite && readPowerSupply(deviceAddress))
  98. parasite = true;
  99. uint8_t b = getResolution(deviceAddress);
  100. if (b > bitResolution) bitResolution = b;
  101. }
  102. }
  103. }
  104. }
  105. // returns the number of devices found on the bus
  106. uint8_t DallasTemperature::getDeviceCount(void) {
  107. return devices;
  108. }
  109. uint8_t DallasTemperature::getDS18Count(void) {
  110. return ds18Count;
  111. }
  112. // returns true if address is valid
  113. bool DallasTemperature::validAddress(const uint8_t* deviceAddress) {
  114. return (_wire->crc8(deviceAddress, 7) == deviceAddress[DSROM_CRC]);
  115. }
  116. // finds an address at a given index on the bus
  117. // returns true if the device was found
  118. bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index) {
  119. uint8_t depth = 0;
  120. _wire->reset_search();
  121. while (depth <= index && _wire->search(deviceAddress)) {
  122. if (depth == index && validAddress(deviceAddress))
  123. return true;
  124. depth++;
  125. }
  126. return false;
  127. }
  128. // attempt to determine if the device at the given address is connected to the bus
  129. bool DallasTemperature::isConnected(const uint8_t* deviceAddress) {
  130. ScratchPad scratchPad;
  131. return isConnected(deviceAddress, scratchPad);
  132. }
  133. // attempt to determine if the device at the given address is connected to the bus
  134. // also allows for updating the read scratchpad
  135. bool DallasTemperature::isConnected(const uint8_t* deviceAddress,
  136. uint8_t* scratchPad) {
  137. bool b = readScratchPad(deviceAddress, scratchPad);
  138. return b && !isAllZeros(scratchPad) && (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
  139. }
  140. bool DallasTemperature::readScratchPad(const uint8_t* deviceAddress,
  141. uint8_t* scratchPad) {
  142. // send the reset command and fail fast
  143. int b = _wire->reset();
  144. if (b == 0)
  145. return false;
  146. _wire->select(deviceAddress);
  147. _wire->write(READSCRATCH);
  148. // Read all registers in a simple loop
  149. // byte 0: temperature LSB
  150. // byte 1: temperature MSB
  151. // byte 2: high alarm temp
  152. // byte 3: low alarm temp
  153. // byte 4: DS18S20: store for crc
  154. // DS18B20 & DS1822: configuration register
  155. // byte 5: internal use & crc
  156. // byte 6: DS18S20: COUNT_REMAIN
  157. // DS18B20 & DS1822: store for crc
  158. // byte 7: DS18S20: COUNT_PER_C
  159. // DS18B20 & DS1822: store for crc
  160. // byte 8: SCRATCHPAD_CRC
  161. for (uint8_t i = 0; i < 9; i++) {
  162. scratchPad[i] = _wire->read();
  163. }
  164. b = _wire->reset();
  165. return (b == 1);
  166. }
  167. void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress,
  168. const uint8_t* scratchPad) {
  169. _wire->reset();
  170. _wire->select(deviceAddress);
  171. _wire->write(WRITESCRATCH);
  172. _wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp
  173. _wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp
  174. // DS1820 and DS18S20 have no configuration register
  175. if (deviceAddress[DSROM_FAMILY] != DS18S20MODEL)
  176. _wire->write(scratchPad[CONFIGURATION]);
  177. if (autoSaveScratchPad)
  178. saveScratchPad(deviceAddress);
  179. else
  180. _wire->reset();
  181. }
  182. // returns true if parasite mode is used (2 wire)
  183. // returns false if normal mode is used (3 wire)
  184. // if no address is given (or nullptr) it checks if any device on the bus
  185. // uses parasite mode.
  186. // See issue #145
  187. bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress)
  188. {
  189. bool parasiteMode = false;
  190. _wire->reset();
  191. if (deviceAddress == nullptr)
  192. _wire->skip();
  193. else
  194. _wire->select(deviceAddress);
  195. _wire->write(READPOWERSUPPLY);
  196. if (_wire->read_bit() == 0)
  197. parasiteMode = true;
  198. _wire->reset();
  199. return parasiteMode;
  200. }
  201. // set resolution of all devices to 9, 10, 11, or 12 bits
  202. // if new resolution is out of range, it is constrained.
  203. void DallasTemperature::setResolution(uint8_t newResolution) {
  204. bitResolution = constrain(newResolution, 9, 12);
  205. DeviceAddress deviceAddress;
  206. for (uint8_t i = 0; i < devices; i++) {
  207. getAddress(deviceAddress, i);
  208. setResolution(deviceAddress, bitResolution, true);
  209. }
  210. }
  211. /* PROPOSAL */
  212. // set resolution of a device to 9, 10, 11, or 12 bits
  213. // if new resolution is out of range, 9 bits is used.
  214. bool DallasTemperature::setResolution(const uint8_t* deviceAddress,
  215. uint8_t newResolution, bool skipGlobalBitResolutionCalculation) {
  216. bool success = false;
  217. // DS1820 and DS18S20 have no resolution configuration register
  218. if (deviceAddress[DSROM_FAMILY] == DS18S20MODEL)
  219. {
  220. success = true;
  221. }
  222. else
  223. {
  224. // handle the sensors with configuration register
  225. newResolution = constrain(newResolution, 9, 12);
  226. uint8_t newValue = 0;
  227. ScratchPad scratchPad;
  228. // we can only update the sensor if it is connected
  229. if (isConnected(deviceAddress, scratchPad))
  230. {
  231. switch (newResolution) {
  232. case 12:
  233. newValue = TEMP_12_BIT;
  234. break;
  235. case 11:
  236. newValue = TEMP_11_BIT;
  237. break;
  238. case 10:
  239. newValue = TEMP_10_BIT;
  240. break;
  241. case 9:
  242. default:
  243. newValue = TEMP_9_BIT;
  244. break;
  245. }
  246. // if it needs to be updated we write the new value
  247. if (scratchPad[CONFIGURATION] != newValue)
  248. {
  249. scratchPad[CONFIGURATION] = newValue;
  250. writeScratchPad(deviceAddress, scratchPad);
  251. }
  252. // done
  253. success = true;
  254. }
  255. }
  256. // do we need to update the max resolution used?
  257. if (skipGlobalBitResolutionCalculation == false)
  258. {
  259. bitResolution = newResolution;
  260. if (devices > 1)
  261. {
  262. for (uint8_t i = 0; i < devices; i++)
  263. {
  264. if (bitResolution == 12) break;
  265. DeviceAddress deviceAddr;
  266. getAddress(deviceAddr, i);
  267. uint8_t b = getResolution(deviceAddr);
  268. if (b > bitResolution) bitResolution = b;
  269. }
  270. }
  271. }
  272. return success;
  273. }
  274. // returns the global resolution
  275. uint8_t DallasTemperature::getResolution() {
  276. return bitResolution;
  277. }
  278. // returns the current resolution of the device, 9-12
  279. // returns 0 if device not found
  280. uint8_t DallasTemperature::getResolution(const uint8_t* deviceAddress) {
  281. // DS1820 and DS18S20 have no resolution configuration register
  282. if (deviceAddress[DSROM_FAMILY] == DS18S20MODEL)
  283. return 12;
  284. ScratchPad scratchPad;
  285. if (isConnected(deviceAddress, scratchPad)) {
  286. switch (scratchPad[CONFIGURATION]) {
  287. case TEMP_12_BIT:
  288. return 12;
  289. case TEMP_11_BIT:
  290. return 11;
  291. case TEMP_10_BIT:
  292. return 10;
  293. case TEMP_9_BIT:
  294. return 9;
  295. }
  296. }
  297. return 0;
  298. }
  299. // sets the value of the waitForConversion flag
  300. // TRUE : function requestTemperature() etc returns when conversion is ready
  301. // FALSE: function requestTemperature() etc returns immediately (USE WITH CARE!!)
  302. // (1) programmer has to check if the needed delay has passed
  303. // (2) but the application can do meaningful things in that time
  304. void DallasTemperature::setWaitForConversion(bool flag) {
  305. waitForConversion = flag;
  306. }
  307. // gets the value of the waitForConversion flag
  308. bool DallasTemperature::getWaitForConversion() {
  309. return waitForConversion;
  310. }
  311. // sets the value of the checkForConversion flag
  312. // TRUE : function requestTemperature() etc will 'listen' to an IC to determine whether a conversion is complete
  313. // FALSE: function requestTemperature() etc will wait a set time (worst case scenario) for a conversion to complete
  314. void DallasTemperature::setCheckForConversion(bool flag) {
  315. checkForConversion = flag;
  316. }
  317. // gets the value of the waitForConversion flag
  318. bool DallasTemperature::getCheckForConversion() {
  319. return checkForConversion;
  320. }
  321. bool DallasTemperature::isConversionComplete() {
  322. uint8_t b = _wire->read_bit();
  323. return (b == 1);
  324. }
  325. // sends command for all devices on the bus to perform a temperature conversion
  326. void DallasTemperature::requestTemperatures() {
  327. _wire->reset();
  328. _wire->skip();
  329. _wire->write(STARTCONVO, parasite);
  330. // ASYNC mode?
  331. if (!waitForConversion)
  332. return;
  333. blockTillConversionComplete(bitResolution);
  334. }
  335. // sends command for one device to perform a temperature by address
  336. // returns FALSE if device is disconnected
  337. // returns TRUE otherwise
  338. bool DallasTemperature::requestTemperaturesByAddress(
  339. const uint8_t* deviceAddress) {
  340. uint8_t bitResolution = getResolution(deviceAddress);
  341. if (bitResolution == 0) {
  342. return false; //Device disconnected
  343. }
  344. _wire->reset();
  345. _wire->select(deviceAddress);
  346. _wire->write(STARTCONVO, parasite);
  347. // ASYNC mode?
  348. if (!waitForConversion)
  349. return true;
  350. blockTillConversionComplete(bitResolution);
  351. return true;
  352. }
  353. // Continue to check if the IC has responded with a temperature
  354. void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution) {
  355. if (checkForConversion && !parasite) {
  356. unsigned long start = millis();
  357. while (!isConversionComplete() && (millis() - start < MAX_CONVERSION_TIMEOUT ))
  358. yield();
  359. } else {
  360. unsigned long delms = millisToWaitForConversion(bitResolution);
  361. activateExternalPullup();
  362. delay(delms);
  363. deactivateExternalPullup();
  364. }
  365. }
  366. // returns number of milliseconds to wait till conversion is complete (based on IC datasheet)
  367. int16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution) {
  368. switch (bitResolution) {
  369. case 9:
  370. return 94;
  371. case 10:
  372. return 188;
  373. case 11:
  374. return 375;
  375. default:
  376. return 750;
  377. }
  378. }
  379. // Sends command to one device to save values from scratchpad to EEPROM by index
  380. // Returns true if no errors were encountered, false indicates failure
  381. bool DallasTemperature::saveScratchPadByIndex(uint8_t deviceIndex) {
  382. DeviceAddress deviceAddress;
  383. if (!getAddress(deviceAddress, deviceIndex)) return false;
  384. return saveScratchPad(deviceAddress);
  385. }
  386. // Sends command to one or more devices to save values from scratchpad to EEPROM
  387. // If optional argument deviceAddress is omitted the command is send to all devices
  388. // Returns true if no errors were encountered, false indicates failure
  389. bool DallasTemperature::saveScratchPad(const uint8_t* deviceAddress) {
  390. if (_wire->reset() == 0)
  391. return false;
  392. if (deviceAddress == nullptr)
  393. _wire->skip();
  394. else
  395. _wire->select(deviceAddress);
  396. _wire->write(COPYSCRATCH,parasite);
  397. // Specification: NV Write Cycle Time is typically 2ms, max 10ms
  398. // Waiting 20ms to allow for sensors that take longer in practice
  399. if (!parasite) {
  400. delay(20);
  401. } else {
  402. activateExternalPullup();
  403. delay(20);
  404. deactivateExternalPullup();
  405. }
  406. return _wire->reset() == 1;
  407. }
  408. // Sends command to one device to recall values from EEPROM to scratchpad by index
  409. // Returns true if no errors were encountered, false indicates failure
  410. bool DallasTemperature::recallScratchPadByIndex(uint8_t deviceIndex) {
  411. DeviceAddress deviceAddress;
  412. if (!getAddress(deviceAddress, deviceIndex)) return false;
  413. return recallScratchPad(deviceAddress);
  414. }
  415. // Sends command to one or more devices to recall values from EEPROM to scratchpad
  416. // If optional argument deviceAddress is omitted the command is send to all devices
  417. // Returns true if no errors were encountered, false indicates failure
  418. bool DallasTemperature::recallScratchPad(const uint8_t* deviceAddress) {
  419. if (_wire->reset() == 0)
  420. return false;
  421. if (deviceAddress == nullptr)
  422. _wire->skip();
  423. else
  424. _wire->select(deviceAddress);
  425. _wire->write(RECALLSCRATCH,parasite);
  426. // Specification: Strong pullup only needed when writing to EEPROM (and temp conversion)
  427. unsigned long start = millis();
  428. while (_wire->read_bit() == 0) {
  429. // Datasheet doesn't specify typical/max duration, testing reveals typically within 1ms
  430. if (millis() - start > 20) return false;
  431. yield();
  432. }
  433. return _wire->reset() == 1;
  434. }
  435. // Sets the autoSaveScratchPad flag
  436. void DallasTemperature::setAutoSaveScratchPad(bool flag) {
  437. autoSaveScratchPad = flag;
  438. }
  439. // Gets the autoSaveScratchPad flag
  440. bool DallasTemperature::getAutoSaveScratchPad() {
  441. return autoSaveScratchPad;
  442. }
  443. void DallasTemperature::activateExternalPullup() {
  444. if(useExternalPullup)
  445. digitalWrite(pullupPin, LOW);
  446. }
  447. void DallasTemperature::deactivateExternalPullup() {
  448. if(useExternalPullup)
  449. digitalWrite(pullupPin, HIGH);
  450. }
  451. // sends command for one device to perform a temp conversion by index
  452. bool DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex) {
  453. DeviceAddress deviceAddress;
  454. getAddress(deviceAddress, deviceIndex);
  455. return requestTemperaturesByAddress(deviceAddress);
  456. }
  457. // Fetch temperature for device index
  458. float DallasTemperature::getTempCByIndex(uint8_t deviceIndex) {
  459. DeviceAddress deviceAddress;
  460. if (!getAddress(deviceAddress, deviceIndex)) {
  461. return DEVICE_DISCONNECTED_C;
  462. }
  463. return getTempC((uint8_t*) deviceAddress);
  464. }
  465. // Fetch temperature for device index
  466. float DallasTemperature::getTempFByIndex(uint8_t deviceIndex) {
  467. DeviceAddress deviceAddress;
  468. if (!getAddress(deviceAddress, deviceIndex)) {
  469. return DEVICE_DISCONNECTED_F;
  470. }
  471. return getTempF((uint8_t*) deviceAddress);
  472. }
  473. // reads scratchpad and returns fixed-point temperature, scaling factor 2^-7
  474. int16_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress,
  475. uint8_t* scratchPad) {
  476. int16_t fpTemperature = (((int16_t) scratchPad[TEMP_MSB]) << 11)
  477. | (((int16_t) scratchPad[TEMP_LSB]) << 3);
  478. /*
  479. DS1820 and DS18S20 have a 9-bit temperature register.
  480. Resolutions greater than 9-bit can be calculated using the data from
  481. the temperature, and COUNT REMAIN and COUNT PER °C registers in the
  482. scratchpad. The resolution of the calculation depends on the model.
  483. While the COUNT PER °C register is hard-wired to 16 (10h) in a
  484. DS18S20, it changes with temperature in DS1820.
  485. After reading the scratchpad, the TEMP_READ value is obtained by
  486. truncating the 0.5°C bit (bit 0) from the temperature data. The
  487. extended resolution temperature can then be calculated using the
  488. following equation:
  489. COUNT_PER_C - COUNT_REMAIN
  490. TEMPERATURE = TEMP_READ - 0.25 + --------------------------
  491. COUNT_PER_C
  492. Hagai Shatz simplified this to integer arithmetic for a 12 bits
  493. value for a DS18S20, and James Cameron added legacy DS1820 support.
  494. See - http://myarduinotoy.blogspot.co.uk/2013/02/12bit-result-from-ds18s20.html
  495. */
  496. if ((deviceAddress[DSROM_FAMILY] == DS18S20MODEL) && (scratchPad[COUNT_PER_C] != 0)) {
  497. fpTemperature = ((fpTemperature & 0xfff0) << 3) - 32
  498. + (((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7)
  499. / scratchPad[COUNT_PER_C]);
  500. }
  501. return fpTemperature;
  502. }
  503. // returns temperature in 1/128 degrees C or DEVICE_DISCONNECTED_RAW if the
  504. // device's scratch pad cannot be read successfully.
  505. // the numeric value of DEVICE_DISCONNECTED_RAW is defined in
  506. // DallasTemperature.h. It is a large negative number outside the
  507. // operating range of the device
  508. int16_t DallasTemperature::getTemp(const uint8_t* deviceAddress) {
  509. ScratchPad scratchPad;
  510. if (isConnected(deviceAddress, scratchPad))
  511. return calculateTemperature(deviceAddress, scratchPad);
  512. return DEVICE_DISCONNECTED_RAW;
  513. }
  514. // returns temperature in degrees C or DEVICE_DISCONNECTED_C if the
  515. // device's scratch pad cannot be read successfully.
  516. // the numeric value of DEVICE_DISCONNECTED_C is defined in
  517. // DallasTemperature.h. It is a large negative number outside the
  518. // operating range of the device
  519. float DallasTemperature::getTempC(const uint8_t* deviceAddress) {
  520. return rawToCelsius(getTemp(deviceAddress));
  521. }
  522. // returns temperature in degrees F or DEVICE_DISCONNECTED_F if the
  523. // device's scratch pad cannot be read successfully.
  524. // the numeric value of DEVICE_DISCONNECTED_F is defined in
  525. // DallasTemperature.h. It is a large negative number outside the
  526. // operating range of the device
  527. float DallasTemperature::getTempF(const uint8_t* deviceAddress) {
  528. return rawToFahrenheit(getTemp(deviceAddress));
  529. }
  530. // returns true if the bus requires parasite power
  531. bool DallasTemperature::isParasitePowerMode(void) {
  532. return parasite;
  533. }
  534. // IF alarm is not used one can store a 16 bit int of userdata in the alarm
  535. // registers. E.g. an ID of the sensor.
  536. // See github issue #29
  537. // note if device is not connected it will fail writing the data.
  538. void DallasTemperature::setUserData(const uint8_t* deviceAddress,
  539. int16_t data) {
  540. // return when stored value == new value
  541. if (getUserData(deviceAddress) == data)
  542. return;
  543. ScratchPad scratchPad;
  544. if (isConnected(deviceAddress, scratchPad)) {
  545. scratchPad[HIGH_ALARM_TEMP] = data >> 8;
  546. scratchPad[LOW_ALARM_TEMP] = data & 255;
  547. writeScratchPad(deviceAddress, scratchPad);
  548. }
  549. }
  550. int16_t DallasTemperature::getUserData(const uint8_t* deviceAddress) {
  551. int16_t data = 0;
  552. ScratchPad scratchPad;
  553. if (isConnected(deviceAddress, scratchPad)) {
  554. data = scratchPad[HIGH_ALARM_TEMP] << 8;
  555. data += scratchPad[LOW_ALARM_TEMP];
  556. }
  557. return data;
  558. }
  559. // note If address cannot be found no error will be reported.
  560. int16_t DallasTemperature::getUserDataByIndex(uint8_t deviceIndex) {
  561. DeviceAddress deviceAddress;
  562. getAddress(deviceAddress, deviceIndex);
  563. return getUserData((uint8_t*) deviceAddress);
  564. }
  565. void DallasTemperature::setUserDataByIndex(uint8_t deviceIndex, int16_t data) {
  566. DeviceAddress deviceAddress;
  567. getAddress(deviceAddress, deviceIndex);
  568. setUserData((uint8_t*) deviceAddress, data);
  569. }
  570. // Convert float Celsius to Fahrenheit
  571. float DallasTemperature::toFahrenheit(float celsius) {
  572. return (celsius * 1.8f) + 32.0f;
  573. }
  574. // Convert float Fahrenheit to Celsius
  575. float DallasTemperature::toCelsius(float fahrenheit) {
  576. return (fahrenheit - 32.0f) * 0.555555556f;
  577. }
  578. // convert from raw to Celsius
  579. float DallasTemperature::rawToCelsius(int16_t raw) {
  580. if (raw <= DEVICE_DISCONNECTED_RAW)
  581. return DEVICE_DISCONNECTED_C;
  582. // C = RAW/128
  583. return (float) raw * 0.0078125f;
  584. }
  585. // convert from raw to Fahrenheit
  586. float DallasTemperature::rawToFahrenheit(int16_t raw) {
  587. if (raw <= DEVICE_DISCONNECTED_RAW)
  588. return DEVICE_DISCONNECTED_F;
  589. // C = RAW/128
  590. // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32
  591. return ((float) raw * 0.0140625f) + 32.0f;
  592. }
  593. // Returns true if all bytes of scratchPad are '\0'
  594. bool DallasTemperature::isAllZeros(const uint8_t * const scratchPad, const size_t length) {
  595. for (size_t i = 0; i < length; i++) {
  596. if (scratchPad[i] != 0) {
  597. return false;
  598. }
  599. }
  600. return true;
  601. }
  602. #if REQUIRESALARMS
  603. /*
  604. ALARMS:
  605. TH and TL Register Format
  606. BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0
  607. S 2^6 2^5 2^4 2^3 2^2 2^1 2^0
  608. Only bits 11 through 4 of the temperature register are used
  609. in the TH and TL comparison since TH and TL are 8-bit
  610. registers. If the measured temperature is lower than or equal
  611. to TL or higher than or equal to TH, an alarm condition exists
  612. and an alarm flag is set inside the DS18B20. This flag is
  613. updated after every temperature measurement; therefore, if the
  614. alarm condition goes away, the flag will be turned off after
  615. the next temperature conversion.
  616. */
  617. // sets the high alarm temperature for a device in degrees Celsius
  618. // accepts a float, but the alarm resolution will ignore anything
  619. // after a decimal point. valid range is -55C - 125C
  620. void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress,
  621. int8_t celsius) {
  622. // return when stored value == new value
  623. if (getHighAlarmTemp(deviceAddress) == celsius)
  624. return;
  625. // make sure the alarm temperature is within the device's range
  626. if (celsius > 125)
  627. celsius = 125;
  628. else if (celsius < -55)
  629. celsius = -55;
  630. ScratchPad scratchPad;
  631. if (isConnected(deviceAddress, scratchPad)) {
  632. scratchPad[HIGH_ALARM_TEMP] = (uint8_t) celsius;
  633. writeScratchPad(deviceAddress, scratchPad);
  634. }
  635. }
  636. // sets the low alarm temperature for a device in degrees Celsius
  637. // accepts a float, but the alarm resolution will ignore anything
  638. // after a decimal point. valid range is -55C - 125C
  639. void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress,
  640. int8_t celsius) {
  641. // return when stored value == new value
  642. if (getLowAlarmTemp(deviceAddress) == celsius)
  643. return;
  644. // make sure the alarm temperature is within the device's range
  645. if (celsius > 125)
  646. celsius = 125;
  647. else if (celsius < -55)
  648. celsius = -55;
  649. ScratchPad scratchPad;
  650. if (isConnected(deviceAddress, scratchPad)) {
  651. scratchPad[LOW_ALARM_TEMP] = (uint8_t) celsius;
  652. writeScratchPad(deviceAddress, scratchPad);
  653. }
  654. }
  655. // returns a int8_t with the current high alarm temperature or
  656. // DEVICE_DISCONNECTED for an address
  657. int8_t DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress) {
  658. ScratchPad scratchPad;
  659. if (isConnected(deviceAddress, scratchPad))
  660. return (int8_t) scratchPad[HIGH_ALARM_TEMP];
  661. return DEVICE_DISCONNECTED_C;
  662. }
  663. // returns a int8_t with the current low alarm temperature or
  664. // DEVICE_DISCONNECTED for an address
  665. int8_t DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress) {
  666. ScratchPad scratchPad;
  667. if (isConnected(deviceAddress, scratchPad))
  668. return (int8_t) scratchPad[LOW_ALARM_TEMP];
  669. return DEVICE_DISCONNECTED_C;
  670. }
  671. // resets internal variables used for the alarm search
  672. void DallasTemperature::resetAlarmSearch() {
  673. alarmSearchJunction = -1;
  674. alarmSearchExhausted = 0;
  675. for (uint8_t i = 0; i < 7; i++) {
  676. alarmSearchAddress[i] = 0;
  677. }
  678. }
  679. // This is a modified version of the OneWire::search method.
  680. //
  681. // Also added the OneWire search fix documented here:
  682. // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295
  683. //
  684. // Perform an alarm search. If this function returns a '1' then it has
  685. // enumerated the next device and you may retrieve the ROM from the
  686. // OneWire::address variable. If there are no devices, no further
  687. // devices, or something horrible happens in the middle of the
  688. // enumeration then a 0 is returned. If a new device is found then
  689. // its address is copied to newAddr. Use
  690. // DallasTemperature::resetAlarmSearch() to start over.
  691. bool DallasTemperature::alarmSearch(uint8_t* newAddr) {
  692. uint8_t i;
  693. int8_t lastJunction = -1;
  694. uint8_t done = 1;
  695. if (alarmSearchExhausted)
  696. return false;
  697. if (!_wire->reset())
  698. return false;
  699. // send the alarm search command
  700. _wire->write(0xEC, 0);
  701. for (i = 0; i < 64; i++) {
  702. uint8_t a = _wire->read_bit();
  703. uint8_t nota = _wire->read_bit();
  704. uint8_t ibyte = i / 8;
  705. uint8_t ibit = 1 << (i & 7);
  706. // I don't think this should happen, this means nothing responded, but maybe if
  707. // something vanishes during the search it will come up.
  708. if (a && nota)
  709. return false;
  710. if (!a && !nota) {
  711. if (i == alarmSearchJunction) {
  712. // this is our time to decide differently, we went zero last time, go one.
  713. a = 1;
  714. alarmSearchJunction = lastJunction;
  715. } else if (i < alarmSearchJunction) {
  716. // take whatever we took last time, look in address
  717. if (alarmSearchAddress[ibyte] & ibit) {
  718. a = 1;
  719. } else {
  720. // Only 0s count as pending junctions, we've already exhausted the 0 side of 1s
  721. a = 0;
  722. done = 0;
  723. lastJunction = i;
  724. }
  725. } else {
  726. // we are blazing new tree, take the 0
  727. a = 0;
  728. alarmSearchJunction = i;
  729. done = 0;
  730. }
  731. // OneWire search fix
  732. // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295
  733. }
  734. if (a)
  735. alarmSearchAddress[ibyte] |= ibit;
  736. else
  737. alarmSearchAddress[ibyte] &= ~ibit;
  738. _wire->write_bit(a);
  739. }
  740. if (done)
  741. alarmSearchExhausted = 1;
  742. for (i = 0; i < 8; i++)
  743. newAddr[i] = alarmSearchAddress[i];
  744. return true;
  745. }
  746. // returns true if device address might have an alarm condition
  747. // (only an alarm search can verify this)
  748. bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress) {
  749. ScratchPad scratchPad;
  750. if (isConnected(deviceAddress, scratchPad)) {
  751. int8_t temp = calculateTemperature(deviceAddress, scratchPad) >> 7;
  752. // check low alarm
  753. if (temp <= (int8_t) scratchPad[LOW_ALARM_TEMP])
  754. return true;
  755. // check high alarm
  756. if (temp >= (int8_t) scratchPad[HIGH_ALARM_TEMP])
  757. return true;
  758. }
  759. // no alarm
  760. return false;
  761. }
  762. // returns true if any device is reporting an alarm condition on the bus
  763. bool DallasTemperature::hasAlarm(void) {
  764. DeviceAddress deviceAddress;
  765. resetAlarmSearch();
  766. return alarmSearch(deviceAddress);
  767. }
  768. // runs the alarm handler for all devices returned by alarmSearch()
  769. // unless there no _AlarmHandler exist.
  770. void DallasTemperature::processAlarms(void) {
  771. if (!hasAlarmHandler())
  772. {
  773. return;
  774. }
  775. resetAlarmSearch();
  776. DeviceAddress alarmAddr;
  777. while (alarmSearch(alarmAddr)) {
  778. if (validAddress(alarmAddr)) {
  779. _AlarmHandler(alarmAddr);
  780. }
  781. }
  782. }
  783. // sets the alarm handler
  784. void DallasTemperature::setAlarmHandler(const AlarmHandler *handler) {
  785. _AlarmHandler = handler;
  786. }
  787. // checks if AlarmHandler has been set.
  788. bool DallasTemperature::hasAlarmHandler()
  789. {
  790. return _AlarmHandler != NO_ALARM_HANDLER;
  791. }
  792. #endif
  793. #if REQUIRESNEW
  794. // MnetCS - Allocates memory for DallasTemperature. Allows us to instance a new object
  795. void* DallasTemperature::operator new(unsigned int size) { // Implicit NSS obj size
  796. void * p;// void pointer
  797. p = malloc(size);// Allocate memory
  798. memset((DallasTemperature*)p,0,size);// Initialise memory
  799. //!!! CANT EXPLICITLY CALL CONSTRUCTOR - workaround by using an init() methodR - workaround by using an init() method
  800. return (DallasTemperature*) p;// Cast blank region to NSS pointer
  801. }
  802. // MnetCS 2009 - Free the memory used by this instance
  803. void DallasTemperature::operator delete(void* p) {
  804. DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer
  805. pNss->~DallasTemperature();// Destruct the object
  806. free(p);// Free the memory
  807. }
  808. #endif