diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3fab7aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build/ +sdkconfig +sdkconfig.old + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..76da102 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "components/esp32-owb"] + path = components/esp32-owb + url = https://github.com/DavidAntliff/esp32-owb +[submodule "components/esp32-ds18b20"] + path = components/esp32-ds18b20 + url = https://github.com/DavidAntliff/esp32-ds18b20 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..441ee32 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 David Antliff + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3b60079 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := esp32-ds18b20-example + +include $(IDF_PATH)/make/project.mk + diff --git a/README.md b/README.md new file mode 100644 index 0000000..7365920 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# ESP32-DS18B20 + +## Introduction + +This is an example application for the Maxim Integrated DS18B20 Programmable Resolution 1-Wire Digital Thermometer device. + +It supports a single or multiple devices on the same 1-Wire bus. + +It is written and tested for the [ESP-IDF](https://github.com/espressif/esp-idf) environment, using the xtensa-esp32-elf toolchain (gcc version 5.2.0). + +Ensure that submodules are cloned: + + $ git clone --recursive https://github.com/DavidAntliff/esp32-ds18b20-example.git + +Build the application with: + + $ cd esp32-ds18b20-example.git + $ make menuconfig # set your serial configuration and the 1-Wire GPIO - see below + $ make flash monitor + +The program should detect your connected devices and periodically obtain temperature readings from them, displaying them on the console. + +## Hardware + +To run this example, connect one or more DS18B20 devices to a single GPIO on the ESP32. Use the recommended pull-up resistor of 4.k kOhms, connected to the 3.3V supply. + +`make menuconfig` can be used to set the 1-Wire GPIO. + +## Features + +This example provides: + + * External power supply mode. + * Static (stack-based) or dynamic (malloc-based) memory model examples. + * No global variables. + * Device search. + * Addressing optimisation for a single (solo) device on a bus. + * CRC checks on ROM code and temperature data. + * Programmable temperature measurement resolution (9, 10, 11 or 12-bit resolution). + * Temperature conversion and retrieval. + * Simultaneous conversion across multiple devices. + +## Source Code + +The source is available from [GitHub](https://www.github.com/DavidAntliff/esp32-ds18b20-example). + +## License + +The code in this project is licensed under the MIT license - see LICENSE for details. + +## Links + + * [DS18B20 Datasheet](http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf) + * [Espressif IoT Development Framework for ESP32](https://github.com/espressif/esp-idf) + +## Acknowledgements + +"1-Wire" is a registered trademark of Maxim Integrated. diff --git a/components/esp32-ds18b20 b/components/esp32-ds18b20 new file mode 160000 index 0000000..0970db5 --- /dev/null +++ b/components/esp32-ds18b20 @@ -0,0 +1 @@ +Subproject commit 0970db56b1008d46f54fb5fb8a670161010448c4 diff --git a/components/esp32-owb b/components/esp32-owb new file mode 160000 index 0000000..57bcaf0 --- /dev/null +++ b/components/esp32-owb @@ -0,0 +1 @@ +Subproject commit 57bcaf06f500953e3acb97d23c6a6a98712824ab diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild new file mode 100644 index 0000000..27da83c --- /dev/null +++ b/main/Kconfig.projbuild @@ -0,0 +1,14 @@ +menu "esp32-ds18b20-example Configuration" + +config ONE_WIRE_GPIO + int "OneWire GPIO number" + range 0 34 + default 5 + help + GPIO number (IOxx) to access One Wire Bus. + + Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used. + + GPIOs 35-39 are input-only so cannot be used to drive the One Wire Bus. + +endmenu diff --git a/main/app_main.c b/main/app_main.c new file mode 100644 index 0000000..95224bc --- /dev/null +++ b/main/app_main.c @@ -0,0 +1,179 @@ +/* + * MIT License + * + * Copyright (c) 2017 David Antliff + * + * 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: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. + */ + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "esp_log.h" + +// Uncomment to enable static (stack-based) allocation of instances and avoid malloc/free. +//#define USE_STATIC 1 + +#include "owb.h" +#include "ds18b20.h" + + +#define GPIO_DS18B20_0 (GPIO_NUM_5) +#define MAX_DEVICES (8) +#define DS18B20_RESOLUTION (DS18B20_RESOLUTION_11_BIT) + +void app_main() +{ + esp_log_level_set("*", ESP_LOG_INFO); + + // Create a 1-Wire bus +#ifdef USE_STATIC + OneWireBus owb_static; // static allocation + OneWireBus * owb = &owb_static; +#else + OneWireBus * owb = owb_malloc(); // heap allocation +#endif + + owb_init(owb, GPIO_DS18B20_0); + owb_use_crc(owb, true); // enable CRC check for ROM code + + // find all connected devices + printf("Find devices:\n"); + OneWireBus_ROMCode device_rom_codes[MAX_DEVICES] = {0}; + int num_devices = 0; + OneWireBus_SearchState search_state = {0}; + bool found = owb_search_first(owb, &search_state); + while (found) + { + char rom_code_s[17]; + owb_string_from_rom_code(search_state.rom_code, rom_code_s, sizeof(rom_code_s)); + printf(" %d : %s\n", num_devices, rom_code_s); + device_rom_codes[num_devices] = search_state.rom_code; + ++num_devices; + found = owb_search_next(owb, &search_state); + } + + //uint64_t rom_code = 0x0001162e87ccee28; // pink + //uint64_t rom_code = 0xf402162c6149ee28; // green + //uint64_t rom_code = 0x1502162ca5b2ee28; // orange + //uint64_t rom_code = owb_read_rom(owb); + + // known ROM codes (LSB first): + OneWireBus_ROMCode known_device = { + .fields.family = { 0x28 }, + .fields.serial_number = { 0xee, 0xcc, 0x87, 0x2e, 0x16, 0x01 }, + .fields.crc = { 0x00 }, + }; + char rom_code_s[17]; + owb_string_from_rom_code(known_device, rom_code_s, sizeof(rom_code_s)); + printf("Device %s is %s\n", rom_code_s, owb_verify_rom(owb, known_device) ? "present" : "not present"); + + // Create a DS18B20 device on the 1-Wire bus +#ifdef USE_STATIC + DS18B20_Info devices_static[MAX_DEVICES] = {0}; + DS18B20_Info * devices[MAX_DEVICES] = {0}; + for (int i = 0; i < MAX_DEVICES; ++i) + { + devices[i] = &(devices_static[i]); + } +#else + DS18B20_Info * devices[MAX_DEVICES] = {0}; +#endif + + for (int i = 0; i < num_devices; ++i) + { +#ifdef USE_STATIC + DS18B20_Info * ds18b20_info = devices[i]; +#else + DS18B20_Info * ds18b20_info = ds18b20_malloc(); // heap allocation + devices[i] = ds18b20_info; +#endif + if (num_devices == 1) + { + printf("Single device optimisations enabled\n"); + ds18b20_init_solo(ds18b20_info, owb); // only one device on bus + } + else + { + ds18b20_init(ds18b20_info, owb, device_rom_codes[i]); // associate with bus and device + } + ds18b20_use_crc(ds18b20_info, true); // enable CRC check for temperature readings + ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION); + } + +// // read temperatures from all sensors sequentially +// while (1) +// { +// printf("\nTemperature readings (degrees C):\n"); +// for (int i = 0; i < num_devices; ++i) +// { +// float temp = ds18b20_get_temp(devices[i]); +// printf(" %d: %.3f\n", i, temp); +// } +// vTaskDelay(1000 / portTICK_PERIOD_MS); +// } + + // read temperatures more efficiently by starting conversions on all devices at the same time + if (num_devices > 0) + { + while (1) + { + TickType_t start_ticks = xTaskGetTickCount(); + + ds18b20_convert_all(owb); + + // in this application all devices use the same resolution, + // so use the first device to determine the delay + ds18b20_wait_for_conversion(devices[0]); + + // read the results immediately after conversion otherwise it may fail + // (using printf before reading may take too long) + float temps[MAX_DEVICES] = { 0 }; + for (int i = 0; i < num_devices; ++i) + { + temps[i] = ds18b20_read_temp(devices[i]); + } + + // print results in a separate loop, after all have been read + printf("\nTemperature readings (degrees C):\n"); + for (int i = 0; i < num_devices; ++i) + { + printf(" %d: %.1f\n", i, temps[i]); + } + + // make up delay to approximately 1 second per measurement + vTaskDelay(1000 / portTICK_PERIOD_MS - (xTaskGetTickCount() - start_ticks)); + } + } + +#ifndef USE_STATIC + // clean up dynamically allocated data + for (int i = 0; i < num_devices; ++i) + { + ds18b20_free(&devices[i]); + } + owb_free(&owb); +#endif + + printf("Restarting now.\n"); + fflush(stdout); + esp_restart(); +} diff --git a/main/component.mk b/main/component.mk new file mode 100644 index 0000000..0b9d758 --- /dev/null +++ b/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +