├── LICENSE ├── README.md ├── component.mk ├── ds18b20.c ├── ds18b20.h └── main.c /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Filip Grzywok @feelfreelinux 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple library for single DS18B20 on ESP32 2 | # Usage 3 | Put ds18b20.c and ds18b20.h in the same directory as your project code.
4 | Include library with #include ds18b20.h
5 | To initialize library, call ds18b20_init(GPIO);
6 | To get temperature(in Celcius), call ds18b20_get_temp();
7 | For example, see this code. 8 | -------------------------------------------------------------------------------- /component.mk: -------------------------------------------------------------------------------- 1 | # Make file 2 | include $(IDF_PATH)/make/component_common.mk 3 | -------------------------------------------------------------------------------- /ds18b20.c: -------------------------------------------------------------------------------- 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 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | #include "freertos/FreeRTOS.h" 16 | #include "freertos/task.h" 17 | #include "driver/gpio.h" 18 | #include "esp32/rom/ets_sys.h" 19 | #include "ds18b20.h" 20 | 21 | // OneWire commands 22 | #define GETTEMP 0x44 // Tells device to take a temperature reading and put it on the scratchpad 23 | #define SKIPROM 0xCC // Command to address all devices on the bus 24 | #define SELECTDEVICE 0x55 // Command to address all devices on the bus 25 | #define COPYSCRATCH 0x48 // Copy scratchpad to EEPROM 26 | #define READSCRATCH 0xBE // Read from scratchpad 27 | #define WRITESCRATCH 0x4E // Write to scratchpad 28 | #define RECALLSCRATCH 0xB8 // Recall from EEPROM to scratchpad 29 | #define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power 30 | #define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition 31 | // Scratchpad locations 32 | #define TEMP_LSB 0 33 | #define TEMP_MSB 1 34 | #define HIGH_ALARM_TEMP 2 35 | #define LOW_ALARM_TEMP 3 36 | #define CONFIGURATION 4 37 | #define INTERNAL_BYTE 5 38 | #define COUNT_REMAIN 6 39 | #define COUNT_PER_C 7 40 | #define SCRATCHPAD_CRC 8 41 | // DSROM FIELDS 42 | #define DSROM_FAMILY 0 43 | #define DSROM_CRC 7 44 | // Device resolution 45 | #define TEMP_9_BIT 0x1F // 9 bit 46 | #define TEMP_10_BIT 0x3F // 10 bit 47 | #define TEMP_11_BIT 0x5F // 11 bit 48 | #define TEMP_12_BIT 0x7F // 12 bit 49 | 50 | uint8_t DS_GPIO; 51 | uint8_t init=0; 52 | uint8_t bitResolution=12; 53 | uint8_t devices=0; 54 | 55 | DeviceAddress ROM_NO; 56 | uint8_t LastDiscrepancy; 57 | uint8_t LastFamilyDiscrepancy; 58 | bool LastDeviceFlag; 59 | 60 | /// Sends one bit to bus 61 | void ds18b20_write(char bit){ 62 | if (bit & 1) { 63 | gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT); 64 | noInterrupts(); 65 | gpio_set_level(DS_GPIO,0); 66 | ets_delay_us(6); 67 | gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT); // release bus 68 | ets_delay_us(64); 69 | interrupts(); 70 | } else { 71 | gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT); 72 | noInterrupts(); 73 | gpio_set_level(DS_GPIO,0); 74 | ets_delay_us(60); 75 | gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT); // release bus 76 | ets_delay_us(10); 77 | interrupts(); 78 | } 79 | } 80 | 81 | // Reads one bit from bus 82 | unsigned char ds18b20_read(void){ 83 | unsigned char value = 0; 84 | gpio_set_direction(DS_GPIO, GPIO_MODE_OUTPUT); 85 | noInterrupts(); 86 | gpio_set_level(DS_GPIO, 0); 87 | ets_delay_us(6); 88 | gpio_set_direction(DS_GPIO, GPIO_MODE_INPUT); 89 | ets_delay_us(9); 90 | value = gpio_get_level(DS_GPIO); 91 | ets_delay_us(55); 92 | interrupts(); 93 | return (value); 94 | } 95 | // Sends one byte to bus 96 | void ds18b20_write_byte(char data){ 97 | unsigned char i; 98 | unsigned char x; 99 | for(i=0;i<8;i++){ 100 | x = data>>i; 101 | x &= 0x01; 102 | ds18b20_write(x); 103 | } 104 | ets_delay_us(100); 105 | } 106 | // Reads one byte from bus 107 | unsigned char ds18b20_read_byte(void){ 108 | unsigned char i; 109 | unsigned char data = 0; 110 | for (i=0;i<8;i++) 111 | { 112 | if(ds18b20_read()) data|=0x01<> 4) & 0x0f)); 246 | } 247 | return crc; 248 | } 249 | 250 | bool ds18b20_isAllZeros(const uint8_t * const scratchPad) { 251 | for (size_t i = 0; i < 9; i++) { 252 | if (scratchPad[i] != 0) { 253 | return false; 254 | } 255 | } 256 | return true; 257 | } 258 | 259 | float ds18b20_getTempF(const DeviceAddress *deviceAddress) { 260 | ScratchPad scratchPad; 261 | if (ds18b20_isConnected(deviceAddress, scratchPad)){ 262 | int16_t rawTemp = calculateTemperature(deviceAddress, scratchPad); 263 | if (rawTemp <= DEVICE_DISCONNECTED_RAW) 264 | return DEVICE_DISCONNECTED_F; 265 | // C = RAW/128 266 | // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32 267 | return ((float) rawTemp * 0.0140625f) + 32.0f; 268 | } 269 | return DEVICE_DISCONNECTED_F; 270 | } 271 | 272 | float ds18b20_getTempC(const DeviceAddress *deviceAddress) { 273 | ScratchPad scratchPad; 274 | if (ds18b20_isConnected(deviceAddress, scratchPad)){ 275 | int16_t rawTemp = calculateTemperature(deviceAddress, scratchPad); 276 | if (rawTemp <= DEVICE_DISCONNECTED_RAW) 277 | return DEVICE_DISCONNECTED_F; 278 | // C = RAW/128 279 | // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32 280 | return (float) rawTemp/128.0f; 281 | } 282 | return DEVICE_DISCONNECTED_F; 283 | } 284 | 285 | // reads scratchpad and returns fixed-point temperature, scaling factor 2^-7 286 | int16_t calculateTemperature(const DeviceAddress *deviceAddress, uint8_t* scratchPad) { 287 | int16_t fpTemperature = (((int16_t) scratchPad[TEMP_MSB]) << 11) | (((int16_t) scratchPad[TEMP_LSB]) << 3); 288 | return fpTemperature; 289 | } 290 | 291 | // Returns temperature from sensor 292 | float ds18b20_get_temp(void) { 293 | if(init==1){ 294 | unsigned char check; 295 | char temp1=0, temp2=0; 296 | check=ds18b20_RST_PULSE(); 297 | if(check==1) 298 | { 299 | ds18b20_send_byte(0xCC); 300 | ds18b20_send_byte(0x44); 301 | vTaskDelay(750 / portTICK_RATE_MS); 302 | check=ds18b20_RST_PULSE(); 303 | ds18b20_send_byte(0xCC); 304 | ds18b20_send_byte(0xBE); 305 | temp1=ds18b20_read_byte(); 306 | temp2=ds18b20_read_byte(); 307 | check=ds18b20_RST_PULSE(); 308 | float temp=0; 309 | temp=(float)(temp1+(temp2*256))/16; 310 | return temp; 311 | } 312 | else{return 0;} 313 | 314 | } 315 | else{return 0;} 316 | } 317 | 318 | void ds18b20_init(int GPIO) { 319 | DS_GPIO = GPIO; 320 | gpio_pad_select_gpio(DS_GPIO); 321 | init = 1; 322 | } 323 | 324 | // 325 | // You need to use this function to start a search again from the beginning. 326 | // You do not need to do it for the first search, though you could. 327 | // 328 | void reset_search() { 329 | devices=0; 330 | // reset the search state 331 | LastDiscrepancy = 0; 332 | LastDeviceFlag = false; 333 | LastFamilyDiscrepancy = 0; 334 | for (int i = 7; i >= 0; i--) { 335 | ROM_NO[i] = 0; 336 | } 337 | } 338 | // --- Replaced by the one from the Dallas Semiconductor web site --- 339 | //-------------------------------------------------------------------------- 340 | // Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing 341 | // search state. 342 | // Return TRUE : device found, ROM number in ROM_NO buffer 343 | // FALSE : device not found, end of search 344 | 345 | bool search(uint8_t *newAddr, bool search_mode) { 346 | uint8_t id_bit_number; 347 | uint8_t last_zero, rom_byte_number; 348 | bool search_result; 349 | uint8_t id_bit, cmp_id_bit; 350 | 351 | unsigned char rom_byte_mask, search_direction; 352 | 353 | // initialize for search 354 | id_bit_number = 1; 355 | last_zero = 0; 356 | rom_byte_number = 0; 357 | rom_byte_mask = 1; 358 | search_result = false; 359 | 360 | // if the last call was not the last one 361 | if (!LastDeviceFlag) { 362 | // 1-Wire reset 363 | if (!ds18b20_reset()) { 364 | // reset the search 365 | LastDiscrepancy = 0; 366 | LastDeviceFlag = false; 367 | LastFamilyDiscrepancy = 0; 368 | return false; 369 | } 370 | 371 | // issue the search command 372 | if (search_mode == true) { 373 | ds18b20_write_byte(0xF0); // NORMAL SEARCH 374 | } else { 375 | ds18b20_write_byte(0xEC); // CONDITIONAL SEARCH 376 | } 377 | 378 | // loop to do the search 379 | do { 380 | // read a bit and its complement 381 | id_bit = ds18b20_read(); 382 | cmp_id_bit = ds18b20_read(); 383 | 384 | // check for no devices on 1-wire 385 | if ((id_bit == 1) && (cmp_id_bit == 1)) { 386 | break; 387 | } else { 388 | // all devices coupled have 0 or 1 389 | if (id_bit != cmp_id_bit) { 390 | search_direction = id_bit; // bit write value for search 391 | } else { 392 | // if this discrepancy if before the Last Discrepancy 393 | // on a previous next then pick the same as last time 394 | if (id_bit_number < LastDiscrepancy) { 395 | search_direction = ((ROM_NO[rom_byte_number] 396 | & rom_byte_mask) > 0); 397 | } else { 398 | // if equal to last pick 1, if not then pick 0 399 | search_direction = (id_bit_number == LastDiscrepancy); 400 | } 401 | // if 0 was picked then record its position in LastZero 402 | if (search_direction == 0) { 403 | last_zero = id_bit_number; 404 | 405 | // check for Last discrepancy in family 406 | if (last_zero < 9) 407 | LastFamilyDiscrepancy = last_zero; 408 | } 409 | } 410 | 411 | // set or clear the bit in the ROM byte rom_byte_number 412 | // with mask rom_byte_mask 413 | if (search_direction == 1) 414 | ROM_NO[rom_byte_number] |= rom_byte_mask; 415 | else 416 | ROM_NO[rom_byte_number] &= ~rom_byte_mask; 417 | 418 | // serial number search direction write bit 419 | ds18b20_write(search_direction); 420 | 421 | // increment the byte counter id_bit_number 422 | // and shift the mask rom_byte_mask 423 | id_bit_number++; 424 | rom_byte_mask <<= 1; 425 | 426 | // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask 427 | if (rom_byte_mask == 0) { 428 | rom_byte_number++; 429 | rom_byte_mask = 1; 430 | } 431 | } 432 | } while (rom_byte_number < 8); // loop until through all ROM bytes 0-7 433 | 434 | // if the search was successful then 435 | if (!(id_bit_number < 65)) { 436 | // search successful so set LastDiscrepancy,LastDeviceFlag,search_result 437 | LastDiscrepancy = last_zero; 438 | 439 | // check for last device 440 | if (LastDiscrepancy == 0) { 441 | LastDeviceFlag = true; 442 | } 443 | search_result = true; 444 | } 445 | } 446 | 447 | // if no device found then reset counters so next 'search' will be like a first 448 | if (!search_result || !ROM_NO[0]) { 449 | devices=0; 450 | LastDiscrepancy = 0; 451 | LastDeviceFlag = false; 452 | LastFamilyDiscrepancy = 0; 453 | search_result = false; 454 | } else { 455 | for (int i = 0; i < 8; i++){ 456 | newAddr[i] = ROM_NO[i]; 457 | } 458 | devices++; 459 | } 460 | return search_result; 461 | } 462 | -------------------------------------------------------------------------------- /ds18b20.h: -------------------------------------------------------------------------------- 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 | 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | #include 16 | 17 | #ifndef DS18B20_H_ 18 | #define DS18B20_H_ 19 | 20 | #define noInterrupts() portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;taskENTER_CRITICAL(&mux) 21 | #define interrupts() taskEXIT_CRITICAL(&mux) 22 | 23 | #define DEVICE_DISCONNECTED_C -127 24 | #define DEVICE_DISCONNECTED_F -196.6 25 | #define DEVICE_DISCONNECTED_RAW -7040 26 | #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) 27 | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) 28 | 29 | typedef uint8_t DeviceAddress[8]; 30 | typedef uint8_t ScratchPad[9]; 31 | 32 | // Dow-CRC using polynomial X^8 + X^5 + X^4 + X^0 33 | // Tiny 2x16 entry CRC table created by Arjen Lentz 34 | // See http://lentz.com.au/blog/calculating-crc-with-a-tiny-32-entry-lookup-table 35 | static const uint8_t dscrc2x16_table[] = { 36 | 0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83, 37 | 0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41, 38 | 0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8, 39 | 0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74 40 | }; 41 | 42 | /* *INDENT-OFF* */ 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | /* *INDENT-ON* */ 47 | 48 | void ds18b20_init(int GPIO); 49 | 50 | #define ds18b20_send ds18b20_write 51 | #define ds18b20_send_byte ds18b20_write_byte 52 | #define ds18b20_RST_PULSE ds18b20_reset 53 | 54 | void ds18b20_write(char bit); 55 | unsigned char ds18b20_read(void); 56 | void ds18b20_write_byte(char data); 57 | unsigned char ds18b20_read_byte(void); 58 | unsigned char ds18b20_reset(void); 59 | 60 | bool ds18b20_setResolution(const DeviceAddress tempSensorAddresses[], int numAddresses, uint8_t newResolution); 61 | bool ds18b20_isConnected(const DeviceAddress *deviceAddress, uint8_t *scratchPad); 62 | void ds18b20_writeScratchPad(const DeviceAddress *deviceAddress, const uint8_t *scratchPad); 63 | bool ds18b20_readScratchPad(const DeviceAddress *deviceAddress, uint8_t *scratchPad); 64 | void ds18b20_select(const DeviceAddress *address); 65 | uint8_t ds18b20_crc8(const uint8_t *addr, uint8_t len); 66 | bool ds18b20_isAllZeros(const uint8_t * const scratchPad); 67 | bool isConversionComplete(); 68 | uint16_t millisToWaitForConversion(); 69 | 70 | void ds18b20_requestTemperatures(); 71 | float ds18b20_getTempF(const DeviceAddress *deviceAddress); 72 | float ds18b20_getTempC(const DeviceAddress *deviceAddress); 73 | int16_t calculateTemperature(const DeviceAddress *deviceAddress, uint8_t* scratchPad); 74 | float ds18b20_get_temp(void); 75 | 76 | void reset_search(); 77 | bool search(uint8_t *newAddr, bool search_mode); 78 | 79 | /* *INDENT-OFF* */ 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | /* *INDENT-ON* */ 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ds18b20.h" 3 | #include "freertos/FreeRTOS.h" 4 | #include "freertos/task.h" 5 | #include "driver/gpio.h" 6 | 7 | // Temp Sensors are on GPIO26 8 | #define TEMP_BUS 26 9 | #define LED 2 10 | #define HIGH 1 11 | #define LOW 0 12 | #define digitalWrite gpio_set_level 13 | 14 | DeviceAddress tempSensors[2]; 15 | 16 | void getTempAddresses(DeviceAddress *tempSensorAddresses) { 17 | unsigned int numberFound = 0; 18 | reset_search(); 19 | // search for 2 addresses on the oneWire protocol 20 | while (search(tempSensorAddresses[numberFound],true)) { 21 | numberFound++; 22 | if (numberFound == 2) break; 23 | } 24 | // if 2 addresses aren't found then flash the LED rapidly 25 | while (numberFound != 2) { 26 | numberFound = 0; 27 | digitalWrite(LED, HIGH); 28 | vTaskDelay(100 / portTICK_PERIOD_MS); 29 | digitalWrite(LED, LOW); 30 | vTaskDelay(100 / portTICK_PERIOD_MS); 31 | // search in the loop for the temp sensors as they may hook them up 32 | reset_search(); 33 | while (search(tempSensorAddresses[numberFound],true)) { 34 | numberFound++; 35 | if (numberFound == 2) break; 36 | } 37 | } 38 | return; 39 | } 40 | 41 | void app_main(void){ 42 | gpio_reset_pin(LED); 43 | /* Set the GPIO as a push/pull output */ 44 | gpio_set_direction(LED, GPIO_MODE_OUTPUT); 45 | 46 | ds18b20_init(TEMP_BUS); 47 | getTempAddresses(tempSensors); 48 | ds18b20_setResolution(tempSensors,2,10); 49 | 50 | printf("Address 0: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n", tempSensors[0][0],tempSensors[0][1],tempSensors[0][2],tempSensors[0][3],tempSensors[0][4],tempSensors[0][5],tempSensors[0][6],tempSensors[0][7]); 51 | printf("Address 1: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n", tempSensors[1][0],tempSensors[1][1],tempSensors[1][2],tempSensors[1][3],tempSensors[1][4],tempSensors[1][5],tempSensors[1][6],tempSensors[1][7]); 52 | 53 | while (1) { 54 | ds18b20_requestTemperatures(); 55 | float temp1 = ds18b20_getTempF((DeviceAddress *)tempSensors[0]); 56 | float temp2 = ds18b20_getTempF((DeviceAddress *)tempSensors[1]); 57 | float temp3 = ds18b20_getTempC((DeviceAddress *)tempSensors[0]); 58 | float temp4 = ds18b20_getTempC((DeviceAddress *)tempSensors[1]); 59 | printf("Temperatures: %0.1fF %0.1fF\n", temp1,temp2); 60 | printf("Temperatures: %0.1fC %0.1fC\n", temp3,temp4); 61 | 62 | float cTemp = ds18b20_get_temp(); 63 | printf("Temperature: %0.1fC\n", cTemp); 64 | vTaskDelay(1000 / portTICK_PERIOD_MS); 65 | } 66 | } 67 | --------------------------------------------------------------------------------