diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ds18x20.c	Fri May 18 23:57:08 2012 +0800
@@ -0,0 +1,760 @@
+/*********************************************************************************
+Title:    DS18X20-Functions via One-Wire-Bus
+Author:   Martin Thomas <[email protected]>   
+          http://www.siwawi.arubi.uni-kl.de/avr-projects
+Software: avr-gcc 4.3.3 / avr-libc 1.6.7 (WinAVR 3/2010) 
+Hardware: any AVR - tested with ATmega16/ATmega32/ATmega324P and 3 DS18B20
+
+Partly based on code from Peter Dannegger and others.
+
+changelog:
+20041124 - Extended measurements for DS18(S)20 contributed by Carsten Foss (CFO)
+200502xx - function DS18X20_read_meas_single
+20050310 - DS18x20 EEPROM functions (can be disabled to save flash-memory)
+           (DS18X20_EEPROMSUPPORT in ds18x20.h)
+20100625 - removed inner returns, added static function for read scratchpad
+         . replaced full-celcius and fractbit method with decicelsius
+           and maxres (degreeCelsius*10e-4) functions, renamed eeprom-functions,
+           delay in recall_e2 replaced by timeout-handling
+20100714 - ow_command_skip_last_recovery used for parasite-powerd devices so the
+           strong pull-up can be enabled in time even with longer OW recovery times
+20110209 - fix in DS18X20_format_from_maxres() by Marian Kulesza
+**********************************************************************************/
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+
+#include "ds18x20.h"
+#include "onewire.h"
+#include "crc8.h"
+
+#if DS18X20_EEPROMSUPPORT
+// for 10ms delay in copy scratchpad
+#include <util/delay.h>
+#endif /* DS18X20_EEPROMSUPPORT */
+
+/*----------- start of "debug-functions" ---------------*/
+
+#if DS18X20_VERBOSE
+#if (!DS18X20_DECICELSIUS)
+#error "DS18X20_DECICELSIUS must be enabled for verbose-mode"
+#endif
+
+/* functions for debugging-output - undef DS18X20_VERBOSE in .h
+   if you run out of program-memory */
+#include <string.h>
+#include "uart.h"
+#include "uart_addon.h"
+
+static int16_t DS18X20_raw_to_decicelsius( uint8_t fc, uint8_t sp[] );
+
+void DS18X20_show_id_uart( uint8_t *id, size_t n )
+{
+	size_t i;
+
+	for( i = 0; i < n; i++ ) {
+		if ( i == 0 ) { uart_puts_P( "FC:" ); }
+		else if ( i == n-1 ) { uart_puts_P( "CRC:" ); }
+		if ( i == 1 ) { uart_puts_P( "SN: " ); }
+		uart_puthex_byte(id[i]);
+		uart_puts_P(" ");
+		if ( i == 0 ) {
+			if ( id[0] == DS18S20_FAMILY_CODE ) { uart_puts_P ("(18S)"); }
+			else if ( id[0] == DS18B20_FAMILY_CODE ) { uart_puts_P ("(18B)"); }
+			else if ( id[0] == DS1822_FAMILY_CODE ) { uart_puts_P ("(22)"); }
+			else { uart_puts_P ("( ? )"); }
+		}
+	}
+	if ( crc8( id, OW_ROMCODE_SIZE) )
+		uart_puts_P( " CRC FAIL " );
+	else 
+		uart_puts_P( " CRC O.K. " );
+}
+
+static void show_sp_uart( uint8_t *sp, size_t n )
+{
+	size_t i;
+
+	uart_puts_P( "SP:" );
+	for( i = 0; i < n; i++ ) {
+		if ( i == n-1 ) { uart_puts_P( "CRC:" ); }
+		uart_puthex_byte(sp[i]);
+		uart_puts_P(" ");
+	}
+}
+
+/* 
+   convert raw value from DS18x20 to Celsius
+   input is: 
+   - familycode fc (0x10/0x28 see header)
+   - scratchpad-buffer
+   output is:
+   - cel full celsius
+   - fractions of celsius in millicelsius*(10^-1)/625 (the 4 LS-Bits)
+   - subzero =0 positiv / 1 negativ
+   always returns  DS18X20_OK
+*/
+static uint8_t DS18X20_meas_to_cel( uint8_t fc, uint8_t *sp, 
+	uint8_t* subzero, uint8_t* cel, uint8_t* cel_frac_bits)
+{
+	uint16_t meas;
+	uint8_t  i;
+	
+	meas = sp[0];  // LSB
+	meas |= ( (uint16_t)sp[1] ) << 8; // MSB
+	
+	//  only work on 12bit-base
+	if( fc == DS18S20_FAMILY_CODE ) { // 9 -> 12 bit if 18S20
+		/* Extended res. measurements for DS18S20 contributed by Carsten Foss */
+		meas &= (uint16_t) 0xfffe;    // Discard LSB, needed for later extended precicion calc
+		meas <<= 3;                   // Convert to 12-bit, now degrees are in 1/16 degrees units
+		meas += ( 16 - sp[6] ) - 4;   // Add the compensation and remember to subtract 0.25 degree (4/16)
+	}
+	
+	// check for negative 
+	if ( meas & 0x8000 )  {
+		*subzero=1;      // mark negative
+		meas ^= 0xffff;  // convert to positive => (twos complement)++
+		meas++;
+	}
+	else {
+		*subzero=0;
+	}
+	
+	// clear undefined bits for B != 12bit
+	if ( fc == DS18B20_FAMILY_CODE || fc == DS1822_FAMILY_CODE ) {
+		i = sp[DS18B20_CONF_REG];
+		if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) { ; }
+		else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT ) {
+			meas &= ~(DS18B20_11_BIT_UNDF);
+		} else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT ) {
+			meas &= ~(DS18B20_10_BIT_UNDF);
+		} else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) { 
+			meas &= ~(DS18B20_9_BIT_UNDF);
+		}
+	}
+	
+	*cel  = (uint8_t)(meas >> 4); 
+	*cel_frac_bits = (uint8_t)(meas & 0x000F);
+	
+	return DS18X20_OK;
+}
+
+static void DS18X20_uart_put_temp(const uint8_t subzero, 
+	const uint8_t cel, const uint8_t cel_frac_bits)
+{
+	char buffer[sizeof(int)*8+1];
+	size_t i;
+	
+	uart_putc((subzero)?'-':'+');
+	uart_put_int((int)cel);
+	uart_puts_P(".");
+	itoa(cel_frac_bits*DS18X20_FRACCONV,buffer,10);
+	for ( i = 0; i < 4-strlen(buffer); i++ ) {
+		uart_puts_P("0");
+	}
+	uart_puts(buffer);
+	uart_puts_P("�C");
+}
+
+/* verbose output rom-search follows read-scratchpad in one loop */
+uint8_t DS18X20_read_meas_all_verbose( void )
+{
+	uint8_t id[OW_ROMCODE_SIZE], sp[DS18X20_SP_SIZE], diff;
+	uint8_t i;
+	uint16_t meas;
+	int16_t decicelsius;
+	char s[10];
+	uint8_t subzero, cel, cel_frac_bits;
+	
+	for( diff = OW_SEARCH_FIRST; diff != OW_LAST_DEVICE; )
+	{
+		diff = ow_rom_search( diff, &id[0] );
+
+		if( diff == OW_PRESENCE_ERR ) {
+			uart_puts_P( "No Sensor found\r" );
+			return OW_PRESENCE_ERR; // <--- early exit!
+		}
+		
+		if( diff == OW_DATA_ERR ) {
+			uart_puts_P( "Bus Error\r" );
+			return OW_DATA_ERR;     // <--- early exit!
+		}
+		
+		DS18X20_show_id_uart( id, OW_ROMCODE_SIZE );
+		
+		if( id[0] == DS18B20_FAMILY_CODE || id[0] == DS18S20_FAMILY_CODE ||
+		    id[0] == DS1822_FAMILY_CODE ) { 
+			// temperature sensor
+			
+			uart_putc ('\r');
+			
+			ow_byte_wr( DS18X20_READ );           // read command
+			
+			for ( i=0 ; i< DS18X20_SP_SIZE; i++ ) {
+				sp[i]=ow_byte_rd();
+			}
+			
+			show_sp_uart( sp, DS18X20_SP_SIZE );
+
+			if ( crc8( &sp[0], DS18X20_SP_SIZE ) ) {
+				uart_puts_P( " CRC FAIL " );
+			} else {
+				uart_puts_P( " CRC O.K. " );
+			}
+			uart_putc ('\r');
+		
+			meas = sp[0]; // LSB Temp. from Scrachpad-Data
+			meas |= (uint16_t) (sp[1] << 8); // MSB
+			
+			uart_puts_P( " T_raw=");
+			uart_puthex_byte( (uint8_t)(meas >> 8) );
+			uart_puthex_byte( (uint8_t)meas );
+			uart_puts_P( " " );
+
+			if( id[0] == DS18S20_FAMILY_CODE ) { // 18S20
+				uart_puts_P( "S20/09" );
+			}
+			else if ( id[0] == DS18B20_FAMILY_CODE ||
+			          id[0] == DS1822_FAMILY_CODE ) { // 18B20 or 1822
+				i=sp[DS18B20_CONF_REG];
+				if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) {
+					uart_puts_P( "B20/12" );
+				}
+				else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT ) {
+					uart_puts_P( "B20/11" );
+				}
+				else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT ) {
+					uart_puts_P( " B20/10 " );
+				}
+				else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) { 
+					uart_puts_P( "B20/09" );
+				}
+			}			
+			uart_puts_P(" ");
+			
+			DS18X20_meas_to_cel( id[0], sp, &subzero, &cel, &cel_frac_bits );
+			DS18X20_uart_put_temp( subzero, cel, cel_frac_bits );
+
+			decicelsius = DS18X20_raw_to_decicelsius( id[0], sp );
+			if ( decicelsius == DS18X20_INVALID_DECICELSIUS ) {
+				uart_puts_P("* INVALID *");
+			} else {
+				uart_puts_P(" conv: ");
+				uart_put_int(decicelsius);
+				uart_puts_P(" deci�C ");
+				DS18X20_format_from_decicelsius( decicelsius, s, 10 );
+				uart_puts_P(" fmt: ");
+				uart_puts(s);
+				uart_puts_P(" �C ");
+			}
+
+			uart_puts("\r");
+			
+		} // if meas-sensor
+		
+	} // loop all sensors
+	
+	uart_puts_P( "\r" );
+	
+	return DS18X20_OK;
+}
+
+#endif /* DS18X20_VERBOSE */
+
+#if DS18X20_VERBOSE
+#define uart_puts_P_verbose(s__) uart_puts_P(s__)
+#else 
+#define uart_puts_P_verbose(s__)
+#endif
+
+
+/*----------- end of "debug-functions" ---------------*/
+
+
+/* find DS18X20 Sensors on 1-Wire-Bus
+   input/ouput: diff is the result of the last rom-search
+                *diff = OW_SEARCH_FIRST for first call
+   output: id is the rom-code of the sensor found */
+uint8_t DS18X20_find_sensor( uint8_t *diff, uint8_t id[] )
+{
+	uint8_t go;
+	uint8_t ret;
+
+	ret = DS18X20_OK;
+	go = 1;
+	do {
+		*diff = ow_rom_search( *diff, &id[0] );
+		if ( *diff == OW_PRESENCE_ERR || *diff == OW_DATA_ERR ||
+		     *diff == OW_LAST_DEVICE ) { 
+			go  = 0;
+			ret = DS18X20_ERROR;
+		} else {
+			if ( id[0] == DS18B20_FAMILY_CODE || id[0] == DS18S20_FAMILY_CODE ||
+			     id[0] == DS1822_FAMILY_CODE ) { 
+				go = 0;
+			}
+		}
+	} while (go);
+
+	return ret;
+}
+
+/* get power status of DS18x20 
+   input:   id = rom_code 
+   returns: DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE */
+uint8_t DS18X20_get_power_status( uint8_t id[] )
+{
+	uint8_t pstat;
+
+	ow_reset();
+	ow_command( DS18X20_READ_POWER_SUPPLY, id );
+	pstat = ow_bit_io( 1 );
+	ow_reset();
+	return ( pstat ) ? DS18X20_POWER_EXTERN : DS18X20_POWER_PARASITE;
+}
+
+/* start measurement (CONVERT_T) for all sensors if input id==NULL 
+   or for single sensor where id is the rom-code */
+uint8_t DS18X20_start_meas( uint8_t with_power_extern, uint8_t id[])
+{
+	uint8_t ret;
+
+	ow_reset();
+	if( ow_input_pin_state() ) { // only send if bus is "idle" = high
+		if ( with_power_extern != DS18X20_POWER_EXTERN ) {
+			ow_command_with_parasite_enable( DS18X20_CONVERT_T, id );
+			/* not longer needed: ow_parasite_enable(); */
+		} else {
+			ow_command( DS18X20_CONVERT_T, id );
+		}
+		ret = DS18X20_OK;
+	} 
+	else { 
+		uart_puts_P_verbose( "DS18X20_start_meas: Short Circuit!\r" );
+		ret = DS18X20_START_FAIL;
+	}
+
+	return ret;
+}
+
+// returns 1 if conversion is in progress, 0 if finished
+// not available when parasite powered.
+uint8_t DS18X20_conversion_in_progress(void)
+{
+	return ow_bit_io( 1 ) ? DS18X20_CONVERSION_DONE : DS18X20_CONVERTING;
+}
+
+static uint8_t read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n )
+{
+	uint8_t i;
+	uint8_t ret;
+
+	ow_command( DS18X20_READ, id );
+	for ( i = 0; i < n; i++ ) {
+		sp[i] = ow_byte_rd();
+	}
+	if ( crc8( &sp[0], DS18X20_SP_SIZE ) ) {
+		ret = DS18X20_ERROR_CRC;
+	} else {
+		ret = DS18X20_OK;
+	}
+
+	return ret;
+}
+
+
+#if DS18X20_DECICELSIUS
+
+/* convert scratchpad data to physical value in unit decicelsius */
+static int16_t DS18X20_raw_to_decicelsius( uint8_t familycode, uint8_t sp[] )
+{
+	uint16_t measure;
+	uint8_t  negative;
+	int16_t  decicelsius;
+	uint16_t fract;
+
+	measure = sp[0] | (sp[1] << 8);
+	//measure = 0xFF5E; // test -10.125
+	//measure = 0xFE6F; // test -25.0625
+
+	if( familycode == DS18S20_FAMILY_CODE ) {   // 9 -> 12 bit if 18S20
+		/* Extended measurements for DS18S20 contributed by Carsten Foss */
+		measure &= (uint16_t)0xfffe;   // Discard LSB, needed for later extended precicion calc
+		measure <<= 3;                 // Convert to 12-bit, now degrees are in 1/16 degrees units
+		measure += (16 - sp[6]) - 4;   // Add the compensation and remember to subtract 0.25 degree (4/16)
+	}
+
+	// check for negative 
+	if ( measure & 0x8000 )  {
+		negative = 1;       // mark negative
+		measure ^= 0xffff;  // convert to positive => (twos complement)++
+		measure++;
+	}
+	else {
+		negative = 0;
+	}
+
+	// clear undefined bits for DS18B20 != 12bit resolution
+	if ( familycode == DS18B20_FAMILY_CODE || familycode == DS1822_FAMILY_CODE ) {
+		switch( sp[DS18B20_CONF_REG] & DS18B20_RES_MASK ) {
+		case DS18B20_9_BIT:
+			measure &= ~(DS18B20_9_BIT_UNDF);
+			break;
+		case DS18B20_10_BIT:
+			measure &= ~(DS18B20_10_BIT_UNDF);
+			break;
+		case DS18B20_11_BIT:
+			measure &= ~(DS18B20_11_BIT_UNDF);
+			break;
+		default:
+			// 12 bit - all bits valid
+			break;
+		}
+	}
+
+	decicelsius = (measure >> 4);
+	decicelsius *= 10;
+
+	// decicelsius += ((measure & 0x000F) * 640 + 512) / 1024;
+	// 625/1000 = 640/1024
+	fract = ( measure & 0x000F ) * 640;
+	if ( !negative ) {
+		fract += 512;
+	}
+	fract /= 1024;
+	decicelsius += fract;
+
+	if ( negative ) {
+		decicelsius = -decicelsius;
+	}
+
+	if ( /* decicelsius == 850 || */ decicelsius < -550 || decicelsius > 1250 ) {
+		return DS18X20_INVALID_DECICELSIUS;
+	} else {
+		return decicelsius;
+	}
+}
+
+/* format decicelsius-value into string, itoa method inspired 
+   by code from Chris Takahashi for the MSP430 libc, BSD-license 
+   modifications mthomas: variable-types, fixed radix 10, use div(), 
+   insert decimal-point */
+uint8_t DS18X20_format_from_decicelsius( int16_t decicelsius, char str[], uint8_t n)
+{
+	uint8_t sign = 0;
+	char temp[7];
+	int8_t temp_loc = 0;
+	uint8_t str_loc = 0;
+	div_t dt;
+	uint8_t ret;
+
+	// range from -550:-55.0�C to 1250:+125.0�C -> min. 6+1 chars
+	if ( n >= (6+1) && decicelsius > -1000 && decicelsius < 10000 ) {
+
+		if ( decicelsius < 0) {
+			sign = 1;
+			decicelsius = -decicelsius;
+		}
+
+		// construct a backward string of the number.
+		do {
+			dt = div(decicelsius,10);
+			temp[temp_loc++] = dt.rem + '0';
+			decicelsius = dt.quot;
+		} while ( decicelsius > 0 );
+
+		if ( sign ) {
+			temp[temp_loc] = '-';
+		} else {
+			///temp_loc--;
+			temp[temp_loc] = '+';
+		}
+
+		// reverse the string.into the output
+		while ( temp_loc >=0 ) {
+			str[str_loc++] = temp[(uint8_t)temp_loc--];
+			if ( temp_loc == 0 ) {
+				str[str_loc++] = DS18X20_DECIMAL_CHAR;
+			}
+		}
+		str[str_loc] = '\0';
+
+		ret = DS18X20_OK;
+	} else {
+		ret = DS18X20_ERROR;
+	}
+	
+	return ret;
+}
+
+/* reads temperature (scratchpad) of sensor with rom-code id
+   output: decicelsius 
+   returns DS18X20_OK on success */
+uint8_t DS18X20_read_decicelsius( uint8_t id[], int16_t *decicelsius )
+{
+	uint8_t sp[DS18X20_SP_SIZE];
+	uint8_t ret;
+	
+	ow_reset();
+	ret = read_scratchpad( id, sp, DS18X20_SP_SIZE );
+	if ( ret == DS18X20_OK ) {
+		*decicelsius = DS18X20_raw_to_decicelsius( id[0], sp );
+	}
+	return ret;
+}
+
+/* reads temperature (scratchpad) of sensor without id (single sensor)
+   output: decicelsius 
+   returns DS18X20_OK on success */
+uint8_t DS18X20_read_decicelsius_single( uint8_t familycode, int16_t *decicelsius )
+{
+	uint8_t sp[DS18X20_SP_SIZE];
+	uint8_t ret;
+	
+	ret = read_scratchpad( NULL, sp, DS18X20_SP_SIZE );
+	if ( ret == DS18X20_OK ) {
+		*decicelsius = DS18X20_raw_to_decicelsius( familycode, sp );
+	}
+	return ret;
+}
+
+#endif /* DS18X20_DECICELSIUS */
+
+
+#if DS18X20_MAX_RESOLUTION
+
+static int32_t DS18X20_raw_to_maxres( uint8_t familycode, uint8_t sp[] )
+{
+	uint16_t measure;
+	uint8_t  negative;
+	int32_t  temperaturevalue;
+
+	measure = sp[0] | (sp[1] << 8);
+	//measure = 0xFF5E; // test -10.125
+	//measure = 0xFE6F; // test -25.0625
+
+	if( familycode == DS18S20_FAMILY_CODE ) {   // 9 -> 12 bit if 18S20
+		/* Extended measurements for DS18S20 contributed by Carsten Foss */
+		measure &= (uint16_t)0xfffe;   // Discard LSB, needed for later extended precicion calc
+		measure <<= 3;                 // Convert to 12-bit, now degrees are in 1/16 degrees units
+		measure += ( 16 - sp[6] ) - 4; // Add the compensation and remember to subtract 0.25 degree (4/16)
+	}
+
+	// check for negative 
+	if ( measure & 0x8000 )  {
+		negative = 1;       // mark negative
+		measure ^= 0xffff;  // convert to positive => (twos complement)++
+		measure++;
+	}
+	else {
+		negative = 0;
+	}
+
+	// clear undefined bits for DS18B20 != 12bit resolution
+	if ( familycode == DS18B20_FAMILY_CODE || familycode == DS1822_FAMILY_CODE ) {
+		switch( sp[DS18B20_CONF_REG] & DS18B20_RES_MASK ) {
+		case DS18B20_9_BIT:
+			measure &= ~(DS18B20_9_BIT_UNDF);
+			break;
+		case DS18B20_10_BIT:
+			measure &= ~(DS18B20_10_BIT_UNDF);
+			break;
+		case DS18B20_11_BIT:
+			measure &= ~(DS18B20_11_BIT_UNDF);
+			break;
+		default:
+			// 12 bit - all bits valid
+			break;
+		}
+	}
+
+	temperaturevalue  = (measure >> 4);
+	temperaturevalue *= 10000;
+	temperaturevalue +=( measure & 0x000F ) * DS18X20_FRACCONV;
+
+	if ( negative ) {
+		temperaturevalue = -temperaturevalue;
+	}
+
+	return temperaturevalue;
+}
+
+uint8_t DS18X20_read_maxres( uint8_t id[], int32_t *temperaturevalue )
+{
+	uint8_t sp[DS18X20_SP_SIZE];
+	uint8_t ret;
+	
+	ow_reset();
+	ret = read_scratchpad( id, sp, DS18X20_SP_SIZE );
+	if ( ret == DS18X20_OK ) {
+		*temperaturevalue = DS18X20_raw_to_maxres( id[0], sp );
+	}
+	return ret;
+}
+
+uint8_t DS18X20_read_maxres_single( uint8_t familycode, int32_t *temperaturevalue )
+{
+	uint8_t sp[DS18X20_SP_SIZE];
+	uint8_t ret;
+	
+	ret = read_scratchpad( NULL, sp, DS18X20_SP_SIZE );
+	if ( ret == DS18X20_OK ) {
+		*temperaturevalue = DS18X20_raw_to_maxres( familycode, sp );
+	}
+	return ret;
+
+}
+
+uint8_t DS18X20_format_from_maxres( int32_t temperaturevalue, char str[], uint8_t n)
+{
+	uint8_t sign = 0;
+	char temp[10];
+	int8_t temp_loc = 0;
+	uint8_t str_loc = 0;
+	ldiv_t ldt;
+	uint8_t ret;
+
+	// range from -550000:-55.0000�C to 1250000:+125.0000�C -> min. 9+1 chars
+	if ( n >= (9+1) && temperaturevalue > -1000000L && temperaturevalue < 10000000L ) {
+
+		if ( temperaturevalue < 0) {
+			sign = 1;
+			temperaturevalue = -temperaturevalue;
+		}
+
+		do {
+			ldt = ldiv( temperaturevalue, 10 );
+			temp[temp_loc++] = ldt.rem + '0';
+			temperaturevalue = ldt.quot;
+		} while ( temperaturevalue > 0 );
+		
+		// mk 20110209
+		if ((temp_loc < 4)&&(temp_loc > 1)) {
+			temp[temp_loc++] = '0';
+		} // mk end
+
+		if ( sign ) {
+			temp[temp_loc] = '-';
+		} else {
+			temp[temp_loc] = '+';
+		}
+
+		while ( temp_loc >= 0 ) {
+			str[str_loc++] = temp[(uint8_t)temp_loc--];
+			if ( temp_loc == 3 ) {
+				str[str_loc++] = DS18X20_DECIMAL_CHAR;
+			}
+		}
+		str[str_loc] = '\0';
+
+		ret = DS18X20_OK;
+	} else {
+		ret = DS18X20_ERROR;
+	}
+	
+	return ret;
+}
+
+#endif /* DS18X20_MAX_RESOLUTION */
+
+
+#if DS18X20_EEPROMSUPPORT
+
+uint8_t DS18X20_write_scratchpad( uint8_t id[], 
+	uint8_t th, uint8_t tl, uint8_t conf)
+{
+	uint8_t ret;
+
+	ow_reset();
+	if( ow_input_pin_state() ) { // only send if bus is "idle" = high
+		ow_command( DS18X20_WRITE_SCRATCHPAD, id );
+		ow_byte_wr( th );
+		ow_byte_wr( tl );
+		if ( id[0] == DS18B20_FAMILY_CODE || id[0] == DS1822_FAMILY_CODE ) {
+			ow_byte_wr( conf ); // config only available on DS18B20 and DS1822
+		}
+		ret = DS18X20_OK;
+	} 
+	else { 
+		uart_puts_P_verbose( "DS18X20_write_scratchpad: Short Circuit!\r" );
+		ret = DS18X20_ERROR;
+	}
+
+	return ret;
+}
+
+uint8_t DS18X20_read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n )
+{
+	uint8_t ret;
+
+	ow_reset();
+	if( ow_input_pin_state() ) { // only send if bus is "idle" = high
+		ret = read_scratchpad( id, sp, n );
+	} 
+	else {
+		uart_puts_P_verbose( "DS18X20_read_scratchpad: Short Circuit!\r" );
+		ret = DS18X20_ERROR;
+	}
+
+	return ret;
+}
+
+uint8_t DS18X20_scratchpad_to_eeprom( uint8_t with_power_extern, 
+	uint8_t id[] )
+{
+	uint8_t ret;
+
+	ow_reset();
+	if( ow_input_pin_state() ) { // only send if bus is "idle" = high
+		if ( with_power_extern != DS18X20_POWER_EXTERN ) {
+			ow_command_with_parasite_enable( DS18X20_COPY_SCRATCHPAD, id );
+			/* not longer needed: ow_parasite_enable(); */
+		} else {
+			ow_command( DS18X20_COPY_SCRATCHPAD, id );
+		}
+		_delay_ms(DS18X20_COPYSP_DELAY); // wait for 10 ms 
+		if ( with_power_extern != DS18X20_POWER_EXTERN ) {
+			ow_parasite_disable();
+		}
+		ret = DS18X20_OK;
+	} 
+	else { 
+		uart_puts_P_verbose( "DS18X20_copy_scratchpad: Short Circuit!\r" );
+		ret = DS18X20_START_FAIL;
+	}
+
+	return ret;
+}
+
+uint8_t DS18X20_eeprom_to_scratchpad( uint8_t id[] )
+{
+	uint8_t ret;
+	uint8_t retry_count=255;
+
+	ow_reset();
+	if( ow_input_pin_state() ) { // only send if bus is "idle" = high
+		ow_command( DS18X20_RECALL_E2, id );
+		while( retry_count-- && !( ow_bit_io( 1 ) ) ) { 
+			;
+		}
+		if ( retry_count ) {
+			ret = DS18X20_OK;
+		} else {
+			uart_puts_P_verbose( "DS18X20_recall_E2: timeout!\r" );
+			ret = DS18X20_ERROR;
+		}
+	} 
+	else { 
+		uart_puts_P_verbose( "DS18X20_recall_E2: Short Circuit!\r" );
+		ret = DS18X20_ERROR;
+	}
+
+	return ret;
+}
+
+#endif /* DS18X20_EEPROMSUPPORT */
+