Mercurial > templog
comparison ds18x20.c @ 9:7da9a3f23592
Import ds18x20 code
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 18 May 2012 23:57:08 +0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
8:c55321727d02 | 9:7da9a3f23592 |
---|---|
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 |