From 6d437c8007e9c5de9341091f31341d99a84630bd Mon Sep 17 00:00:00 2001 From: Jon Trulson Date: Tue, 13 Sep 2016 11:27:27 -0600 Subject: [PATCH] ds18b20: Add a C implementation and inprove documentation This commit adds a C implementation for the DS18B20. The C++ implementation was untouched (ie: it does not wrap the C implementation). This can be done in the future if desired. In addition, add an ascii-schematic to both the .h and .hpp files to better illustrate how to wire up the DS 1-wire interface for the UART. Signed-off-by: Jon Trulson --- examples/c/CMakeLists.txt | 1 + examples/c/ds18b20.c | 81 ++++++++ src/ds18b20/CMakeLists.txt | 14 +- src/ds18b20/ds18b20.c | 396 +++++++++++++++++++++++++++++++++++++ src/ds18b20/ds18b20.h | 236 ++++++++++++++++++++++ src/ds18b20/ds18b20.hpp | 39 +++- 6 files changed, 756 insertions(+), 11 deletions(-) create mode 100644 examples/c/ds18b20.c create mode 100644 src/ds18b20/ds18b20.c create mode 100644 src/ds18b20/ds18b20.h diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index a7218844..925a364a 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -116,6 +116,7 @@ add_example (tsl2561) add_example (collision) add_example (moisture) add_example (led) +add_example (ds18b20) # Custom examples add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) diff --git a/examples/c/ds18b20.c b/examples/c/ds18b20.c new file mode 100644 index 00000000..e858b901 --- /dev/null +++ b/examples/c/ds18b20.c @@ -0,0 +1,81 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * 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 +#include + +#include "ds18b20.h" + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + + printf("Initializing...\n"); + + // Instantiate an DS18B20 instance using the uart 0 + ds18b20_context sensor = ds18b20_init(0); + + if (!sensor) + { + printf("ds18b20_init() failed.\n"); + return(1); + } + + printf("Found %d device(s)\n\n", ds18b20_devices_found(sensor)); + + // update and print available values every second + while (shouldRun) + { + // update our values for all sensors + ds18b20_update(sensor, -1); + + int i; + for (i=0; i + * Copyright (c) 2016 Intel Corporation. + * + * 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 "ds18b20.h" + +// I'd rather use MRAA_UART_OW_ROMCODE_SIZE defined in uart_ow.h, but +// this then can't be used to specify array sizes since it's a static +// const int, rather than a define. This should be fixed in MRAA (PR +// submitted 9/2016). Until then, work around it. +#if !defined(MRAA_UART_OW_ROMCODE) +# define ROMCODE_SIZE 8 +#else +# define ROMCODE_SIZE MRAA_UART_OW_ROMCODE +#endif + +// an internal struct we use to store information on the devices +// found during initialization +typedef struct _ds18b20_info_t { + uint8_t id[ROMCODE_SIZE]; // 8-byte romcode id + float temperature; + DS18B20_RESOLUTIONS_T resolution; +} ds18b20_info_t; + +// internal utility function forward to read temperature from a single +// device +static float readSingleTemp(const ds18b20_context dev, unsigned int index); + +ds18b20_context ds18b20_init(unsigned int uart) +{ + ds18b20_context dev = + (ds18b20_context)malloc(sizeof(struct _ds18b20_context)); + + if (!dev) + return NULL; + + // zero out context + memset((void *)dev, 0, sizeof(struct _ds18b20_context)); + + dev->ow = NULL; + + if (!(dev->ow = mraa_uart_ow_init(uart))) + { + printf("%s: mraa_uart_ow_init() failed.\n", __FUNCTION__); + ds18b20_close(dev); + return NULL; + } + + // iterate through the bus and build up a list of detected DS18B20 + // devices (only) + + mraa_result_t rv; + if ((rv = mraa_uart_ow_reset(dev->ow)) != MRAA_SUCCESS) + { + printf("%s: mraa_uart_ow_reset() failed, no devices detected\n", + __FUNCTION__); + ds18b20_close(dev); + return NULL; + } + + uint8_t id[ROMCODE_SIZE]; + + rv = mraa_uart_ow_rom_search(dev->ow, 1, id); + if (rv == MRAA_ERROR_UART_OW_NO_DEVICES) + { + // shouldn't happen, but.... + printf("%s: mraa_uart_ow_rom_search() failed, no devices detected\n", + __FUNCTION__); + ds18b20_close(dev); + return NULL; + } + + if (rv == MRAA_ERROR_UART_OW_DATA_ERROR) + { + printf("%s: mraa_uart_ow_rom_search() failed, Bus/Data error\n", + __FUNCTION__); + ds18b20_close(dev); + return NULL; + } + + while (rv == MRAA_SUCCESS) + { + // The first byte (id[0]]) is the device type (family) code. We + // are only interested in the family code for these devices. + + if ((uint8_t)id[0] == DS18B20_FAMILY_CODE) + { + ds18b20_info_t *dsPtr = + (ds18b20_info_t *)realloc((void *)dev->devices, + sizeof(ds18b20_info_t) * + (dev->numDevices + 1)); + + if (!dsPtr) + { + printf("%s: realloc(%d) failed\n", + __FUNCTION__, + sizeof(ds18b20_info_t) * (dev->numDevices + 1)); + ds18b20_close(dev); + return NULL; + } + + dev->devices = dsPtr; + // copy in the romcode + memcpy(dev->devices[dev->numDevices].id, id, + ROMCODE_SIZE); + // set defaults for now + dev->devices[dev->numDevices].temperature = 0.0; + dev->devices[dev->numDevices].resolution = + DS18B20_RESOLUTION_12BITS; + + dev->numDevices++; + } + + // on to the next one + rv = mraa_uart_ow_rom_search(dev->ow, 0, id); + } + + if (!dev->numDevices) + { + printf("%s: no DS18B20 devices found on bus\n", __FUNCTION__); + ds18b20_close(dev); + return NULL; + } + + // iterate through the found devices and query their resolutions + int i; + for (i=0; inumDevices; i++) + { + // read only the first 5 bytes of the scratchpad + static const int numScratch = 5; + uint8_t scratch[numScratch]; + + mraa_uart_ow_command(dev->ow, DS18B20_CMD_READ_SCRATCHPAD, + dev->devices[i].id); + + int j; + for (j=0; jow); + + // config byte, shift the resolution to bit 0 + scratch[4] >>= _DS18B20_CFG_RESOLUTION_SHIFT; + + switch (scratch[4] & _DS18B20_CFG_RESOLUTION_MASK) + { + case 0: dev->devices[i].resolution = DS18B20_RESOLUTION_9BITS; break; + case 1: dev->devices[i].resolution = DS18B20_RESOLUTION_10BITS; break; + case 2: dev->devices[i].resolution = DS18B20_RESOLUTION_11BITS; break; + case 3: dev->devices[i].resolution = DS18B20_RESOLUTION_12BITS; break; + } + + // reset the bus + mraa_uart_ow_reset(dev->ow); + } + + return dev; +} + +void ds18b20_close(ds18b20_context dev) +{ + assert(dev != NULL); + + if (dev->devices) + free(dev->devices); + if (dev->ow) + mraa_uart_ow_stop(dev->ow); + + free(dev); +} + +void ds18b20_update(const ds18b20_context dev, int index) +{ + assert(dev != NULL); + + if (index >= dev->numDevices) + { + printf("%s: device index %d out of range\n", __FUNCTION__, index); + return; + } + + // should we update all of them? + bool doAll = (index < 0) ? true : false; + + if (doAll) + { + // if we want to update all of them, we will first send the + // convert command to all of them, then wait. This will be + // faster, timey-wimey wise, then converting, sleeping, and + // reading each individual sensor. + + int i; + for (i=0; inumDevices; i++) + mraa_uart_ow_command(dev->ow, DS18B20_CMD_CONVERT, dev->devices[i].id); + } + else + mraa_uart_ow_command(dev->ow, DS18B20_CMD_CONVERT, dev->devices[index].id); + + // wait for conversion(s) to finish + usleep(750000); // 750ms max + + if (doAll) + { + int i; + for (i=0; inumDevices; i++) + dev->devices[i].temperature = readSingleTemp(dev, i); + } + else + dev->devices[index].temperature = readSingleTemp(dev, index); +} + +// utility function to read temp data from a single sensor +static float readSingleTemp(const ds18b20_context dev, unsigned int index) +{ + assert(dev != NULL); + + if (index >= dev->numDevices) + { + printf("%s: device index %d out of range\n", __FUNCTION__, index); + return 0.0; + } + + static const int numScratch = 9; + uint8_t scratch[numScratch]; + + // read the 9-byte scratchpad + mraa_uart_ow_command(dev->ow, DS18B20_CMD_READ_SCRATCHPAD, + dev->devices[index].id); + int i; + for (i=0; iow); + + // validate cksum -- if we get an error, we will warn and simply + // return the current (previously read) temperature + uint8_t crc = mraa_uart_ow_crc8(scratch, 8); + + if (crc != scratch[8]) + { + printf("%s: crc check failed for device %d, returning previously " + "measured temperature\n", __FUNCTION__, index); + return dev->devices[index].temperature; + } + + // check the sign bit(s) + bool negative = (scratch[1] & 0x80) ? true : false; + + // shift everything into position + int16_t temp = (scratch[1] << 8) | scratch[0]; + + // grab the fractional + uint8_t frac = temp & 0x0f; + + // depending on the resolution, some frac bits should be ignored, so + // we mask them off. For 12bits, all bits are valid so we leve them + // alone. + + switch (dev->devices[index].resolution) + { + case DS18B20_RESOLUTION_9BITS: frac &= 0x08; break; + case DS18B20_RESOLUTION_10BITS: frac &= 0x0c; break; + case DS18B20_RESOLUTION_11BITS: frac &= 0x0e; break; + // use all bits for 12b + case DS18B20_RESOLUTION_12BITS: break; + } + + // remove the fractional with extreme prejudice + temp >>= 4; + + // compensate for sign + if (negative) + temp -= 65536; // 2^^16 + + // convert + return ( (float)temp + ((float)frac * 0.0625) ); +} + +float ds18b20_get_temperature(const ds18b20_context dev, unsigned int index) +{ + assert(dev != NULL); + + if (index >= dev->numDevices) + { + printf("%s: device index %d out of range\n", __FUNCTION__, index); + return 0.0; + } + + return dev->devices[index].temperature; +} + +void ds18b20_set_resolution(const ds18b20_context dev, unsigned int index, + DS18B20_RESOLUTIONS_T res) +{ + assert(dev != NULL); + + if (index >= dev->numDevices) + { + printf("%s: device index %d out of range\n", __FUNCTION__, index); + return; + } + + static const int numScratch = 9; + uint8_t scratch[numScratch]; + + // read the 9-byte scratchpad + mraa_uart_ow_command(dev->ow, DS18B20_CMD_READ_SCRATCHPAD, + dev->devices[index].id); + int i; + for (i=0; iow); + + // resolution is stored in byte 4 + scratch[4] = ((scratch[4] & ~(_DS18B20_CFG_RESOLUTION_MASK << + _DS18B20_CFG_RESOLUTION_SHIFT)) + | (res << _DS18B20_CFG_RESOLUTION_SHIFT)); + + // now, write back, we only write 3 bytes (2-4), no cksum. + mraa_uart_ow_command(dev->ow, DS18B20_CMD_WRITE_SCRATCHPAD, + dev->devices[index].id); + for (i=0; i<3; i++) + mraa_uart_ow_write_byte(dev->ow, scratch[i+2]); +} + +void ds18b20_copy_scratch_pad(const ds18b20_context dev, unsigned int index) +{ + assert(dev != NULL); + + if (index >= dev->numDevices) + { + printf("%s: device index %d out of range\n", __FUNCTION__, index); + return; + } + + // issue the command + mraa_uart_ow_command(dev->ow, DS18B20_CMD_COPY_SCRATCHPAD, + dev->devices[index].id); + + sleep(1); // to be safe... +} + +void ds18b20_recallEEPROM(const ds18b20_context dev, unsigned int index) +{ + assert(dev != NULL); + + if (index >= dev->numDevices) + { + printf("%s: device index %d out of range\n", __FUNCTION__, index); + return; + } + + // issue the command + mraa_uart_ow_command(dev->ow, DS18B20_CMD_RECALL_EEPROM, + dev->devices[index].id); + + // issue read timeslots until a '1' is read back, indicating completion + while (!mraa_uart_ow_bit(dev->ow, 1)) + usleep(100); +} + +int ds18b20_devices_found(const ds18b20_context dev) +{ + assert(dev != NULL); + + return dev->numDevices; +} + +const uint8_t *ds18b20_get_id(const ds18b20_context dev, unsigned int index) +{ + assert(dev != NULL); + + if (index >= dev->numDevices) + return NULL; + + static uint8_t id[ROMCODE_SIZE]; + + memcpy(id, dev->devices[index].id, ROMCODE_SIZE); + return id; +} diff --git a/src/ds18b20/ds18b20.h b/src/ds18b20/ds18b20.h new file mode 100644 index 00000000..2908412d --- /dev/null +++ b/src/ds18b20/ds18b20.h @@ -0,0 +1,236 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * 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. + */ +#pragma once + +#include +#include +#include + +#include + +#include "upm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// The family code for these devices. We handle all of them that +// are found on the bus. +#define DS18B20_FAMILY_CODE 0x28 + + /** + * @library ds18b20 + * @sensor ds18b20 + * @comname DS18B20 1-Wire Temperature Sensor + * @type uart + * @man maxim + * @con uart + * @web https://www.sparkfun.com/products/11050 + * + * @brief DS18B20 1-Wire Temperature Sensor + * + * This driver supports, and was tested with, a DS18B20 with + * external power. + * + * Multiple DS18B20 devices can be connected to this bus. This + * module will identify all such devices connected, and allow you + * to access them using an index starting at 0. + * + * Parasitic power is not currently supported due + * to the very tight 10us limit on switching a GPIO properly to + * supply power during certain operations. For this reason, you + * should use external power for your sensors. + * + * Setting the alarm values (Tl, Th) is also not supported, since + * this is only useful when doing a 1-wire device search looking + * for devices in an alarm state, a capability not yet supported + * in MRAA. In reality, this is trivial to handle yourself in + * your application. + * + * This device requires the use of a TTL level UART (specifically + * through the uart_ow MRAA context) to provide access to a Dallas + * 1-wire bus. It is important to realize that the UART is only + * being used to provide an interface to devices on a Dallas 1-wire + * compliant bus. + * + * A circuit like the following should be used for the UART + * interface (ASCII schematic - best viewed in a fixed monospace + * font): + * + * -| + * U| (D1) + * A| TX---|<--+ + * R| | + * T| RX-------o--------o >to 1-wire data bus + * -| + * + * + * Vcc + * | + * o------------+ + * | | + * R1 | + * | o(+) + * >1-wire------o--------o[DS18B20] + * o(-) + * | + * GND + * + * D1 = 1N4148 + * R1 = 4.7K + * + * The cathode of D1 is connected to the UART TX. + * + * @snippet ds18b20.c Interesting + */ + + // forward declaration + typedef struct _ds18b20_info_t ds18b20_info_t; + + /** + * Device context + */ + typedef struct _ds18b20_context { + mraa_uart_ow_context ow; + + // number of devices found + int numDevices; + + // list of allocated ds18b20_info_t instances + ds18b20_info_t *devices; + } *ds18b20_context; + + // commands + typedef enum { + DS18B20_CMD_CONVERT = 0x44, // start a temp conversion + DS18B20_CMD_WRITE_SCRATCHPAD = 0x4e, + DS18B20_CMD_READ_SCRATCHPAD = 0xbe, + DS18B20_CMD_COPY_SCRATCHPAD = 0x48, // copy scratchpad to EEPROM + DS18B20_CMD_RECALL_EEPROM = 0xb8, // copy EEPROM to scratchpad + DS18B20_CMD_READ_POWER_SUPPLY = 0xb4 // parasitically powered? + } DS18B20_CMD_T; + + // config register (scratchpad[4]) + typedef enum { + DS18B20_CFG_RESOLUTION_R0 = 0x20, + DS18B20_CFG_RESOLUTION_R1 = 0x40, + _DS18B20_CFG_RESOLUTION_MASK = 3, + _DS18B20_CFG_RESOLUTION_SHIFT = 5 + + // all other bits reserved and non-writable + } DS18B20_CFG_BITS_T; + + typedef enum { + DS18B20_RESOLUTION_9BITS = 0, // 93.75ms (tconv/8) + DS18B20_RESOLUTION_10BITS = 1, // 187.5 (tconv/4) + DS18B20_RESOLUTION_11BITS = 2, // 375ms (tconv/2) + DS18B20_RESOLUTION_12BITS = 3 // 750ms (tconv) + } DS18B20_RESOLUTIONS_T; + + /** + * This function will initilaize and search the 1-wire bus and store + * information on each DS18B20 device detected on the bus. If no + * devices are found, NULL is returned. Once this function + * completes successfully, you can use ds18b20_devices_found() to + * determine how many devices were detected. + * + * @return device context, or NULL on error. + */ + ds18b20_context ds18b20_init(unsigned int uart); + + /** + * Close the device and deallocate all resources. + */ + void ds18b20_close(ds18b20_context dev); + + /** + * Update our stored temperature for a device. This method must + * be called prior to ds18b20_get_temperature(). + * + * @param index The device index to access (starts at 0). Specify + * -1 to query all detected devices. Default: -1 + */ + void ds18b20_update(const ds18b20_context dev, int index); + + /** + * Get the current temperature. ds18b20_update() must have been + * called prior to calling this method. + * + * @param index The device index to access (starts at 0). + * @return The last temperature reading in Celsius. + */ + float ds18b20_get_temperature(const ds18b20_context dev, + unsigned int index); + + /** + * Set the device resolution for a device. These devices support + * 9, 10, 11, and 12 bits of resolution, with the default from the + * factory at 12 bits. + * + * @param index The device index to access (starts at 0). + * @param res One of the DS18B20_RESOLUTIONS_T values + */ + void ds18b20_set_resolution(const ds18b20_context dev, unsigned int index, + DS18B20_RESOLUTIONS_T res); + + /** + * Copy the device's scratchpad memory to the EEPROM. This + * includes the configuration byte (resolution). + * + * @param index The device index to access (starts at 0). + */ + void ds18b20_copy_scratchpad(const ds18b20_context dev, unsigned int index); + + /** + * Copy the device's EEPROM memory to the scratchpad. This method + * will return when the copy completes. This operation is + * performed by the device automatically on power up, so it is + * rarely needed. + * + * @param index The device index to access (starts at 0). + */ + void ds18b20_recall_eeprom(const ds18b20_context dev, unsigned int index); + + /** + * This method will return the number of DS18B20 devices that were + * found on the bus by ds18b20_init(). + * + * @return number of DS18B20's that were found on the bus + */ + int ds18b20_devices_found(const ds18b20_context dev); + + /** + * Return an 8 byte string representing the unique device ID (1-wire + * romcode) for a given device index. The pointer returned is + * statically allocated and will be overwritten on each call. + * + * @param index The device index to access (starts at 0). + * @return pointer to 8 byte DS18B20_ROMCODE_T representing the 1-wire + * device's unique romcode, or NULL on error. + */ + const uint8_t *get_id(const ds18b20_context dev, unsigned int index); + +#ifdef __cplusplus +} +#endif diff --git a/src/ds18b20/ds18b20.hpp b/src/ds18b20/ds18b20.hpp index e22ca69c..978016c3 100644 --- a/src/ds18b20/ds18b20.hpp +++ b/src/ds18b20/ds18b20.hpp @@ -72,12 +72,39 @@ namespace upm { * in MRAA. In reality, this is trivial to handle yourself in * your application. * - * This device requires the use of a UART to provide access to a - * Dallas 1-wire bus, via a new facility supported by MRAA (once - * the relevant PR is accepted), using the UartOW access class. - * It is important to realize that the UART is only being used to - * access and control a Dallas 1-wire compliant bus, it is not - * actually a UART device. + * This device requires the use of a TTL level UART (specifically + * through the UartOW MRAA context class) to provide access to a + * Dallas 1-wire bus. It is important to realize that the UART is + * only being used to provide an interface to devices on a Dallas + * 1-wire compliant bus. + * + * A circuit like the following should be used for the UART + * interface (ASCII schematic - best viewed in a fixed monospace + * font): + * + * -| + * U| (D1) + * A| TX---|<--+ + * R| | + * T| RX-------o--------o >to 1-wire data bus + * -| + * + * + * Vcc + * | + * o------------+ + * | | + * R1 | + * | o(+) + * >1-wire------o--------o[DS18B20] + * o(-) + * | + * GND + * + * D1 = 1N4148 + * R1 = 4.7K + * + * The cathode of D1 is connected to the UART TX. * * @snippet ds18b20.cxx Interesting */