41 #include "freertos/FreeRTOS.h"
42 #include "freertos/task.h"
43 #include "driver/gpio.h"
44 #include "esp_system.h"
50 static const char *
TAG = CONFIG_TEMP_TAG;
51 static const int T_CONV = 750;
54 #define DS18B20_FUNCTION_TEMP_CONVERT 0x44
55 #define DS18B20_FUNCTION_SCRATCHPAD_WRITE 0x4E
56 #define DS18B20_FUNCTION_SCRATCHPAD_READ 0xBE
57 #define DS18B20_FUNCTION_SCRATCHPAD_COPY 0x48
58 #define DS18B20_FUNCTION_EEPROM_RECALL 0xB8
59 #define DS18B20_FUNCTION_POWER_SUPPLY_READ 0xB4
64 uint8_t temperature[2];
67 uint8_t configuration;
70 } __attribute__((packed)) Scratchpad;
75 if (ds18b20_info != NULL)
77 ds18b20_info->
bus = bus;
81 ds18b20_info->
solo =
false;
82 ds18b20_info->
init =
true;
86 ESP_LOGE(
TAG,
"ds18b20_info is NULL");
93 if (ds18b20_info != NULL)
95 if (ds18b20_info->
init)
102 ESP_LOGE(
TAG,
"ds18b20_info is not initialised");
107 ESP_LOGE(
TAG,
"ds18b20_info is NULL");
112 static bool _address_device(
const DS18B20_Info *ds18b20_info)
114 bool present =
false;
115 if (_is_init(ds18b20_info))
120 if (ds18b20_info->
solo)
136 ESP_LOGE(
TAG,
"ds18b20 device not responding");
149 int64_t start_time = esp_timer_get_time();
150 if (_check_resolution(resolution))
153 ESP_LOGD(
TAG,
"divisor %d", divisor);
154 float max_conversion_time = (float)T_CONV / (
float)divisor;
155 int ticks = ceil(max_conversion_time / portTICK_PERIOD_MS);
156 ESP_LOGD(
TAG,
"wait for conversion: %.3f ms, %d ticks", max_conversion_time, ticks);
161 int64_t end_time = esp_timer_get_time();
162 return (
float)(end_time - start_time) / 1000000.0f;
165 static float _wait_for_device_signal(
const DS18B20_Info *ds18b20_info)
167 float elapsed_time = 0.0f;
168 if (_check_resolution(ds18b20_info->
resolution))
173 float max_conversion_time = (float)T_CONV / (
float)divisor * 1.1;
174 int max_conversion_ticks = ceil(max_conversion_time / portTICK_PERIOD_MS);
175 ESP_LOGD(
TAG,
"wait for conversion: max %.0f ms, %d ticks", max_conversion_time, max_conversion_ticks);
178 TickType_t start_ticks = xTaskGetTickCount();
179 TickType_t duration_ticks = 0;
185 duration_ticks = xTaskGetTickCount() - start_ticks;
186 }
while (status == 0 && duration_ticks < max_conversion_ticks);
188 elapsed_time = duration_ticks * portTICK_PERIOD_MS;
189 if (duration_ticks >= max_conversion_ticks)
191 ESP_LOGW(
TAG,
"conversion timed out");
195 ESP_LOGD(
TAG,
"conversion took at most %.0f ms", elapsed_time);
204 if (_check_resolution(resolution))
207 static const uint8_t lsb_mask[4] = {~0x07, ~0x03, ~0x01, ~0x00};
209 int16_t raw = (msb << 8) | lsb_masked;
210 result = raw / 16.0f;
214 ESP_LOGE(
TAG,
"Unsupported resolution %d", resolution);
219 static size_t _min(
size_t x,
size_t y)
221 return x > y ? y : x;
238 count =
sizeof(Scratchpad);
240 count = _min(
sizeof(Scratchpad), count);
242 ESP_LOGD(
TAG,
"scratchpad read: CRC %d, count %d", ds18b20_info->
use_crc, count);
243 if (_address_device(ds18b20_info))
250 ESP_LOG_BUFFER_HEX_LEVEL(
TAG, scratchpad, count, ESP_LOG_DEBUG);
256 ESP_LOGD(
TAG,
"No CRC check");
257 bool is_present =
false;
263 if (
owb_crc8_bytes(0, (uint8_t *)scratchpad,
sizeof(*scratchpad)) != 0)
265 ESP_LOGE(
TAG,
"CRC failed");
270 ESP_LOGD(
TAG,
"CRC ok");
276 ESP_LOGE(
TAG,
"owb_read_bytes failed");
282 ESP_LOGE(
TAG,
"owb_write_byte failed");
293 static bool _write_scratchpad(
const DS18B20_Info *ds18b20_info,
const Scratchpad *scratchpad,
bool verify)
298 if (_is_init(ds18b20_info))
300 if (_address_device(ds18b20_info))
302 ESP_LOGD(
TAG,
"scratchpad write 3 bytes:");
303 ESP_LOG_BUFFER_HEX_LEVEL(
TAG, &scratchpad->trigger_high, 3, ESP_LOG_DEBUG);
310 Scratchpad read = {0};
311 if (_read_scratchpad(ds18b20_info, &read, offsetof(Scratchpad, configuration) + 1) ==
DS18B20_OK)
313 if (memcmp(&scratchpad->trigger_high, &read.trigger_high, 3) != 0)
315 ESP_LOGE(
TAG,
"scratchpad verify failed: "
316 "wrote {0x%02x, 0x%02x, 0x%02x}, "
317 "read {0x%02x, 0x%02x, 0x%02x}",
318 scratchpad->trigger_high, scratchpad->trigger_low, scratchpad->configuration,
319 read.trigger_high, read.trigger_low, read.configuration);
325 ESP_LOGE(
TAG,
"read scratchpad failed");
338 DS18B20_Info *ds18b20_info = malloc(
sizeof(*ds18b20_info));
339 if (ds18b20_info != NULL)
341 memset(ds18b20_info, 0,
sizeof(*ds18b20_info));
342 ESP_LOGD(
TAG,
"malloc %p", ds18b20_info);
346 ESP_LOGE(
TAG,
"malloc failed");
354 if (ds18b20_info != NULL && (*ds18b20_info != NULL))
356 ESP_LOGD(
TAG,
"free %p", *ds18b20_info);
358 *ds18b20_info = NULL;
364 if (ds18b20_info != NULL)
366 _init(ds18b20_info, bus);
374 ESP_LOGE(
TAG,
"ds18b20_info is NULL");
380 if (ds18b20_info != NULL)
382 _init(ds18b20_info, bus);
383 ds18b20_info->
solo =
true;
391 ESP_LOGE(
TAG,
"ds18b20_info is NULL");
397 if (_is_init(ds18b20_info))
399 ds18b20_info->
use_crc = use_crc;
400 ESP_LOGD(
TAG,
"use_crc %d", ds18b20_info->
use_crc);
407 if (_is_init(ds18b20_info))
409 if (_check_resolution(ds18b20_info->
resolution))
412 Scratchpad scratchpad = {0};
413 _read_scratchpad(ds18b20_info, &scratchpad,
414 offsetof(Scratchpad, configuration) - offsetof(Scratchpad, temperature) + 1);
417 uint8_t value = (((resolution - 1) & 0x03) << 5) | 0x1f;
418 scratchpad.configuration = value;
419 ESP_LOGD(
TAG,
"configuration value 0x%02x", value);
422 result = _write_scratchpad(ds18b20_info, &scratchpad,
true);
426 ESP_LOGD(
TAG,
"Resolution set to %d bits", (
int)resolution);
432 ESP_LOGW(
TAG,
"Resolution consistency lost - refreshed from device: %d", ds18b20_info->
resolution);
437 ESP_LOGE(
TAG,
"Unsupported resolution %d", resolution);
446 if (_is_init(ds18b20_info))
449 Scratchpad scratchpad = {0};
450 _read_scratchpad(ds18b20_info, &scratchpad,
451 offsetof(Scratchpad, configuration) - offsetof(Scratchpad, temperature) + 1);
454 if (!_check_resolution(resolution))
456 ESP_LOGE(
TAG,
"invalid resolution read from device: 0x%02x", scratchpad.configuration);
461 ESP_LOGD(
TAG,
"Resolution read as %d", resolution);
470 if (_is_init(ds18b20_info))
473 if (_address_device(ds18b20_info))
481 ESP_LOGE(
TAG,
"ds18b20 device not responding");
491 bool is_present =
false;
499 ESP_LOGE(
TAG,
"bus is NULL");
505 float elapsed_time = 0.0f;
506 if (_is_init(ds18b20_info))
512 elapsed_time = _wait_for_duration(ds18b20_info->
resolution);
517 elapsed_time = _wait_for_device_signal(ds18b20_info);
526 if (_is_init(ds18b20_info))
528 uint8_t temp_LSB = 0x00;
529 uint8_t temp_MSB = 0x80;
530 Scratchpad scratchpad = {0};
531 if ((err = _read_scratchpad(ds18b20_info, &scratchpad, 2)) ==
DS18B20_OK)
533 temp_LSB = scratchpad.temperature[0];
534 temp_MSB = scratchpad.temperature[1];
538 if (scratchpad.reserved[1] == 0x0c && temp_MSB == 0x05 && temp_LSB == 0x50)
540 ESP_LOGE(
TAG,
"Read power-on value (85.0)");
544 float temp = _decode_temp(temp_LSB, temp_MSB, ds18b20_info->
resolution);
545 ESP_LOGD(
TAG,
"temp_LSB 0x%02x, temp_MSB 0x%02x, temp %f", temp_LSB, temp_MSB,
temp);
558 if (_is_init(ds18b20_info))
582 ESP_LOGD(
TAG,
"ds18b20_check_for_parasite_power");
588 ESP_LOGD(
TAG,
"owb_reset OK");
591 ESP_LOGD(
TAG,
"owb_write_byte(ROM_SKIP) OK");
595 ESP_LOGD(
TAG,
"owb_write_byte(POWER_SUPPLY_READ) OK");
599 ESP_LOGD(
TAG,
"owb_read_bit OK: 0x%02x", value);
602 *present = !(bool)(value & 0x01u);
611 ESP_LOGE(
TAG,
"bus is NULL");
#define DS18B20_FUNCTION_TEMP_CONVERT
Initiate a single temperature conversion.
void ds18b20_init_solo(DS18B20_Info *ds18b20_info, const OneWireBus *bus)
Initialise a device info instance as a solo device on the bus.
bool ds18b20_set_resolution(DS18B20_Info *ds18b20_info, DS18B20_RESOLUTION resolution)
Set temperature measurement resolution.
void ds18b20_init(DS18B20_Info *ds18b20_info, const OneWireBus *bus, OneWireBus_ROMCode rom_code)
Initialise a device info instance with the specified GPIO.
void ds18b20_free(DS18B20_Info **ds18b20_info)
Delete an existing device info instance.
DS18B20_RESOLUTION ds18b20_read_resolution(DS18B20_Info *ds18b20_info)
Update and return the current temperature measurement resolution from the device.
#define DS18B20_FUNCTION_SCRATCHPAD_READ
Read 9 bytes of data (including CRC) from the device scratchpad.
#define DS18B20_FUNCTION_SCRATCHPAD_WRITE
Write 3 bytes of data to the device scratchpad at positions 2, 3 and 4.
float ds18b20_wait_for_conversion(const DS18B20_Info *ds18b20_info)
Wait for the maximum conversion time according to the current resolution of the device....
DS18B20_ERROR ds18b20_read_temp(const DS18B20_Info *ds18b20_info, float *value)
Read last temperature measurement from device.
#define DS18B20_FUNCTION_POWER_SUPPLY_READ
Determine if a device is using parasitic power.
DS18B20_ERROR ds18b20_check_for_parasite_power(const OneWireBus *bus, bool *present)
Check OneWire bus for presence of parasitic-powered devices.
void ds18b20_convert_all(const OneWireBus *bus)
Start temperature conversion on all connected devices.
void ds18b20_use_crc(DS18B20_Info *ds18b20_info, bool use_crc)
Enable or disable use of CRC checks on device communications.
DS18B20_ERROR ds18b20_convert_and_read_temp(const DS18B20_Info *ds18b20_info, float *value)
Convert, wait and read current temperature from device.
bool ds18b20_convert(const DS18B20_Info *ds18b20_info)
Start a temperature measurement conversion on a single device.
DS18B20_Info * ds18b20_malloc(void)
Construct a new device info instance. New instance should be initialised before calling other functio...
Interface definitions for the Maxim Integrated DS18B20 Programmable Resolution 1-Wire Digital Thermom...
DS18B20_RESOLUTION
Symbols for the supported temperature resolution of the device.
@ DS18B20_RESOLUTION_12_BIT
12-bit resolution (default)
@ DS18B20_RESOLUTION_9_BIT
9-bit resolution, LSB bits 2,1,0 undefined
@ DS18B20_RESOLUTION_INVALID
Invalid resolution.
DS18B20_ERROR
Success and error codes.
@ DS18B20_ERROR_UNKNOWN
An unknown error occurred, or the value was not set.
@ DS18B20_ERROR_NULL
A parameter or value is NULL.
@ DS18B20_ERROR_DEVICE
A device error occurred.
@ DS18B20_ERROR_CRC
A CRC error occurred.
@ DS18B20_ERROR_OWB
A One Wire Bus error occurred.
Interface definitions for the 1-Wire bus component.
owb_status owb_set_strong_pullup(const OneWireBus *bus, bool enable)
Enable or disable the strong-pullup GPIO, if configured.
#define OWB_ROM_SKIP
Address all devices on the bus simultaneously.
uint8_t owb_crc8_bytes(uint8_t crc, const uint8_t *data, size_t len)
1-Wire 8-bit CRC lookup with accumulation over a block of bytes.
owb_status owb_write_rom_code(const OneWireBus *bus, OneWireBus_ROMCode rom_code)
Write a ROM code to the 1-Wire bus ensuring LSB is sent first.
owb_status owb_write_bytes(const OneWireBus *bus, const uint8_t *buffer, size_t len)
Write a number of bytes to the 1-Wire bus.
owb_status owb_read_bytes(const OneWireBus *bus, uint8_t *buffer, unsigned int len)
Read a number of bytes from the 1-Wire bus.
@ OWB_STATUS_OK
Operation succeeded.
owb_status owb_read_bit(const OneWireBus *bus, uint8_t *out)
Read a single bit from the 1-Wire bus.
#define OWB_ROM_MATCH
Address a specific device on the bus by ROM.
owb_status owb_write_byte(const OneWireBus *bus, uint8_t data)
Write a single byte to the 1-Wire bus.
owb_status owb_reset(const OneWireBus *bus, bool *is_present)
Reset the 1-Wire bus.
Structure containing information related to a single DS18B20 device connected via a 1-Wire bus.
DS18B20_RESOLUTION resolution
Temperature measurement resolution per reading.
bool init
True if struct has been initialised, otherwise false.
const 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 use_crc
True if CRC checks are to be used when retrieving information from a device on the bus.
bool solo
True if device is intended to be the only one connected to the bus, otherwise false.
Structure containing 1-Wire bus information relevant to a single instance.
bool use_parasitic_power
True if parasitic-powered devices are expected on the bus.
Represents a 1-Wire ROM Code. This is a sequence of eight bytes, where the first byte is the family n...
volatile float temp
current temp