esp32-warm-water
esp32 based project for the control of a heating element based on temperature
ds18b20_wrapper.c
Go to the documentation of this file.
1 /*
2  * MIT License
3  *
4  * Copyright (c) 2017-2019 David Antliff
5  * Copyright (c) 2021 wolffshots
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * A note on the copyright line: https://www.copyright.gov/title17/92chap4.html#408
26  */
27 
33 #include <stdbool.h>
34 
35 #include "ds18b20_wrapper.h"
36 
37 #include "freertos/FreeRTOS.h"
38 #include "freertos/task.h"
39 #include "esp_system.h"
40 #include "esp_log.h"
41 
42 #include "owb.h"
43 #include "owb.h"
44 #include "ds18b20.h"
45 
46 #define GPIO_DS18B20_0 (CONFIG_TEMP_OWB_GPIO)
47 #define MAX_DEVICES (CONFIG_TEMP_MAX_DEVS)
48 #define DS18B20_RESOLUTION (DS18B20_RESOLUTION_12_BIT)
49 
51 int num_devices = 0;
54 static const char *TAG = CONFIG_TEMP_WRAPPER_TAG;
55 
62 {
63  ESP_LOGI(TAG, "setting up temp sensor");
64  owb = owb_rmt_initialize(&rmt_driver_info, GPIO_DS18B20_0, RMT_CHANNEL_1, RMT_CHANNEL_0);
65  owb_use_crc(owb, true); // enable CRC check for ROM code
66 
67  // Find all connected devices
68  ESP_LOGD(TAG, "find devices:");
69  OneWireBus_ROMCode device_rom_codes[MAX_DEVICES] = {0};
70 
71  OneWireBus_SearchState search_state = {0};
72  bool found = false;
73  owb_search_first(owb, &search_state, &found);
74  while (found)
75  {
76  char rom_code_s[17];
77  owb_string_from_rom_code(search_state.rom_code, rom_code_s, sizeof(rom_code_s));
78  ESP_LOGD(TAG, " %d : %s", num_devices, rom_code_s);
79  device_rom_codes[num_devices] = search_state.rom_code;
80  ++num_devices;
81  owb_search_next(owb, &search_state, &found);
82  }
83  ESP_LOGI(TAG, "found %d device%s", num_devices, num_devices == 1 ? "" : "s");
84 
85  // In this example, if a single device is present, then the ROM code is probably
86  // not very interesting, so just print it out. If there are multiple devices,
87  // then it may be useful to check that a specific device is present.
88 
89  if (num_devices == 1)
90  {
91  // For a single device only:
92  OneWireBus_ROMCode rom_code;
93  owb_status status = owb_read_rom(owb, &rom_code);
94  if (status == OWB_STATUS_OK)
95  {
96  char rom_code_s[OWB_ROM_CODE_STRING_LENGTH];
97  owb_string_from_rom_code(rom_code, rom_code_s, sizeof(rom_code_s));
98  ESP_LOGD(TAG, "single device %s present", rom_code_s);
99  }
100  else
101  {
102  ESP_LOGE(TAG, "an error occurred reading ROM code: %d", status);
103  }
104  }
105  else
106  {
107  // Search for a known ROM code (LSB first):
108  // For example: 0x1502162ca5b2ee28
109  OneWireBus_ROMCode known_device = {
110  .fields.family = {0x28},
111  .fields.serial_number = {0xee, 0xb2, 0xa5, 0x2c, 0x16, 0x02},
112  .fields.crc = {0x15},
113  };
114  char rom_code_s[OWB_ROM_CODE_STRING_LENGTH];
115  owb_string_from_rom_code(known_device, rom_code_s, sizeof(rom_code_s));
116  bool is_present = false;
117 
118  owb_status search_status = owb_verify_rom(owb, known_device, &is_present);
119  if (search_status == OWB_STATUS_OK)
120  {
121  ESP_LOGD(TAG, "device %s is %s", rom_code_s, is_present ? "present" : "not present");
122  }
123  else
124  {
125  ESP_LOGE(TAG, "an error occurred searching for known device: %d", search_status);
126  }
127  }
128 
129  // Create DS18B20 devices on the 1-Wire bus
130 
131  for (int i = 0; i < num_devices; ++i)
132  {
133  DS18B20_Info *ds18b20_info = ds18b20_malloc(); // heap allocation
134  devices[i] = ds18b20_info;
135 
136  if (num_devices == 1)
137  {
138  ESP_LOGI(TAG, "single device optimisations enabled");
139  ds18b20_init_solo(ds18b20_info, owb); // only one device on bus
140  }
141  else
142  {
143  ds18b20_init(ds18b20_info, owb, device_rom_codes[i]); // associate with bus and device
144  }
145  ds18b20_use_crc(ds18b20_info, true); // enable CRC check on all reads
147  }
148 
149  // Check for parasitic-powered devices
150  bool parasitic_power = false;
151  ds18b20_check_for_parasite_power(owb, &parasitic_power);
152  if (parasitic_power)
153  {
154  ESP_LOGI(TAG, "parasitic-powered devices detected");
155  }
156 
157  // In parasitic-power mode, devices cannot indicate when conversions are complete,
158  // so waiting for a temperature conversion must be done by waiting a prescribed duration
159  owb_use_parasitic_power(owb, parasitic_power);
160 
161 #ifdef CONFIG_ENABLE_STRONG_PULLUP_GPIO
162  // An external pull-up circuit is used to supply extra current to OneWireBus devices
163  // during temperature conversions.
164  owb_use_strong_pullup_gpio(owb, CONFIG_STRONG_PULLUP_GPIO);
165 #endif
166 
167  ESP_LOGI(TAG, "finished sensor init");
168  return num_devices;
169 }
175 {
176  ESP_LOGI(TAG, "temp deinit start");
177 
178  // clean up dynamically allocated data
179  for (int i = 0; i < num_devices; ++i)
180  {
181  ds18b20_free(&devices[i]);
182  }
184 
185  ESP_LOGI(TAG, "temp deinit end");
186 
187  fflush(stdout);
188  vTaskDelay(1000 / portTICK_PERIOD_MS);
189 }
196 {
197  ESP_LOGD(TAG, "temp read");
198  // Read temperatures more efficiently by starting conversions on all devices at the same time
199  int errors_count[MAX_DEVICES] = {0};
200  int sample_count = 0;
201  if (num_devices > 0)
202  {
203  TickType_t last_wake_time = xTaskGetTickCount();
204 
206 
207  // In this application all devices use the same resolution,
208  // so use the first device to determine the delay
210 
211  // Read the results immediately after conversion otherwise it may fail
212  float readings[MAX_DEVICES] = {0};
213  DS18B20_ERROR errors[MAX_DEVICES] = {0};
214 
215  for (int i = 0; i < num_devices; ++i)
216  {
217  errors[i] = ds18b20_read_temp(devices[i], &readings[i]);
218  }
219 
220  // Print results in a separate loop, after all have been read
221  ESP_LOGI(TAG, "temperature readings (degrees C): sample %d", ++sample_count);
222  for (int i = 0; i < num_devices; ++i)
223  {
224  if (errors[i] != DS18B20_OK)
225  {
226  ++errors_count[i];
227  }
228 
229  ESP_LOGI(TAG, " %d: %.1f %d errors", i, readings[i], errors_count[i]);
230  }
231 
232  vTaskDelayUntil(&last_wake_time, CONFIG_TEMP_SAMPLE_PERIOD / portTICK_PERIOD_MS);
233  }
234  else
235  {
236  ESP_LOGE(TAG, "no DS18B20 devices detected!");
237  }
238 }
248 void ds18b20_wrapped_capture(float *results, int size)
249 {
250  TickType_t last_wake_time = xTaskGetTickCount();
251  if (size > 0)
252  {
255  for (int i = 0; i < size; ++i)
256  {
257  ds18b20_read_temp(devices[i], &results[i]);
258  }
259  }
260  else
261  {
262  ESP_LOGE(TAG, "no DS18B20 devices detected or invalid size provided");
263  }
264  vTaskDelayUntil(&last_wake_time, CONFIG_TEMP_SAMPLE_PERIOD / portTICK_PERIOD_MS);
265 }
void ds18b20_init_solo(DS18B20_Info *ds18b20_info, const OneWireBus *bus)
Initialise a device info instance as a solo device on the bus.
Definition: ds18b20.c:378
bool ds18b20_set_resolution(DS18B20_Info *ds18b20_info, DS18B20_RESOLUTION resolution)
Set temperature measurement resolution.
Definition: ds18b20.c:404
void ds18b20_init(DS18B20_Info *ds18b20_info, const OneWireBus *bus, OneWireBus_ROMCode rom_code)
Initialise a device info instance with the specified GPIO.
Definition: ds18b20.c:362
void ds18b20_free(DS18B20_Info **ds18b20_info)
Delete an existing device info instance.
Definition: ds18b20.c:352
float ds18b20_wait_for_conversion(const DS18B20_Info *ds18b20_info)
Wait for the maximum conversion time according to the current resolution of the device....
Definition: ds18b20.c:503
DS18B20_ERROR ds18b20_read_temp(const DS18B20_Info *ds18b20_info, float *value)
Read last temperature measurement from device.
Definition: ds18b20.c:523
DS18B20_ERROR ds18b20_check_for_parasite_power(const OneWireBus *bus, bool *present)
Check OneWire bus for presence of parasitic-powered devices.
Definition: ds18b20.c:579
void ds18b20_convert_all(const OneWireBus *bus)
Start temperature conversion on all connected devices.
Definition: ds18b20.c:487
void ds18b20_use_crc(DS18B20_Info *ds18b20_info, bool use_crc)
Enable or disable use of CRC checks on device communications.
Definition: ds18b20.c:395
DS18B20_Info * ds18b20_malloc(void)
Construct a new device info instance. New instance should be initialised before calling other functio...
Definition: ds18b20.c:336
Interface definitions for the Maxim Integrated DS18B20 Programmable Resolution 1-Wire Digital Thermom...
DS18B20_RESOLUTION
Symbols for the supported temperature resolution of the device.
Definition: ds18b20.h:61
DS18B20_ERROR
Success and error codes.
Definition: ds18b20.h:48
@ DS18B20_OK
Success.
Definition: ds18b20.h:50
OneWireBus * owb
onewire bus pointer
void ds18b20_wrapped_read(void)
print the temps runs conversion on all the owb devices, waits for the conversion and then prints out ...
#define MAX_DEVICES
maximum number of devices to search for
void ds18b20_wrapped_deinit(void)
deinit the sensor cleans up and frees all of the devices and the onewire bus
void ds18b20_wrapped_capture(float *results, int size)
capture temps to results this function runs conversion on all the owb devices, waits for conversion t...
int ds18b20_wrapped_init(void)
init the sensor intitialises the onewire bus and finds and intialises ds18b20 sensors along the pin
DS18B20_Info * devices[MAX_DEVICES]
list of devices
#define GPIO_DS18B20_0
the gpio pin to search for sensors on
int num_devices
current number of devices found
owb_rmt_driver_info rmt_driver_info
the rmt driver info for communicating over the owb
definitions for wrapper component to help setup and interface with temp sensor
Interface definitions for the 1-Wire bus component.
owb_status owb_read_rom(const OneWireBus *bus, OneWireBus_ROMCode *rom_code)
Read ROM code from device - only works when there is a single device on the bus.
Definition: owb.c:361
owb_status owb_use_parasitic_power(OneWireBus *bus, bool use_parasitic_power)
Enable or disable use of parasitic power on the One Wire Bus. This affects how devices signal on the ...
Definition: owb.c:299
char * owb_string_from_rom_code(OneWireBus_ROMCode rom_code, char *buffer, size_t len)
Create a string representation of a ROM code, most significant byte (CRC8) first.
Definition: owb.c:709
owb_status
Represents the result of OWB API functions.
Definition: owb.h:114
@ OWB_STATUS_OK
Operation succeeded.
Definition: owb.h:116
owb_status owb_use_crc(OneWireBus *bus, bool use_crc)
Enable or disable use of CRC checks on device communications.
Definition: owb.c:276
owb_status owb_uninitialize(OneWireBus *bus)
call to release resources after completing use of the OneWireBus
Definition: owb.c:259
owb_status owb_search_next(const OneWireBus *bus, OneWireBus_SearchState *state, bool *found_device)
Locates the next device on the 1-Wire bus, if present, starting from the provided state....
Definition: owb.c:685
#define OWB_ROM_CODE_STRING_LENGTH
Typical length of OneWire bus ROM ID as ASCII hex string, including null terminator.
Definition: owb.h:57
owb_status owb_use_strong_pullup_gpio(OneWireBus *bus, gpio_num_t gpio)
Enable or disable use of extra GPIO to activate strong pull-up circuit. This only has effect if paras...
Definition: owb.c:322
owb_status owb_search_first(const OneWireBus *bus, OneWireBus_SearchState *state, bool *found_device)
Locates the first device on the 1-Wire bus, if present.
Definition: owb.c:657
owb_status owb_verify_rom(const OneWireBus *bus, OneWireBus_ROMCode rom_code, bool *is_present)
Verify the device specified by ROM code is present.
Definition: owb.c:416
OneWireBus * owb_rmt_initialize(owb_rmt_driver_info *info, gpio_num_t gpio_num, rmt_channel_t tx_channel, rmt_channel_t rx_channel)
Initialise the RMT driver.
Definition: owb_rmt.c:453
Structure containing information related to a single DS18B20 device connected via a 1-Wire bus.
Definition: ds18b20.h:74
uint8_t family[1]
family identifier (1 byte, LSB - read/write first)
Definition: owb.h:87
Represents the state of a device search on the 1-Wire bus.
Definition: owb.h:103
OneWireBus_ROMCode rom_code
Device ROM code.
Definition: owb.h:104
Structure containing 1-Wire bus information relevant to a single instance.
Definition: owb.h:69
RMT driver information.
Definition: owb_rmt.h:51
Represents a 1-Wire ROM Code. This is a sequence of eight bytes, where the first byte is the family n...
Definition: owb.h:83
struct OneWireBus_ROMCode::fields fields
Provides access via field names.
const char * TAG
Definition: wifi_sta.c:42