9
|
1 /********************************************************************************* |
|
2 Title: DS18X20-Functions via One-Wire-Bus |
|
3 Author: Martin Thomas <[email protected]> |
|
4 http://www.siwawi.arubi.uni-kl.de/avr-projects |
|
5 Software: avr-gcc 4.3.3 / avr-libc 1.6.7 (WinAVR 3/2010) |
|
6 Hardware: any AVR - tested with ATmega16/ATmega32/ATmega324P and 3 DS18B20 |
|
7 |
|
8 Partly based on code from Peter Dannegger and others. |
|
9 |
|
10 changelog: |
|
11 20041124 - Extended measurements for DS18(S)20 contributed by Carsten Foss (CFO) |
|
12 200502xx - function DS18X20_read_meas_single |
|
13 20050310 - DS18x20 EEPROM functions (can be disabled to save flash-memory) |
|
14 (DS18X20_EEPROMSUPPORT in ds18x20.h) |
|
15 20100625 - removed inner returns, added static function for read scratchpad |
|
16 . replaced full-celcius and fractbit method with decicelsius |
|
17 and maxres (degreeCelsius*10e-4) functions, renamed eeprom-functions, |
|
18 delay in recall_e2 replaced by timeout-handling |
|
19 20100714 - ow_command_skip_last_recovery used for parasite-powerd devices so the |
|
20 strong pull-up can be enabled in time even with longer OW recovery times |
|
21 20110209 - fix in DS18X20_format_from_maxres() by Marian Kulesza |
|
22 **********************************************************************************/ |
|
23 |
|
24 #include <stdlib.h> |
|
25 #include <stdint.h> |
|
26 |
|
27 #include <avr/io.h> |
|
28 #include <avr/pgmspace.h> |
|
29 |
|
30 #include "ds18x20.h" |
|
31 #include "onewire.h" |
|
32 #include "crc8.h" |
|
33 |
|
34 #if DS18X20_EEPROMSUPPORT |
|
35 // for 10ms delay in copy scratchpad |
|
36 #include <util/delay.h> |
|
37 #endif /* DS18X20_EEPROMSUPPORT */ |
|
38 |
|
39 /*----------- start of "debug-functions" ---------------*/ |
|
40 |
|
41 #if DS18X20_VERBOSE |
|
42 #if (!DS18X20_DECICELSIUS) |
|
43 #error "DS18X20_DECICELSIUS must be enabled for verbose-mode" |
|
44 #endif |
|
45 |
|
46 /* functions for debugging-output - undef DS18X20_VERBOSE in .h |
|
47 if you run out of program-memory */ |
|
48 #include <string.h> |
|
49 #include "uart.h" |
|
50 #include "uart_addon.h" |
|
51 |
|
52 static int16_t DS18X20_raw_to_decicelsius( uint8_t fc, uint8_t sp[] ); |
|
53 |
|
54 void DS18X20_show_id_uart( uint8_t *id, size_t n ) |
|
55 { |
|
56 size_t i; |
|
57 |
|
58 for( i = 0; i < n; i++ ) { |
|
59 if ( i == 0 ) { uart_puts_P( "FC:" ); } |
|
60 else if ( i == n-1 ) { uart_puts_P( "CRC:" ); } |
|
61 if ( i == 1 ) { uart_puts_P( "SN: " ); } |
|
62 uart_puthex_byte(id[i]); |
|
63 uart_puts_P(" "); |
|
64 if ( i == 0 ) { |
|
65 if ( id[0] == DS18S20_FAMILY_CODE ) { uart_puts_P ("(18S)"); } |
|
66 else if ( id[0] == DS18B20_FAMILY_CODE ) { uart_puts_P ("(18B)"); } |
|
67 else if ( id[0] == DS1822_FAMILY_CODE ) { uart_puts_P ("(22)"); } |
|
68 else { uart_puts_P ("( ? )"); } |
|
69 } |
|
70 } |
|
71 if ( crc8( id, OW_ROMCODE_SIZE) ) |
|
72 uart_puts_P( " CRC FAIL " ); |
|
73 else |
|
74 uart_puts_P( " CRC O.K. " ); |
|
75 } |
|
76 |
|
77 static void show_sp_uart( uint8_t *sp, size_t n ) |
|
78 { |
|
79 size_t i; |
|
80 |
|
81 uart_puts_P( "SP:" ); |
|
82 for( i = 0; i < n; i++ ) { |
|
83 if ( i == n-1 ) { uart_puts_P( "CRC:" ); } |
|
84 uart_puthex_byte(sp[i]); |
|
85 uart_puts_P(" "); |
|
86 } |
|
87 } |
|
88 |
|
89 /* |
|
90 convert raw value from DS18x20 to Celsius |
|
91 input is: |
|
92 - familycode fc (0x10/0x28 see header) |
|
93 - scratchpad-buffer |
|
94 output is: |
|
95 - cel full celsius |
|
96 - fractions of celsius in millicelsius*(10^-1)/625 (the 4 LS-Bits) |
|
97 - subzero =0 positiv / 1 negativ |
|
98 always returns DS18X20_OK |
|
99 */ |
|
100 static uint8_t DS18X20_meas_to_cel( uint8_t fc, uint8_t *sp, |
|
101 uint8_t* subzero, uint8_t* cel, uint8_t* cel_frac_bits) |
|
102 { |
|
103 uint16_t meas; |
|
104 uint8_t i; |
|
105 |
|
106 meas = sp[0]; // LSB |
|
107 meas |= ( (uint16_t)sp[1] ) << 8; // MSB |
|
108 |
|
109 // only work on 12bit-base |
|
110 if( fc == DS18S20_FAMILY_CODE ) { // 9 -> 12 bit if 18S20 |
|
111 /* Extended res. measurements for DS18S20 contributed by Carsten Foss */ |
|
112 meas &= (uint16_t) 0xfffe; // Discard LSB, needed for later extended precicion calc |
|
113 meas <<= 3; // Convert to 12-bit, now degrees are in 1/16 degrees units |
|
114 meas += ( 16 - sp[6] ) - 4; // Add the compensation and remember to subtract 0.25 degree (4/16) |
|
115 } |
|
116 |
|
117 // check for negative |
|
118 if ( meas & 0x8000 ) { |
|
119 *subzero=1; // mark negative |
|
120 meas ^= 0xffff; // convert to positive => (twos complement)++ |
|
121 meas++; |
|
122 } |
|
123 else { |
|
124 *subzero=0; |
|
125 } |
|
126 |
|
127 // clear undefined bits for B != 12bit |
|
128 if ( fc == DS18B20_FAMILY_CODE || fc == DS1822_FAMILY_CODE ) { |
|
129 i = sp[DS18B20_CONF_REG]; |
|
130 if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) { ; } |
|
131 else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT ) { |
|
132 meas &= ~(DS18B20_11_BIT_UNDF); |
|
133 } else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT ) { |
|
134 meas &= ~(DS18B20_10_BIT_UNDF); |
|
135 } else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) { |
|
136 meas &= ~(DS18B20_9_BIT_UNDF); |
|
137 } |
|
138 } |
|
139 |
|
140 *cel = (uint8_t)(meas >> 4); |
|
141 *cel_frac_bits = (uint8_t)(meas & 0x000F); |
|
142 |
|
143 return DS18X20_OK; |
|
144 } |
|
145 |
|
146 static void DS18X20_uart_put_temp(const uint8_t subzero, |
|
147 const uint8_t cel, const uint8_t cel_frac_bits) |
|
148 { |
|
149 char buffer[sizeof(int)*8+1]; |
|
150 size_t i; |
|
151 |
|
152 uart_putc((subzero)?'-':'+'); |
|
153 uart_put_int((int)cel); |
|
154 uart_puts_P("."); |
|
155 itoa(cel_frac_bits*DS18X20_FRACCONV,buffer,10); |
|
156 for ( i = 0; i < 4-strlen(buffer); i++ ) { |
|
157 uart_puts_P("0"); |
|
158 } |
|
159 uart_puts(buffer); |
|
160 uart_puts_P("�C"); |
|
161 } |
|
162 |
|
163 /* verbose output rom-search follows read-scratchpad in one loop */ |
|
164 uint8_t DS18X20_read_meas_all_verbose( void ) |
|
165 { |
|
166 uint8_t id[OW_ROMCODE_SIZE], sp[DS18X20_SP_SIZE], diff; |
|
167 uint8_t i; |
|
168 uint16_t meas; |
|
169 int16_t decicelsius; |
|
170 char s[10]; |
|
171 uint8_t subzero, cel, cel_frac_bits; |
|
172 |
|
173 for( diff = OW_SEARCH_FIRST; diff != OW_LAST_DEVICE; ) |
|
174 { |
|
175 diff = ow_rom_search( diff, &id[0] ); |
|
176 |
|
177 if( diff == OW_PRESENCE_ERR ) { |
|
178 uart_puts_P( "No Sensor found\r" ); |
|
179 return OW_PRESENCE_ERR; // <--- early exit! |
|
180 } |
|
181 |
|
182 if( diff == OW_DATA_ERR ) { |
|
183 uart_puts_P( "Bus Error\r" ); |
|
184 return OW_DATA_ERR; // <--- early exit! |
|
185 } |
|
186 |
|
187 DS18X20_show_id_uart( id, OW_ROMCODE_SIZE ); |
|
188 |
|
189 if( id[0] == DS18B20_FAMILY_CODE || id[0] == DS18S20_FAMILY_CODE || |
|
190 id[0] == DS1822_FAMILY_CODE ) { |
|
191 // temperature sensor |
|
192 |
|
193 uart_putc ('\r'); |
|
194 |
|
195 ow_byte_wr( DS18X20_READ ); // read command |
|
196 |
|
197 for ( i=0 ; i< DS18X20_SP_SIZE; i++ ) { |
|
198 sp[i]=ow_byte_rd(); |
|
199 } |
|
200 |
|
201 show_sp_uart( sp, DS18X20_SP_SIZE ); |
|
202 |
|
203 if ( crc8( &sp[0], DS18X20_SP_SIZE ) ) { |
|
204 uart_puts_P( " CRC FAIL " ); |
|
205 } else { |
|
206 uart_puts_P( " CRC O.K. " ); |
|
207 } |
|
208 uart_putc ('\r'); |
|
209 |
|
210 meas = sp[0]; // LSB Temp. from Scrachpad-Data |
|
211 meas |= (uint16_t) (sp[1] << 8); // MSB |
|
212 |
|
213 uart_puts_P( " T_raw="); |
|
214 uart_puthex_byte( (uint8_t)(meas >> 8) ); |
|
215 uart_puthex_byte( (uint8_t)meas ); |
|
216 uart_puts_P( " " ); |
|
217 |
|
218 if( id[0] == DS18S20_FAMILY_CODE ) { // 18S20 |
|
219 uart_puts_P( "S20/09" ); |
|
220 } |
|
221 else if ( id[0] == DS18B20_FAMILY_CODE || |
|
222 id[0] == DS1822_FAMILY_CODE ) { // 18B20 or 1822 |
|
223 i=sp[DS18B20_CONF_REG]; |
|
224 if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) { |
|
225 uart_puts_P( "B20/12" ); |
|
226 } |
|
227 else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT ) { |
|
228 uart_puts_P( "B20/11" ); |
|
229 } |
|
230 else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT ) { |
|
231 uart_puts_P( " B20/10 " ); |
|
232 } |
|
233 else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) { |
|
234 uart_puts_P( "B20/09" ); |
|
235 } |
|
236 } |
|
237 uart_puts_P(" "); |
|
238 |
|
239 DS18X20_meas_to_cel( id[0], sp, &subzero, &cel, &cel_frac_bits ); |
|
240 DS18X20_uart_put_temp( subzero, cel, cel_frac_bits ); |
|
241 |
|
242 decicelsius = DS18X20_raw_to_decicelsius( id[0], sp ); |
|
243 if ( decicelsius == DS18X20_INVALID_DECICELSIUS ) { |
|
244 uart_puts_P("* INVALID *"); |
|
245 } else { |
|
246 uart_puts_P(" conv: "); |
|
247 uart_put_int(decicelsius); |
|
248 uart_puts_P(" deci�C "); |
|
249 DS18X20_format_from_decicelsius( decicelsius, s, 10 ); |
|
250 uart_puts_P(" fmt: "); |
|
251 uart_puts(s); |
|
252 uart_puts_P(" �C "); |
|
253 } |
|
254 |
|
255 uart_puts("\r"); |
|
256 |
|
257 } // if meas-sensor |
|
258 |
|
259 } // loop all sensors |
|
260 |
|
261 uart_puts_P( "\r" ); |
|
262 |
|
263 return DS18X20_OK; |
|
264 } |
|
265 |
|
266 #endif /* DS18X20_VERBOSE */ |
|
267 |
|
268 #if DS18X20_VERBOSE |
|
269 #define uart_puts_P_verbose(s__) uart_puts_P(s__) |
|
270 #else |
|
271 #define uart_puts_P_verbose(s__) |
|
272 #endif |
|
273 |
|
274 |
|
275 /*----------- end of "debug-functions" ---------------*/ |
|
276 |
|
277 |
|
278 /* find DS18X20 Sensors on 1-Wire-Bus |
|
279 input/ouput: diff is the result of the last rom-search |
|
280 *diff = OW_SEARCH_FIRST for first call |
|
281 output: id is the rom-code of the sensor found */ |
|
282 uint8_t DS18X20_find_sensor( uint8_t *diff, uint8_t id[] ) |
|
283 { |
|
284 uint8_t go; |
|
285 uint8_t ret; |
|
286 |
|
287 ret = DS18X20_OK; |
|
288 go = 1; |
|
289 do { |
|
290 *diff = ow_rom_search( *diff, &id[0] ); |
|
291 if ( *diff == OW_PRESENCE_ERR || *diff == OW_DATA_ERR || |
|
292 *diff == OW_LAST_DEVICE ) { |
|
293 go = 0; |
|
294 ret = DS18X20_ERROR; |
|
295 } else { |
|
296 if ( id[0] == DS18B20_FAMILY_CODE || id[0] == DS18S20_FAMILY_CODE || |
|
297 id[0] == DS1822_FAMILY_CODE ) { |
|
298 go = 0; |
|
299 } |
|
300 } |
|
301 } while (go); |
|
302 |
|
303 return ret; |
|
304 } |
|
305 |
|
306 /* get power status of DS18x20 |
|
307 input: id = rom_code |
|
308 returns: DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE */ |
|
309 uint8_t DS18X20_get_power_status( uint8_t id[] ) |
|
310 { |
|
311 uint8_t pstat; |
|
312 |
|
313 ow_reset(); |
|
314 ow_command( DS18X20_READ_POWER_SUPPLY, id ); |
|
315 pstat = ow_bit_io( 1 ); |
|
316 ow_reset(); |
|
317 return ( pstat ) ? DS18X20_POWER_EXTERN : DS18X20_POWER_PARASITE; |
|
318 } |
|
319 |
|
320 /* start measurement (CONVERT_T) for all sensors if input id==NULL |
|
321 or for single sensor where id is the rom-code */ |
|
322 uint8_t DS18X20_start_meas( uint8_t with_power_extern, uint8_t id[]) |
|
323 { |
|
324 uint8_t ret; |
|
325 |
|
326 ow_reset(); |
|
327 if( ow_input_pin_state() ) { // only send if bus is "idle" = high |
|
328 if ( with_power_extern != DS18X20_POWER_EXTERN ) { |
|
329 ow_command_with_parasite_enable( DS18X20_CONVERT_T, id ); |
|
330 /* not longer needed: ow_parasite_enable(); */ |
|
331 } else { |
|
332 ow_command( DS18X20_CONVERT_T, id ); |
|
333 } |
|
334 ret = DS18X20_OK; |
|
335 } |
|
336 else { |
|
337 uart_puts_P_verbose( "DS18X20_start_meas: Short Circuit!\r" ); |
|
338 ret = DS18X20_START_FAIL; |
|
339 } |
|
340 |
|
341 return ret; |
|
342 } |
|
343 |
|
344 // returns 1 if conversion is in progress, 0 if finished |
|
345 // not available when parasite powered. |
|
346 uint8_t DS18X20_conversion_in_progress(void) |
|
347 { |
|
348 return ow_bit_io( 1 ) ? DS18X20_CONVERSION_DONE : DS18X20_CONVERTING; |
|
349 } |
|
350 |
|
351 static uint8_t read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n ) |
|
352 { |
|
353 uint8_t i; |
|
354 uint8_t ret; |
|
355 |
|
356 ow_command( DS18X20_READ, id ); |
|
357 for ( i = 0; i < n; i++ ) { |
|
358 sp[i] = ow_byte_rd(); |
|
359 } |
|
360 if ( crc8( &sp[0], DS18X20_SP_SIZE ) ) { |
|
361 ret = DS18X20_ERROR_CRC; |
|
362 } else { |
|
363 ret = DS18X20_OK; |
|
364 } |
|
365 |
|
366 return ret; |
|
367 } |
|
368 |
|
369 |
|
370 #if DS18X20_DECICELSIUS |
|
371 |
|
372 /* convert scratchpad data to physical value in unit decicelsius */ |
|
373 static int16_t DS18X20_raw_to_decicelsius( uint8_t familycode, uint8_t sp[] ) |
|
374 { |
|
375 uint16_t measure; |
|
376 uint8_t negative; |
|
377 int16_t decicelsius; |
|
378 uint16_t fract; |
|
379 |
|
380 measure = sp[0] | (sp[1] << 8); |
|
381 //measure = 0xFF5E; // test -10.125 |
|
382 //measure = 0xFE6F; // test -25.0625 |
|
383 |
|
384 if( familycode == DS18S20_FAMILY_CODE ) { // 9 -> 12 bit if 18S20 |
|
385 /* Extended measurements for DS18S20 contributed by Carsten Foss */ |
|
386 measure &= (uint16_t)0xfffe; // Discard LSB, needed for later extended precicion calc |
|
387 measure <<= 3; // Convert to 12-bit, now degrees are in 1/16 degrees units |
|
388 measure += (16 - sp[6]) - 4; // Add the compensation and remember to subtract 0.25 degree (4/16) |
|
389 } |
|
390 |
|
391 // check for negative |
|
392 if ( measure & 0x8000 ) { |
|
393 negative = 1; // mark negative |
|
394 measure ^= 0xffff; // convert to positive => (twos complement)++ |
|
395 measure++; |
|
396 } |
|
397 else { |
|
398 negative = 0; |
|
399 } |
|
400 |
|
401 // clear undefined bits for DS18B20 != 12bit resolution |
|
402 if ( familycode == DS18B20_FAMILY_CODE || familycode == DS1822_FAMILY_CODE ) { |
|
403 switch( sp[DS18B20_CONF_REG] & DS18B20_RES_MASK ) { |
|
404 case DS18B20_9_BIT: |
|
405 measure &= ~(DS18B20_9_BIT_UNDF); |
|
406 break; |
|
407 case DS18B20_10_BIT: |
|
408 measure &= ~(DS18B20_10_BIT_UNDF); |
|
409 break; |
|
410 case DS18B20_11_BIT: |
|
411 measure &= ~(DS18B20_11_BIT_UNDF); |
|
412 break; |
|
413 default: |
|
414 // 12 bit - all bits valid |
|
415 break; |
|
416 } |
|
417 } |
|
418 |
|
419 decicelsius = (measure >> 4); |
|
420 decicelsius *= 10; |
|
421 |
|
422 // decicelsius += ((measure & 0x000F) * 640 + 512) / 1024; |
|
423 // 625/1000 = 640/1024 |
|
424 fract = ( measure & 0x000F ) * 640; |
|
425 if ( !negative ) { |
|
426 fract += 512; |
|
427 } |
|
428 fract /= 1024; |
|
429 decicelsius += fract; |
|
430 |
|
431 if ( negative ) { |
|
432 decicelsius = -decicelsius; |
|
433 } |
|
434 |
|
435 if ( /* decicelsius == 850 || */ decicelsius < -550 || decicelsius > 1250 ) { |
|
436 return DS18X20_INVALID_DECICELSIUS; |
|
437 } else { |
|
438 return decicelsius; |
|
439 } |
|
440 } |
|
441 |
|
442 /* format decicelsius-value into string, itoa method inspired |
|
443 by code from Chris Takahashi for the MSP430 libc, BSD-license |
|
444 modifications mthomas: variable-types, fixed radix 10, use div(), |
|
445 insert decimal-point */ |
|
446 uint8_t DS18X20_format_from_decicelsius( int16_t decicelsius, char str[], uint8_t n) |
|
447 { |
|
448 uint8_t sign = 0; |
|
449 char temp[7]; |
|
450 int8_t temp_loc = 0; |
|
451 uint8_t str_loc = 0; |
|
452 div_t dt; |
|
453 uint8_t ret; |
|
454 |
|
455 // range from -550:-55.0�C to 1250:+125.0�C -> min. 6+1 chars |
|
456 if ( n >= (6+1) && decicelsius > -1000 && decicelsius < 10000 ) { |
|
457 |
|
458 if ( decicelsius < 0) { |
|
459 sign = 1; |
|
460 decicelsius = -decicelsius; |
|
461 } |
|
462 |
|
463 // construct a backward string of the number. |
|
464 do { |
|
465 dt = div(decicelsius,10); |
|
466 temp[temp_loc++] = dt.rem + '0'; |
|
467 decicelsius = dt.quot; |
|
468 } while ( decicelsius > 0 ); |
|
469 |
|
470 if ( sign ) { |
|
471 temp[temp_loc] = '-'; |
|
472 } else { |
|
473 ///temp_loc--; |
|
474 temp[temp_loc] = '+'; |
|
475 } |
|
476 |
|
477 // reverse the string.into the output |
|
478 while ( temp_loc >=0 ) { |
|
479 str[str_loc++] = temp[(uint8_t)temp_loc--]; |
|
480 if ( temp_loc == 0 ) { |
|
481 str[str_loc++] = DS18X20_DECIMAL_CHAR; |
|
482 } |
|
483 } |
|
484 str[str_loc] = '\0'; |
|
485 |
|
486 ret = DS18X20_OK; |
|
487 } else { |
|
488 ret = DS18X20_ERROR; |
|
489 } |
|
490 |
|
491 return ret; |
|
492 } |
|
493 |
|
494 /* reads temperature (scratchpad) of sensor with rom-code id |
|
495 output: decicelsius |
|
496 returns DS18X20_OK on success */ |
|
497 uint8_t DS18X20_read_decicelsius( uint8_t id[], int16_t *decicelsius ) |
|
498 { |
|
499 uint8_t sp[DS18X20_SP_SIZE]; |
|
500 uint8_t ret; |
|
501 |
|
502 ow_reset(); |
|
503 ret = read_scratchpad( id, sp, DS18X20_SP_SIZE ); |
|
504 if ( ret == DS18X20_OK ) { |
|
505 *decicelsius = DS18X20_raw_to_decicelsius( id[0], sp ); |
|
506 } |
|
507 return ret; |
|
508 } |
|
509 |
|
510 /* reads temperature (scratchpad) of sensor without id (single sensor) |
|
511 output: decicelsius |
|
512 returns DS18X20_OK on success */ |
|
513 uint8_t DS18X20_read_decicelsius_single( uint8_t familycode, int16_t *decicelsius ) |
|
514 { |
|
515 uint8_t sp[DS18X20_SP_SIZE]; |
|
516 uint8_t ret; |
|
517 |
|
518 ret = read_scratchpad( NULL, sp, DS18X20_SP_SIZE ); |
|
519 if ( ret == DS18X20_OK ) { |
|
520 *decicelsius = DS18X20_raw_to_decicelsius( familycode, sp ); |
|
521 } |
|
522 return ret; |
|
523 } |
|
524 |
|
525 #endif /* DS18X20_DECICELSIUS */ |
|
526 |
|
527 |
|
528 #if DS18X20_MAX_RESOLUTION |
|
529 |
|
530 static int32_t DS18X20_raw_to_maxres( uint8_t familycode, uint8_t sp[] ) |
|
531 { |
|
532 uint16_t measure; |
|
533 uint8_t negative; |
|
534 int32_t temperaturevalue; |
|
535 |
|
536 measure = sp[0] | (sp[1] << 8); |
|
537 //measure = 0xFF5E; // test -10.125 |
|
538 //measure = 0xFE6F; // test -25.0625 |
|
539 |
|
540 if( familycode == DS18S20_FAMILY_CODE ) { // 9 -> 12 bit if 18S20 |
|
541 /* Extended measurements for DS18S20 contributed by Carsten Foss */ |
|
542 measure &= (uint16_t)0xfffe; // Discard LSB, needed for later extended precicion calc |
|
543 measure <<= 3; // Convert to 12-bit, now degrees are in 1/16 degrees units |
|
544 measure += ( 16 - sp[6] ) - 4; // Add the compensation and remember to subtract 0.25 degree (4/16) |
|
545 } |
|
546 |
|
547 // check for negative |
|
548 if ( measure & 0x8000 ) { |
|
549 negative = 1; // mark negative |
|
550 measure ^= 0xffff; // convert to positive => (twos complement)++ |
|
551 measure++; |
|
552 } |
|
553 else { |
|
554 negative = 0; |
|
555 } |
|
556 |
|
557 // clear undefined bits for DS18B20 != 12bit resolution |
|
558 if ( familycode == DS18B20_FAMILY_CODE || familycode == DS1822_FAMILY_CODE ) { |
|
559 switch( sp[DS18B20_CONF_REG] & DS18B20_RES_MASK ) { |
|
560 case DS18B20_9_BIT: |
|
561 measure &= ~(DS18B20_9_BIT_UNDF); |
|
562 break; |
|
563 case DS18B20_10_BIT: |
|
564 measure &= ~(DS18B20_10_BIT_UNDF); |
|
565 break; |
|
566 case DS18B20_11_BIT: |
|
567 measure &= ~(DS18B20_11_BIT_UNDF); |
|
568 break; |
|
569 default: |
|
570 // 12 bit - all bits valid |
|
571 break; |
|
572 } |
|
573 } |
|
574 |
|
575 temperaturevalue = (measure >> 4); |
|
576 temperaturevalue *= 10000; |
|
577 temperaturevalue +=( measure & 0x000F ) * DS18X20_FRACCONV; |
|
578 |
|
579 if ( negative ) { |
|
580 temperaturevalue = -temperaturevalue; |
|
581 } |
|
582 |
|
583 return temperaturevalue; |
|
584 } |
|
585 |
|
586 uint8_t DS18X20_read_maxres( uint8_t id[], int32_t *temperaturevalue ) |
|
587 { |
|
588 uint8_t sp[DS18X20_SP_SIZE]; |
|
589 uint8_t ret; |
|
590 |
|
591 ow_reset(); |
|
592 ret = read_scratchpad( id, sp, DS18X20_SP_SIZE ); |
|
593 if ( ret == DS18X20_OK ) { |
|
594 *temperaturevalue = DS18X20_raw_to_maxres( id[0], sp ); |
|
595 } |
|
596 return ret; |
|
597 } |
|
598 |
|
599 uint8_t DS18X20_read_maxres_single( uint8_t familycode, int32_t *temperaturevalue ) |
|
600 { |
|
601 uint8_t sp[DS18X20_SP_SIZE]; |
|
602 uint8_t ret; |
|
603 |
|
604 ret = read_scratchpad( NULL, sp, DS18X20_SP_SIZE ); |
|
605 if ( ret == DS18X20_OK ) { |
|
606 *temperaturevalue = DS18X20_raw_to_maxres( familycode, sp ); |
|
607 } |
|
608 return ret; |
|
609 |
|
610 } |
|
611 |
|
612 uint8_t DS18X20_format_from_maxres( int32_t temperaturevalue, char str[], uint8_t n) |
|
613 { |
|
614 uint8_t sign = 0; |
|
615 char temp[10]; |
|
616 int8_t temp_loc = 0; |
|
617 uint8_t str_loc = 0; |
|
618 ldiv_t ldt; |
|
619 uint8_t ret; |
|
620 |
|
621 // range from -550000:-55.0000�C to 1250000:+125.0000�C -> min. 9+1 chars |
|
622 if ( n >= (9+1) && temperaturevalue > -1000000L && temperaturevalue < 10000000L ) { |
|
623 |
|
624 if ( temperaturevalue < 0) { |
|
625 sign = 1; |
|
626 temperaturevalue = -temperaturevalue; |
|
627 } |
|
628 |
|
629 do { |
|
630 ldt = ldiv( temperaturevalue, 10 ); |
|
631 temp[temp_loc++] = ldt.rem + '0'; |
|
632 temperaturevalue = ldt.quot; |
|
633 } while ( temperaturevalue > 0 ); |
|
634 |
|
635 // mk 20110209 |
|
636 if ((temp_loc < 4)&&(temp_loc > 1)) { |
|
637 temp[temp_loc++] = '0'; |
|
638 } // mk end |
|
639 |
|
640 if ( sign ) { |
|
641 temp[temp_loc] = '-'; |
|
642 } else { |
|
643 temp[temp_loc] = '+'; |
|
644 } |
|
645 |
|
646 while ( temp_loc >= 0 ) { |
|
647 str[str_loc++] = temp[(uint8_t)temp_loc--]; |
|
648 if ( temp_loc == 3 ) { |
|
649 str[str_loc++] = DS18X20_DECIMAL_CHAR; |
|
650 } |
|
651 } |
|
652 str[str_loc] = '\0'; |
|
653 |
|
654 ret = DS18X20_OK; |
|
655 } else { |
|
656 ret = DS18X20_ERROR; |
|
657 } |
|
658 |
|
659 return ret; |
|
660 } |
|
661 |
|
662 #endif /* DS18X20_MAX_RESOLUTION */ |
|
663 |
|
664 |
|
665 #if DS18X20_EEPROMSUPPORT |
|
666 |
|
667 uint8_t DS18X20_write_scratchpad( uint8_t id[], |
|
668 uint8_t th, uint8_t tl, uint8_t conf) |
|
669 { |
|
670 uint8_t ret; |
|
671 |
|
672 ow_reset(); |
|
673 if( ow_input_pin_state() ) { // only send if bus is "idle" = high |
|
674 ow_command( DS18X20_WRITE_SCRATCHPAD, id ); |
|
675 ow_byte_wr( th ); |
|
676 ow_byte_wr( tl ); |
|
677 if ( id[0] == DS18B20_FAMILY_CODE || id[0] == DS1822_FAMILY_CODE ) { |
|
678 ow_byte_wr( conf ); // config only available on DS18B20 and DS1822 |
|
679 } |
|
680 ret = DS18X20_OK; |
|
681 } |
|
682 else { |
|
683 uart_puts_P_verbose( "DS18X20_write_scratchpad: Short Circuit!\r" ); |
|
684 ret = DS18X20_ERROR; |
|
685 } |
|
686 |
|
687 return ret; |
|
688 } |
|
689 |
|
690 uint8_t DS18X20_read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n ) |
|
691 { |
|
692 uint8_t ret; |
|
693 |
|
694 ow_reset(); |
|
695 if( ow_input_pin_state() ) { // only send if bus is "idle" = high |
|
696 ret = read_scratchpad( id, sp, n ); |
|
697 } |
|
698 else { |
|
699 uart_puts_P_verbose( "DS18X20_read_scratchpad: Short Circuit!\r" ); |
|
700 ret = DS18X20_ERROR; |
|
701 } |
|
702 |
|
703 return ret; |
|
704 } |
|
705 |
|
706 uint8_t DS18X20_scratchpad_to_eeprom( uint8_t with_power_extern, |
|
707 uint8_t id[] ) |
|
708 { |
|
709 uint8_t ret; |
|
710 |
|
711 ow_reset(); |
|
712 if( ow_input_pin_state() ) { // only send if bus is "idle" = high |
|
713 if ( with_power_extern != DS18X20_POWER_EXTERN ) { |
|
714 ow_command_with_parasite_enable( DS18X20_COPY_SCRATCHPAD, id ); |
|
715 /* not longer needed: ow_parasite_enable(); */ |
|
716 } else { |
|
717 ow_command( DS18X20_COPY_SCRATCHPAD, id ); |
|
718 } |
|
719 _delay_ms(DS18X20_COPYSP_DELAY); // wait for 10 ms |
|
720 if ( with_power_extern != DS18X20_POWER_EXTERN ) { |
|
721 ow_parasite_disable(); |
|
722 } |
|
723 ret = DS18X20_OK; |
|
724 } |
|
725 else { |
|
726 uart_puts_P_verbose( "DS18X20_copy_scratchpad: Short Circuit!\r" ); |
|
727 ret = DS18X20_START_FAIL; |
|
728 } |
|
729 |
|
730 return ret; |
|
731 } |
|
732 |
|
733 uint8_t DS18X20_eeprom_to_scratchpad( uint8_t id[] ) |
|
734 { |
|
735 uint8_t ret; |
|
736 uint8_t retry_count=255; |
|
737 |
|
738 ow_reset(); |
|
739 if( ow_input_pin_state() ) { // only send if bus is "idle" = high |
|
740 ow_command( DS18X20_RECALL_E2, id ); |
|
741 while( retry_count-- && !( ow_bit_io( 1 ) ) ) { |
|
742 ; |
|
743 } |
|
744 if ( retry_count ) { |
|
745 ret = DS18X20_OK; |
|
746 } else { |
|
747 uart_puts_P_verbose( "DS18X20_recall_E2: timeout!\r" ); |
|
748 ret = DS18X20_ERROR; |
|
749 } |
|
750 } |
|
751 else { |
|
752 uart_puts_P_verbose( "DS18X20_recall_E2: Short Circuit!\r" ); |
|
753 ret = DS18X20_ERROR; |
|
754 } |
|
755 |
|
756 return ret; |
|
757 } |
|
758 |
|
759 #endif /* DS18X20_EEPROMSUPPORT */ |
|
760 |