ds18b20.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. /*
  14. noInterrupts();
  15. ^~~~
  16. warning: 'taskEXIT_CRITICAL(mux)' is deprecated in ESP-IDF, consider using 'portEXIT_CRITICAL(mux)'
  17. interrupts();
  18. ^~
  19. /Users/thomaschef/Documents/Develop/ESP32/HomeEnergyMeter/main/ds18b20.c: In function 'ds18b20_reset':
  20. /Users/thomaschef/Documents/Develop/ESP32/HomeEnergyMeter/main/ds18b20.c:123:13: warning: 'taskENTER_CRITICAL(mux)' is deprecated in ESP-IDF, consider using 'portENTER_CRITICAL(mux)'
  21. noInterrupts();
  22. ^~~~
  23. /Users/thomaschef/Documents/Develop/ESP32/HomeEnergyMeter/main/ds18b20.c:131:13: warning: 'taskEXIT_CRITICAL(mux)' is deprecated in ESP-IDF, consider using 'portEXIT_CR
  24. */
  25. #include "freertos/FreeRTOS.h"
  26. #include "freertos/task.h"
  27. #include "driver/gpio.h"
  28. #include "esp32/rom/ets_sys.h"
  29. #include "ds18b20.h"
  30. #include "config.h"
  31. #ifdef ENABLE_DS18B20
  32. // OneWire commands
  33. #define GETTEMP 0x44 // Tells device to take a temperature reading and put it on the scratchpad
  34. #define SKIPROM 0xCC // Command to address all devices on the bus
  35. #define SELECTDEVICE 0x55 // Command to address all devices on the bus
  36. #define COPYSCRATCH 0x48 // Copy scratchpad to EEPROM
  37. #define READSCRATCH 0xBE // Read from scratchpad
  38. #define WRITESCRATCH 0x4E // Write to scratchpad
  39. #define RECALLSCRATCH 0xB8 // Recall from EEPROM to scratchpad
  40. #define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power
  41. #define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition
  42. // Scratchpad locations
  43. #define TEMP_LSB 0
  44. #define TEMP_MSB 1
  45. #define HIGH_ALARM_TEMP 2
  46. #define LOW_ALARM_TEMP 3
  47. #define CONFIGURATION 4
  48. #define INTERNAL_BYTE 5
  49. #define COUNT_REMAIN 6
  50. #define COUNT_PER_C 7
  51. #define SCRATCHPAD_CRC 8
  52. // DSROM FIELDS
  53. #define DSROM_FAMILY 0
  54. #define DSROM_CRC 7
  55. // Device resolution
  56. #define TEMP_9_BIT 0x1F // 9 bit
  57. #define TEMP_10_BIT 0x3F // 10 bit
  58. #define TEMP_11_BIT 0x5F // 11 bit
  59. #define TEMP_12_BIT 0x7F // 12 bit
  60. uint8_t DS_GPIO;
  61. uint8_t init=0;
  62. uint8_t bitResolution=12;
  63. uint8_t devices=0;
  64. DeviceAddress ROM_NO;
  65. uint8_t LastDiscrepancy;
  66. uint8_t LastFamilyDiscrepancy;
  67. bool LastDeviceFlag;
  68. /// Sends one bit to bus
  69. void ds18b20_write(char bit){
  70. if (bit & 1) {
  71. gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT);
  72. noInterrupts();
  73. gpio_set_level(DS_GPIO,0);
  74. ets_delay_us(6);
  75. gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT); // release bus
  76. ets_delay_us(64);
  77. interrupts();
  78. } else {
  79. gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT);
  80. noInterrupts();
  81. gpio_set_level(DS_GPIO,0);
  82. ets_delay_us(60);
  83. gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT); // release bus
  84. ets_delay_us(10);
  85. interrupts();
  86. }
  87. }
  88. // Reads one bit from bus
  89. unsigned char ds18b20_read(void){
  90. unsigned char value = 0;
  91. gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT);
  92. noInterrupts();
  93. gpio_set_level(DS_GPIO, 0);
  94. ets_delay_us(6);
  95. gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT);
  96. ets_delay_us(9);
  97. value = gpio_get_level(DS_GPIO);
  98. ets_delay_us(55);
  99. interrupts();
  100. return (value);
  101. }
  102. // Sends one byte to bus
  103. void ds18b20_write_byte(char data){
  104. unsigned char i;
  105. unsigned char x;
  106. for(i=0;i<8;i++){
  107. x = data>>i;
  108. x &= 0x01;
  109. ds18b20_write(x);
  110. }
  111. ets_delay_us(100);
  112. }
  113. // Reads one byte from bus
  114. unsigned char ds18b20_read_byte(void){
  115. unsigned char i;
  116. unsigned char data = 0;
  117. for (i=0;i<8;i++)
  118. {
  119. if(ds18b20_read()) data|=0x01<<i;
  120. ets_delay_us(15);
  121. }
  122. return(data);
  123. }
  124. // Sends reset pulse
  125. unsigned char ds18b20_reset(void){
  126. unsigned char presence;
  127. gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT);
  128. noInterrupts();
  129. gpio_set_level(DS_GPIO, 0);
  130. ets_delay_us(480);
  131. gpio_set_level(DS_GPIO, 1);
  132. gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT);
  133. ets_delay_us(70);
  134. presence = (gpio_get_level(DS_GPIO) == 0);
  135. ets_delay_us(410);
  136. interrupts();
  137. return presence;
  138. }
  139. bool ds18b20_setResolution(const DeviceAddress tempSensorAddresses[], int numAddresses, uint8_t newResolution) {
  140. bool success = false;
  141. // handle the sensors with configuration register
  142. newResolution = constrain(newResolution, 9, 12);
  143. uint8_t newValue = 0;
  144. ScratchPad scratchPad;
  145. // loop through each address
  146. for (int i = 0; i < numAddresses; i++){
  147. // we can only update the sensor if it is connected
  148. if (ds18b20_isConnected((DeviceAddress*) tempSensorAddresses[i], scratchPad)) {
  149. switch (newResolution) {
  150. case 12:
  151. newValue = TEMP_12_BIT;
  152. break;
  153. case 11:
  154. newValue = TEMP_11_BIT;
  155. break;
  156. case 10:
  157. newValue = TEMP_10_BIT;
  158. break;
  159. case 9:
  160. default:
  161. newValue = TEMP_9_BIT;
  162. break;
  163. }
  164. // if it needs to be updated we write the new value
  165. if (scratchPad[CONFIGURATION] != newValue) {
  166. scratchPad[CONFIGURATION] = newValue;
  167. ds18b20_writeScratchPad((DeviceAddress*) tempSensorAddresses[i], scratchPad);
  168. }
  169. // done
  170. success = true;
  171. }
  172. }
  173. return success;
  174. }
  175. void ds18b20_writeScratchPad(const DeviceAddress *deviceAddress, const uint8_t *scratchPad) {
  176. ds18b20_reset();
  177. ds18b20_select(deviceAddress);
  178. ds18b20_write_byte(WRITESCRATCH);
  179. ds18b20_write_byte(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp
  180. ds18b20_write_byte(scratchPad[LOW_ALARM_TEMP]); // low alarm temp
  181. ds18b20_write_byte(scratchPad[CONFIGURATION]);
  182. ds18b20_reset();
  183. }
  184. bool ds18b20_readScratchPad(const DeviceAddress *deviceAddress, uint8_t* scratchPad) {
  185. // send the reset command and fail fast
  186. int b = ds18b20_reset();
  187. if (b == 0) return false;
  188. ds18b20_select(deviceAddress);
  189. ds18b20_write_byte(READSCRATCH);
  190. // Read all registers in a simple loop
  191. // byte 0: temperature LSB
  192. // byte 1: temperature MSB
  193. // byte 2: high alarm temp
  194. // byte 3: low alarm temp
  195. // byte 4: DS18B20 & DS1822: configuration register
  196. // byte 5: internal use & crc
  197. // byte 6: DS18B20 & DS1822: store for crc
  198. // byte 7: DS18B20 & DS1822: store for crc
  199. // byte 8: SCRATCHPAD_CRC
  200. for (uint8_t i = 0; i < 9; i++) {
  201. scratchPad[i] = ds18b20_read_byte();
  202. }
  203. b = ds18b20_reset();
  204. return (b == 1);
  205. }
  206. void ds18b20_select(const DeviceAddress *address){
  207. uint8_t i;
  208. ds18b20_write_byte(SELECTDEVICE); // Choose ROM
  209. for (i = 0; i < 8; i++) ds18b20_write_byte(((uint8_t *)address)[i]);
  210. }
  211. void ds18b20_requestTemperatures(){
  212. ds18b20_reset();
  213. ds18b20_write_byte(SKIPROM);
  214. ds18b20_write_byte(GETTEMP);
  215. unsigned long start = esp_timer_get_time() / 1000ULL;
  216. while (!isConversionComplete() && ((esp_timer_get_time() / 1000ULL) - start < millisToWaitForConversion())) vPortYield();
  217. }
  218. bool isConversionComplete() {
  219. uint8_t b = ds18b20_read();
  220. return (b == 1);
  221. }
  222. uint16_t millisToWaitForConversion() {
  223. switch (bitResolution) {
  224. case 9:
  225. return 94;
  226. case 10:
  227. return 188;
  228. case 11:
  229. return 375;
  230. default:
  231. return 750;
  232. }
  233. }
  234. bool ds18b20_isConnected(const DeviceAddress *deviceAddress, uint8_t *scratchPad) {
  235. bool b = ds18b20_readScratchPad(deviceAddress, scratchPad);
  236. return b && !ds18b20_isAllZeros(scratchPad) && (ds18b20_crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
  237. }
  238. uint8_t ds18b20_crc8(const uint8_t *addr, uint8_t len){
  239. uint8_t crc = 0;
  240. while (len--) {
  241. crc = *addr++ ^ crc; // just re-using crc as intermediate
  242. crc = pgm_read_byte(dscrc2x16_table + (crc & 0x0f)) ^
  243. pgm_read_byte(dscrc2x16_table + 16 + ((crc >> 4) & 0x0f));
  244. }
  245. return crc;
  246. }
  247. bool ds18b20_isAllZeros(const uint8_t * const scratchPad) {
  248. for (size_t i = 0; i < 9; i++) {
  249. if (scratchPad[i] != 0) {
  250. return false;
  251. }
  252. }
  253. return true;
  254. }
  255. float ds18b20_getTempC(const DeviceAddress *deviceAddress) {
  256. ScratchPad scratchPad;
  257. if (ds18b20_isConnected(deviceAddress, scratchPad)){
  258. int16_t rawTemp = calculateTemperature(deviceAddress, scratchPad);
  259. if (rawTemp <= DEVICE_DISCONNECTED_RAW)
  260. return DEVICE_DISCONNECTED_C;
  261. // C = RAW/128
  262. // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32
  263. return (float) rawTemp/128.0f;
  264. }
  265. return DEVICE_DISCONNECTED_C;
  266. }
  267. // reads scratchpad and returns fixed-point temperature, scaling factor 2^-7
  268. int16_t calculateTemperature(const DeviceAddress *deviceAddress, uint8_t* scratchPad) {
  269. int16_t fpTemperature = (((int16_t) scratchPad[TEMP_MSB]) << 11) | (((int16_t) scratchPad[TEMP_LSB]) << 3);
  270. return fpTemperature;
  271. }
  272. // Returns temperature from sensor
  273. float ds18b20_get_temp(void) {
  274. if(init==1){
  275. unsigned char check;
  276. char temp1=0, temp2=0;
  277. check=ds18b20_RST_PULSE();
  278. if(check==1)
  279. {
  280. ds18b20_send_byte(0xCC);
  281. ds18b20_send_byte(0x44);
  282. vTaskDelay(750 / portTICK_RATE_MS);
  283. check=ds18b20_RST_PULSE();
  284. ds18b20_send_byte(0xCC);
  285. ds18b20_send_byte(0xBE);
  286. temp1=ds18b20_read_byte();
  287. temp2=ds18b20_read_byte();
  288. check=ds18b20_RST_PULSE();
  289. float temp=0;
  290. temp=(float)(temp1+(temp2*256))/16;
  291. return temp;
  292. }
  293. else{return 0;}
  294. }
  295. else{return 0;}
  296. }
  297. void ds18b20_init(int GPIO) {
  298. DS_GPIO = GPIO;
  299. gpio_pad_select_gpio(DS_GPIO);
  300. init = 1;
  301. }
  302. //
  303. // You need to use this function to start a search again from the beginning.
  304. // You do not need to do it for the first search, though you could.
  305. //
  306. void reset_search() {
  307. devices=0;
  308. // reset the search state
  309. LastDiscrepancy = 0;
  310. LastDeviceFlag = false;
  311. LastFamilyDiscrepancy = 0;
  312. for (int i = 7; i >= 0; i--) {
  313. ROM_NO[i] = 0;
  314. }
  315. }
  316. // --- Replaced by the one from the Dallas Semiconductor web site ---
  317. //--------------------------------------------------------------------------
  318. // Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
  319. // search state.
  320. // Return TRUE : device found, ROM number in ROM_NO buffer
  321. // FALSE : device not found, end of search
  322. bool search(uint8_t *newAddr, bool search_mode) {
  323. uint8_t id_bit_number;
  324. uint8_t last_zero, rom_byte_number;
  325. bool search_result;
  326. uint8_t id_bit, cmp_id_bit;
  327. unsigned char rom_byte_mask, search_direction;
  328. // initialize for search
  329. id_bit_number = 1;
  330. last_zero = 0;
  331. rom_byte_number = 0;
  332. rom_byte_mask = 1;
  333. search_result = false;
  334. // if the last call was not the last one
  335. if (!LastDeviceFlag) {
  336. // 1-Wire reset
  337. if (!ds18b20_reset()) {
  338. // reset the search
  339. LastDiscrepancy = 0;
  340. LastDeviceFlag = false;
  341. LastFamilyDiscrepancy = 0;
  342. return false;
  343. }
  344. // issue the search command
  345. if (search_mode == true) {
  346. ds18b20_write_byte(0xF0); // NORMAL SEARCH
  347. } else {
  348. ds18b20_write_byte(0xEC); // CONDITIONAL SEARCH
  349. }
  350. // loop to do the search
  351. do {
  352. // read a bit and its complement
  353. id_bit = ds18b20_read();
  354. cmp_id_bit = ds18b20_read();
  355. // check for no devices on 1-wire
  356. if ((id_bit == 1) && (cmp_id_bit == 1)) {
  357. break;
  358. } else {
  359. // all devices coupled have 0 or 1
  360. if (id_bit != cmp_id_bit) {
  361. search_direction = id_bit; // bit write value for search
  362. } else {
  363. // if this discrepancy if before the Last Discrepancy
  364. // on a previous next then pick the same as last time
  365. if (id_bit_number < LastDiscrepancy) {
  366. search_direction = ((ROM_NO[rom_byte_number]
  367. & rom_byte_mask) > 0);
  368. } else {
  369. // if equal to last pick 1, if not then pick 0
  370. search_direction = (id_bit_number == LastDiscrepancy);
  371. }
  372. // if 0 was picked then record its position in LastZero
  373. if (search_direction == 0) {
  374. last_zero = id_bit_number;
  375. // check for Last discrepancy in family
  376. if (last_zero < 9)
  377. LastFamilyDiscrepancy = last_zero;
  378. }
  379. }
  380. // set or clear the bit in the ROM byte rom_byte_number
  381. // with mask rom_byte_mask
  382. if (search_direction == 1)
  383. ROM_NO[rom_byte_number] |= rom_byte_mask;
  384. else
  385. ROM_NO[rom_byte_number] &= ~rom_byte_mask;
  386. // serial number search direction write bit
  387. ds18b20_write(search_direction);
  388. // increment the byte counter id_bit_number
  389. // and shift the mask rom_byte_mask
  390. id_bit_number++;
  391. rom_byte_mask <<= 1;
  392. // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
  393. if (rom_byte_mask == 0) {
  394. rom_byte_number++;
  395. rom_byte_mask = 1;
  396. }
  397. }
  398. } while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
  399. // if the search was successful then
  400. if (!(id_bit_number < 65)) {
  401. // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
  402. LastDiscrepancy = last_zero;
  403. // check for last device
  404. if (LastDiscrepancy == 0) {
  405. LastDeviceFlag = true;
  406. }
  407. search_result = true;
  408. }
  409. }
  410. // if no device found then reset counters so next 'search' will be like a first
  411. if (!search_result || !ROM_NO[0]) {
  412. devices=0;
  413. LastDiscrepancy = 0;
  414. LastDeviceFlag = false;
  415. LastFamilyDiscrepancy = 0;
  416. search_result = false;
  417. } else {
  418. for (int i = 0; i < 8; i++){
  419. newAddr[i] = ROM_NO[i];
  420. }
  421. devices++;
  422. }
  423. return search_result;
  424. }
  425. #endif // ENABLE_DS18B20