Sun, 21 Oct 2018 13:07:50 +0200
Updated documentation
0 | 1 | /** |
2 | * @file task_ds18b20.c | |
4 | 3 | * @brief The FreeRTOS task to query the DS18B20 sensors on one or two |
4 | * one-wire busses. Each bus must have only one sensor. That way | |
5 | * we don't need to care about the DS18B20 internal ROM address. | |
6 | * The task will update the DS18B20_State structure. | |
0 | 7 | */ |
8 | ||
9 | ||
10 | #include "owb.h" | |
11 | #include "owb_rmt.h" | |
12 | #include "ds18b20.h" | |
13 | #include "config.h" | |
14 | ||
15 | ||
16 | #ifdef CONFIG_TEMP_SENSORS_ONEWIRE | |
17 | #define GPIO_DS18B20_MLT (CONFIG_ONE_WIRE_MLT) | |
18 | #define GPIO_DS18B20_HLT (CONFIG_ONE_WIRE_HLT) | |
19 | #define MAX_DEVICES (8) | |
20 | #define DS18B20_RESOLUTION (DS18B20_RESOLUTION_12_BIT) | |
21 | #define SAMPLE_PERIOD (2000) // milliseconds | |
22 | #endif | |
23 | ||
24 | #ifdef CONFIG_TEMP_SENSORS_SIMULATOR | |
25 | #define SAMPLE_PERIOD (750) // milliseconds | |
26 | ||
27 | float Fake_MLT = 18.90; | |
28 | float Fake_HLT = 18.70; | |
29 | #endif | |
30 | ||
31 | static const char *TAG = "task_ds18b20"; | |
32 | ||
33 | SemaphoreHandle_t xSemaphoreDS18B20 = NULL; | |
34 | DS18B20_State *ds18b20_state; | |
35 | ||
36 | ||
37 | /* | |
38 | * Task to read temperature sensors. | |
39 | */ | |
40 | void task_ds18b20(void *pvParameter) | |
41 | { | |
42 | #ifdef CONFIG_TEMP_SENSORS_ONEWIRE | |
43 | int num_devices = 0; | |
44 | float readings = 0; | |
45 | bool found = false; | |
46 | DS18B20_ERROR errors = 0; | |
47 | TickType_t last_wake_time = xTaskGetTickCount(); | |
48 | ||
49 | ESP_LOGI(TAG, "Starting DS18B20 sensors"); | |
50 | ds18b20_state = malloc(sizeof(DS18B20_State)); | |
51 | ds18b20_state->mlt_valid = ds18b20_state->hlt_valid = false; | |
52 | ds18b20_state->mlt_temperature = ds18b20_state->hlt_temperature = 0.0; | |
53 | ds18b20_state->mlt_error = ds18b20_state->hlt_error = DS18B20_ERR_NOSENSOR; | |
54 | ||
55 | /* | |
56 | * Initialize the MLT and HLT one-wire busses. | |
57 | */ | |
58 | OneWireBus *owb_mlt; | |
59 | OneWireBus *owb_hlt; | |
60 | owb_rmt_driver_info rmt_driver_info_mlt; | |
61 | owb_rmt_driver_info rmt_driver_info_hlt; | |
62 | owb_mlt = owb_rmt_initialize(&rmt_driver_info_mlt, GPIO_DS18B20_MLT, RMT_CHANNEL_1, RMT_CHANNEL_0); | |
63 | owb_hlt = owb_rmt_initialize(&rmt_driver_info_hlt, GPIO_DS18B20_HLT, RMT_CHANNEL_3, RMT_CHANNEL_2); | |
64 | owb_use_crc(owb_mlt, true); // enable CRC check for ROM code | |
65 | owb_use_crc(owb_hlt, true); | |
66 | ||
67 | DS18B20_Info * ds18b20_info = ds18b20_malloc(); | |
68 | ||
69 | /* | |
70 | * Task loop forever. | |
71 | */ | |
72 | while (1) { | |
73 | ||
74 | last_wake_time = xTaskGetTickCount(); | |
75 | ||
76 | num_devices = 0; | |
77 | OneWireBus_SearchState mlt_search_state = {0}; | |
78 | found = false; | |
79 | owb_search_first(owb_mlt, &mlt_search_state, &found); | |
80 | while (found) { | |
81 | ++num_devices; | |
82 | owb_search_next(owb_mlt, &mlt_search_state, &found); | |
83 | } | |
84 | ||
85 | if (num_devices == 1) { | |
86 | ds18b20_init_solo(ds18b20_info, owb_mlt); // only one device on bus | |
87 | ds18b20_use_crc(ds18b20_info, true); // enable CRC check for temperature readings | |
88 | ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION); // returns true if ok. | |
89 | ||
90 | // Read temperatures more efficiently by starting conversions on all devices at the same time | |
91 | ds18b20_convert_all(owb_mlt); | |
92 | ds18b20_wait_for_conversion(ds18b20_info); | |
93 | ||
94 | errors = ds18b20_read_temp(ds18b20_info, &readings); | |
95 | ||
96 | if (xSemaphoreTake(xSemaphoreDS18B20, 25) == pdTRUE) { | |
97 | if (errors == DS18B20_OK) { | |
98 | ds18b20_state->mlt_error = DS18B20_ERR_NONE; | |
99 | ds18b20_state->mlt_valid = true; | |
100 | ds18b20_state->mlt_temperature = readings; | |
101 | } else { | |
102 | if (errors == DS18B20_ERROR_CRC) | |
103 | ds18b20_state->mlt_error = DS18B20_ERR_CRC; | |
104 | if (errors == DS18B20_ERROR_OWB) | |
105 | ds18b20_state->mlt_error = DS18B20_ERR_READ; | |
106 | if (errors == DS18B20_ERROR_DEVICE) | |
107 | ds18b20_state->mlt_error = DS18B20_ERR_READ; | |
108 | ds18b20_state->mlt_valid = false; | |
109 | ds18b20_state->mlt_temperature = 0.0; | |
110 | } | |
111 | xSemaphoreGive(xSemaphoreDS18B20); | |
112 | } | |
113 | ||
114 | } else { | |
115 | /* | |
116 | * Zero or more then one device, this is an error. | |
117 | */ | |
118 | if (xSemaphoreTake(xSemaphoreDS18B20, 25) == pdTRUE) { | |
119 | if (num_devices == 0) | |
120 | ds18b20_state->mlt_error = DS18B20_ERR_NOSENSOR; | |
121 | else | |
122 | ds18b20_state->mlt_error = DS18B20_ERR_TOOMANY; | |
123 | ds18b20_state->mlt_valid = false; | |
124 | ds18b20_state->mlt_temperature = 0.0; | |
125 | xSemaphoreGive(xSemaphoreDS18B20); | |
126 | } | |
127 | } // if num_devices == 1 | |
128 | ||
129 | num_devices = 0; | |
130 | OneWireBus_SearchState hlt_search_state = {0}; | |
131 | found = false; | |
132 | owb_search_first(owb_hlt, &hlt_search_state, &found); | |
133 | while (found) { | |
134 | ++num_devices; | |
135 | owb_search_next(owb_hlt, &hlt_search_state, &found); | |
136 | } | |
137 | ||
138 | if (num_devices == 1) { | |
139 | ds18b20_init_solo(ds18b20_info, owb_hlt); // only one device on bus | |
140 | ds18b20_use_crc(ds18b20_info, true); // enable CRC check for temperature readings | |
141 | ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION); | |
142 | ||
143 | // Read temperatures more efficiently by starting conversions on all devices at the same time | |
144 | ds18b20_convert_all(owb_hlt); | |
145 | ds18b20_wait_for_conversion(ds18b20_info); | |
146 | ||
147 | errors = ds18b20_read_temp(ds18b20_info, &readings); | |
148 | ||
149 | if (xSemaphoreTake(xSemaphoreDS18B20, 25) == pdTRUE) { | |
150 | if (errors == DS18B20_OK) { | |
151 | ds18b20_state->hlt_error = DS18B20_ERR_NONE; | |
152 | ds18b20_state->hlt_valid = true; | |
153 | ds18b20_state->hlt_temperature = readings; | |
154 | } else { | |
155 | if (errors == DS18B20_ERROR_CRC) | |
156 | ds18b20_state->hlt_error = DS18B20_ERR_CRC; | |
157 | if (errors == DS18B20_ERROR_OWB) | |
158 | ds18b20_state->hlt_error = DS18B20_ERR_READ; | |
159 | if (errors == DS18B20_ERROR_DEVICE) | |
160 | ds18b20_state->hlt_error = DS18B20_ERR_READ; | |
161 | ds18b20_state->hlt_valid = false; | |
162 | ds18b20_state->hlt_temperature = 0.0; | |
163 | } | |
164 | xSemaphoreGive(xSemaphoreDS18B20); | |
165 | } | |
166 | } else { | |
167 | /* | |
168 | * Zero or more then one device, this is an error. | |
169 | */ | |
170 | if (xSemaphoreTake(xSemaphoreDS18B20, 25) == pdTRUE) { | |
171 | if (num_devices == 0) | |
172 | ds18b20_state->hlt_error = DS18B20_ERR_NOSENSOR; | |
173 | else | |
174 | ds18b20_state->hlt_error = DS18B20_ERR_TOOMANY; | |
175 | ds18b20_state->hlt_valid = false; | |
176 | ds18b20_state->hlt_temperature = 0.0; | |
177 | xSemaphoreGive(xSemaphoreDS18B20); | |
178 | } | |
179 | } // if num_devices == 1 | |
180 | ||
181 | #if 0 | |
182 | printf("MLT %.3f %d err %s, HLT %.3f, %d err %s\n", | |
183 | ds18b20_state->mlt_temperature, ds18b20_state->mlt_error, (ds18b20_state->mlt_valid) ? "valid":" N/A ", | |
184 | ds18b20_state->hlt_temperature, ds18b20_state->hlt_error, (ds18b20_state->hlt_valid) ? "valid":" N/A "); | |
185 | #endif | |
186 | vTaskDelayUntil(&last_wake_time, SAMPLE_PERIOD / portTICK_PERIOD_MS); | |
187 | } | |
188 | #endif | |
189 | ||
190 | #ifdef CONFIG_TEMP_SENSORS_SIMULATOR | |
191 | ||
192 | float Plate_MLT = 18.90; | |
193 | extern int MLT_pin, HLT_pin; | |
194 | ||
195 | ESP_LOGI(TAG, "Starting Fake sensors"); | |
196 | ds18b20_state = malloc(sizeof(DS18B20_State)); | |
197 | ds18b20_state->mlt_valid = ds18b20_state->hlt_valid = true; | |
198 | ds18b20_state->mlt_temperature = 18.90; | |
199 | ds18b20_state->hlt_temperature = 18.70; | |
200 | ds18b20_state->mlt_error = ds18b20_state->hlt_error = DS18B20_ERR_NONE; | |
201 | ||
202 | /* | |
203 | * Task loop forever. Update the temperatures each 750 mSeconds. | |
204 | */ | |
205 | while (1) { | |
206 | ||
207 | /* | |
208 | * Make this fake heater a bit more real by using a simulated heatplate. | |
209 | * We heatup that plate and then transfer the heat to the water. | |
210 | * That way we get a nice overshoot like in real life. | |
211 | */ | |
212 | if (MLT_pin) { | |
213 | if (Plate_MLT < 250.0) | |
214 | Plate_MLT += SAMPLE_PERIOD * 0.001; // Simulate plate upto 250 degrees | |
215 | } else { | |
216 | if (Plate_MLT > Fake_MLT) | |
217 | Plate_MLT -= SAMPLE_PERIOD * 0.00002 * (Plate_MLT - Fake_MLT); | |
218 | } | |
219 | // If plate is hotter then the water with a offset so that cooling later works. | |
220 | if (Plate_MLT > (Fake_MLT + 5.0)) { | |
221 | if (Fake_MLT < 100.05) | |
222 | Fake_MLT += SAMPLE_PERIOD * 0.000001 * (Plate_MLT - Fake_MLT); | |
223 | } | |
224 | // Allways loose heat to the air | |
225 | if (Fake_MLT > 16.0) { | |
226 | Fake_MLT -= SAMPLE_PERIOD * 0.00000010 * (Fake_MLT - 16.0); | |
227 | } | |
228 | ||
229 | if ((equipment.SSR2 == SSR2_HLT_SHARE) || (equipment.SSR2 == SSR2_HLT_IND)) { | |
230 | /* | |
231 | * There is a HLT function configured. | |
232 | */ | |
233 | if (HLT_pin) { | |
234 | if (Fake_HLT < 100.05) | |
235 | Fake_HLT += SAMPLE_PERIOD * 0.000055; | |
236 | } else { | |
237 | if (Fake_HLT > 16.0) | |
238 | Fake_HLT -= SAMPLE_PERIOD * 0.00000006 * (Fake_HLT - 16.0); | |
239 | } | |
240 | } | |
241 | ||
242 | if (xSemaphoreTake(xSemaphoreDS18B20, 25) == pdTRUE) { | |
243 | ds18b20_state->mlt_temperature = ((int)(Fake_MLT * 16)) / 16.0; | |
244 | ds18b20_state->hlt_temperature = ((int)(Fake_HLT * 16)) / 16.0; | |
245 | xSemaphoreGive(xSemaphoreDS18B20); | |
246 | } | |
247 | ||
248 | vTaskDelay(SAMPLE_PERIOD / portTICK_PERIOD_MS); | |
249 | } | |
250 | ||
251 | #endif | |
252 | } | |
253 | ||
254 |