diff --git a/main/ds18b20.c b/main/ds18b20.c index f4b118e..4744dc4 100644 --- a/main/ds18b20.c +++ b/main/ds18b20.c @@ -76,6 +76,29 @@ static bool _is_init(const DS18B20_Info * ds18b20_info) return ok; } +static bool _check_resolution(DS18B20_RESOLUTION resolution) +{ + return (resolution >= DS18B20_RESOLUTION_9_BIT) && (resolution <= DS18B20_RESOLUTION_12_BIT); +} + +static float _decode_temp(uint8_t lsb, uint8_t msb, DS18B20_RESOLUTION resolution) +{ + float result = 0.0f; + if (_check_resolution(resolution)) + { + // masks to remove undefined bits from result + static const uint8_t lsb_mask[4] = { ~0x03, ~0x02, ~0x01, ~0x00 }; + uint8_t lsb_masked = lsb_mask[resolution - DS18B20_RESOLUTION_9_BIT] & lsb; + int16_t raw = (msb << 8) | lsb_masked; + result = raw / 16.0f; + } + else + { + ESP_LOGE(TAG, "Unsupported resolution %d", resolution); + } + return result; +} + DS18B20_Info * ds18b20_malloc(void) { DS18B20_Info * ds18b20_info = malloc(sizeof(*ds18b20_info)); @@ -109,6 +132,7 @@ void ds18b20_init(DS18B20_Info * ds18b20_info, OneWireBus * bus, OneWireBus_ROMC ds18b20_info->bus = bus; ds18b20_info->rom_code = rom_code; ds18b20_info->use_crc = false; + ds18b20_info->resolution = DS18B20_RESOLUTION_12_BIT; ds18b20_info->init = true; } else @@ -149,7 +173,7 @@ float ds18b20_get_temp(DS18B20_Info * ds18b20_info) uint8_t temp_LSB = 0; uint8_t temp_MSB = 0; - if (ds18b20_info->use_crc) + if (!ds18b20_info->use_crc) { // Without CRC: temp_LSB = owb_read_byte(bus); @@ -173,7 +197,7 @@ float ds18b20_get_temp(DS18B20_Info * ds18b20_info) } ESP_LOGD(TAG, "temp_LSB 0x%02x, temp_MSB 0x%02x", temp_LSB, temp_MSB); - temp = (float)(((temp_MSB << 8) + temp_LSB) >> 4); + temp = _decode_temp(temp_LSB, temp_MSB, ds18b20_info->resolution); } else { diff --git a/main/ds18b20.h b/main/ds18b20.h index 40dcc85..cbb0e41 100644 --- a/main/ds18b20.h +++ b/main/ds18b20.h @@ -40,16 +40,28 @@ extern "C" { #endif +/** + * @brief Symbols for the supported temperature resolution of the device. + */ +typedef enum +{ + DS18B20_RESOLUTION_9_BIT = 9, ///< 9-bit resolution, LSB bits 2,1,0 undefined + DS18B20_RESOLUTION_10_BIT = 10, ///< 10-bit resolution, LSB bits 1,0 undefined + DS18B20_RESOLUTION_11_BIT = 11, ///< 11-bit resolution, LSB bit 0 undefined + DS18B20_RESOLUTION_12_BIT = 12, ///< 12-bit resolution (default) +} DS18B20_RESOLUTION; + /** * @brief Structure containing information related to a single DS18B20 device connected * via a 1-Wire bus. */ typedef struct { - bool init; ///< True if struct has been initialised, otherwise false. - bool use_crc; ///< True if CRC checks are to be used when retrieving information from a device on the bus - OneWireBus * bus; ///< Pointer to 1-Wire bus information relevant to this device. - OneWireBus_ROMCode rom_code; ///< The ROM code used to address this device on the bus. + bool init; ///< True if struct has been initialised, otherwise false + bool use_crc; ///< True if CRC checks are to be used when retrieving information from a device on the bus + OneWireBus * bus; ///< Pointer to 1-Wire bus information relevant to this device + OneWireBus_ROMCode rom_code; ///< The ROM code used to address this device on the bus + DS18B20_RESOLUTION resolution; ///< Temperature measurement resolution per reading } DS18B20_Info; /** diff --git a/main/ds18b20_main.c b/main/ds18b20_main.c index 9d9e2d9..0604663 100644 --- a/main/ds18b20_main.c +++ b/main/ds18b20_main.c @@ -42,7 +42,7 @@ void app_main() { - esp_log_level_set("*", ESP_LOG_INFO); + esp_log_level_set("*", ESP_LOG_DEBUG); // Create a 1-Wire bus #ifdef USE_STATIC diff --git a/main/owb.c b/main/owb.c index 1e32a35..e174805 100644 --- a/main/owb.c +++ b/main/owb.c @@ -42,28 +42,27 @@ static const char * TAG = "owb"; /// @cond ignore struct _OneWireBus_Timing { - int A, B, C, D, E, F, G, H, I, J; + uint32_t A, B, C, D, E, F, G, H, I, J; }; //// @endcond -// 1-Wire timing delays (standard) in ticks (quarter-microseconds). +// 1-Wire timing delays (standard) in microseconds. +// Labels and values are from https://www.maximintegrated.com/en/app-notes/index.mvp/id/126 static const struct _OneWireBus_Timing _StandardTiming = { - 6 * 4, - 64 * 4, - 60 * 4, - 10 * 4, - 9 * 4, - 55 * 4, - 0, // G - 480 * 4, // H - 70 * 4, // I - 410 * 4, // J + 6, // A - read/write "1" master pull DQ low duration + 64, // B - write "0" master pull DQ low duration + 60, // C - write "1" master pull DQ high duration + 10, // D - write "0" master pull DQ high duration + 9, // E - read master pull DQ high duration + 55, // F - complete read timeslot + 10ms recovery + 0, // G - wait before reset + 480, // H - master pull DQ low duration + 70, // I - master pull DQ high duration + 410, // J - complete presence timeslot + recovery }; -static void _tick_delay(int ticks) +static void _us_delay(uint32_t time_us) { - // Each tick is 0.25 microseconds. - float time_us = ticks / 4.0; ets_delay_us(time_us); } @@ -90,7 +89,7 @@ bool _is_init(const OneWireBus * bus) } /** - * @brief Generate a 1-Wire reset. + * @brief Generate a 1-Wire reset (initialization). * @param[in] bus Initialised bus instance. * @return true if device is present, otherwise false. */ @@ -101,15 +100,15 @@ static bool _reset(const OneWireBus * bus) { gpio_set_direction(bus->gpio, GPIO_MODE_OUTPUT); - _tick_delay(bus->timing->G); + _us_delay(bus->timing->G); gpio_set_level(bus->gpio, 0); // Drive DQ low - _tick_delay(bus->timing->H); + _us_delay(bus->timing->H); gpio_set_level(bus->gpio, 1); // Release the bus - _tick_delay(bus->timing->I); + _us_delay(bus->timing->I); gpio_set_direction(bus->gpio, GPIO_MODE_INPUT); int level1 = gpio_get_level(bus->gpio); - _tick_delay(bus->timing->J); // Complete the reset sequence recovery + _us_delay(bus->timing->J); // Complete the reset sequence recovery int level2 = gpio_get_level(bus->gpio); present = (level1 == 0) && (level2 == 1); // Sample for presence pulse from slave @@ -131,9 +130,9 @@ static void _write_bit(const OneWireBus * bus, int bit) int delay2 = bit ? bus->timing->B : bus->timing->D; gpio_set_direction(bus->gpio, GPIO_MODE_OUTPUT); gpio_set_level(bus->gpio, 0); // Drive DQ low - _tick_delay(delay1); + _us_delay(delay1); gpio_set_level(bus->gpio, 1); // Release the bus - _tick_delay(delay2); + _us_delay(delay2); } } @@ -148,13 +147,13 @@ static int _read_bit(const OneWireBus * bus) { gpio_set_direction(bus->gpio, GPIO_MODE_OUTPUT); gpio_set_level(bus->gpio, 0); // Drive DQ low - _tick_delay(bus->timing->A); + _us_delay(bus->timing->A); gpio_set_level(bus->gpio, 1); // Release the bus - _tick_delay(bus->timing->E); + _us_delay(bus->timing->E); gpio_set_direction(bus->gpio, GPIO_MODE_INPUT); int level = gpio_get_level(bus->gpio); - _tick_delay(bus->timing->F); // Complete the timeslot and 10us recovery + _us_delay(bus->timing->F); // Complete the timeslot and 10us recovery result = level & 0x01; } return result;