DallasTemperature.cpp 30 KB

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