diff --git a/README.md b/README.md index 9ef756a..0b3a6f9 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ This library includes: * CRC checks on ROM code and temperature data. * Programmable temperature measurement resolution (9, 10, 11 or 12-bit resolution). * Temperature conversion and retrieval. + * Separation of conversion and temperature retrieval to allow for simultaneous conversion across multiple devices. ## Documentation @@ -51,7 +52,7 @@ Parts of this code are based on references provided to the public domain by Maxi The following features are anticipated but not yet implemented: - * Simultaneous temperature conversion from multiple devices on the same bus - concurrency. + * Concurrency support (multiple tasks accessing devices on the same bus). * Alarm support. * EEPROM support. * Parasitic power support. diff --git a/main/ds18b20.c b/main/ds18b20.c index eced720..f05fe04 100644 --- a/main/ds18b20.c +++ b/main/ds18b20.c @@ -360,9 +360,9 @@ DS18B20_RESOLUTION ds18b20_read_resolution(DS18B20_Info * ds18b20_info) return resolution; } -float ds18b20_get_temp(const DS18B20_Info * ds18b20_info) +bool ds18b20_convert(const DS18B20_Info * ds18b20_info) { - float temp = 0.0f; + bool result = false; if (_is_init(ds18b20_info)) { OneWireBus * bus = ds18b20_info->bus; @@ -370,10 +370,42 @@ float ds18b20_get_temp(const DS18B20_Info * ds18b20_info) { // initiate a temperature measurement owb_write_byte(bus, DS18B20_FUNCTION_TEMP_CONVERT); + result = true; + } + else + { + ESP_LOGE(TAG, "ds18b20 device not responding"); + } + } + return result; +} - // wait at least maximum conversion time - _wait_for_conversion(ds18b20_info->resolution); +void ds18b20_convert_all(const OneWireBus * bus) +{ + owb_reset(bus); + owb_write_byte(bus, OWB_ROM_SKIP); + owb_write_byte(bus, DS18B20_FUNCTION_TEMP_CONVERT); + + // wait the maximum conversion duration + _wait_for_conversion(DS18B20_RESOLUTION_12_BIT); +} + +void ds18b20_wait_for_conversion(const DS18B20_Info * ds18b20_info) +{ + if (_is_init(ds18b20_info)) + { + _wait_for_conversion(ds18b20_info->resolution); + } +} +float ds18b20_read_temp(const DS18B20_Info * ds18b20_info) +{ + float temp = 0.0f; + if (_is_init(ds18b20_info)) + { + OneWireBus * bus = ds18b20_info->bus; + if (_address_device(ds18b20_info)) + { // read measurement _address_device(ds18b20_info); owb_write_byte(bus, DS18B20_FUNCTION_SCRATCHPAD_READ); @@ -411,6 +443,23 @@ float ds18b20_get_temp(const DS18B20_Info * ds18b20_info) ESP_LOGE(TAG, "ds18b20 device not responding"); } } + return temp; +} +float ds18b20_convert_and_read_temp(const DS18B20_Info * ds18b20_info) +{ + float temp = 0.0f; + if (_is_init(ds18b20_info)) + { + if (ds18b20_convert(ds18b20_info)) + { + // wait at least maximum conversion time + _wait_for_conversion(ds18b20_info->resolution); + + temp = ds18b20_read_temp(ds18b20_info); + } + } return temp; } + + diff --git a/main/ds18b20.h b/main/ds18b20.h index c3b09e2..76dd47a 100644 --- a/main/ds18b20.h +++ b/main/ds18b20.h @@ -136,12 +136,39 @@ DS18B20_RESOLUTION ds18b20_read_resolution(DS18B20_Info * ds18b20_info); OneWireBus_ROMCode ds18b20_read_rom(DS18B20_Info * ds18b20_info); /** - * @brief Get current temperature from device. + * @brief Start a temperature measurement conversion on a single device. + * @param[in] ds18b20_info Pointer to device info instance. + */ +bool ds18b20_convert(const DS18B20_Info * ds18b20_info); + +/** + * @brief Start temperature conversion on all connected devices. + * @param[in] bus Pointer to initialised bus instance. + */ +void ds18b20_convert_all(const OneWireBus * bus); + +/** + * @brief Wait for the maximum conversion time according to the current resolution of the device. + * @param[in] bus Pointer to initialised bus instance. + */ +void ds18b20_wait_for_conversion(const DS18B20_Info * ds18b20_info); + +/** + * @brief Read last temperature measurement from device. + * + * This is typically called after ds18b20_start_mass_conversion(), provided enough time + * has elapsed to ensure that all devices have completed their conversions. * @param[in] ds18b20_info Pointer to device info instance. Must be initialised first. - * @return The current temperature returned by the device, in degrees Celsius. + * @return The measurement value returned by the device, in degrees Celsius. */ -float ds18b20_get_temp(const DS18B20_Info * ds18b20_info); +float ds18b20_read_temp(const DS18B20_Info * ds18b20_info); +/** + * @brief Convert, wait and read current temperature from device. + * @param[in] ds18b20_info Pointer to device info instance. Must be initialised first. + * @return The measurement value returned by the device, in degrees Celsius. + */ +float ds18b20_convert_and_read_temp(const DS18B20_Info * ds18b20_info); #ifdef __cplusplus } diff --git a/main/ds18b20_main.c b/main/ds18b20_main.c index 3d58832..e8615e2 100644 --- a/main/ds18b20_main.c +++ b/main/ds18b20_main.c @@ -72,6 +72,11 @@ void app_main() 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 }, @@ -82,15 +87,8 @@ void app_main() 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"); - //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); - // Create a DS18B20 device on the 1-Wire bus #ifdef USE_STATIC - DS18B20_Info ds18b20_info_static; // static allocation - DS18B20_Info * ds18b20_info = &ds18b20_info_static; DS18B20_Info devices_static[MAX_DEVICES] = {0}; DS18B20_Info * devices[MAX_DEVICES] = {0}; for (int i = 0; i < MAX_DEVICES; ++i) @@ -98,7 +96,6 @@ void app_main() devices[i] = &(devices_static[i]); } #else - DS18B20_Info * ds18b20_info = ds18b20_malloc(); // heap allocation DS18B20_Info * devices[MAX_DEVICES] = {0}; #endif @@ -123,21 +120,44 @@ void app_main() ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION); } - // read temperatures from all sensors sequentially - while (1) +// // 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) { - printf("\nTemperature readings (degrees C):\n"); - for (int i = 0; i < num_devices; ++i) + while (1) { - float temp = ds18b20_get_temp(devices[i]); - printf(" %d: %.3f\n", i, temp); + printf("\nTemperature readings (degrees C):\n"); + ds18b20_convert_all(owb); + + // we know all devices use the same resolution, so use the first device to determine the delay + ds18b20_wait_for_conversion(devices[0]); + + for (int i = 0; i < num_devices; ++i) + { + float temp = ds18b20_read_temp(devices[i]); + printf(" %d: %.3f\n", i, temp); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); } - vTaskDelay(1000 / portTICK_PERIOD_MS); } #ifndef USE_STATIC // clean up dynamically allocated data - ds18b20_free(&ds18b20_info); + for (int i = 0; i < num_devices; ++i) + { + ds18b20_free(&devices[i]); + } owb_free(&owb); #endif diff --git a/main/owb.h b/main/owb.h index af80a82..9ad953a 100644 --- a/main/owb.h +++ b/main/owb.h @@ -80,6 +80,20 @@ typedef union } OneWireBus_ROMCode; +/** + * @brief Represents the state of a device search on the 1-Wire bus. + * + * Pass a pointer to this structure to owb_search_first() and + * owb_search_next() to iterate through detected devices on the bus. + */ +typedef struct +{ + OneWireBus_ROMCode rom_code; + int last_discrepancy; + int last_family_discrepancy; + int last_device_flag; +} OneWireBus_SearchState; + /** * @brief Construct a new 1-Wire bus instance. * New instance should be initialised before calling other functions. @@ -188,23 +202,6 @@ uint8_t owb_crc8_byte(uint8_t crc, uint8_t data); */ uint8_t owb_crc8_bytes(uint8_t crc, const uint8_t * data, size_t len); - -// Search API - -/** - * @brief Represents the state of a device search on the 1-Wire bus. - * - * Pass a pointer to this structure to owb_search_first() and - * owb_search_next() to iterate through detected devices on the bus. - */ -typedef struct -{ - OneWireBus_ROMCode rom_code; - int last_discrepancy; - int last_family_discrepancy; - int last_device_flag; -} OneWireBus_SearchState; - /** * @brief Locates the first device on the 1-Wire bus, if present. * @param[in] bus Pointer to initialised bus instance.