Mercurial > templog
view simple_ds18b20.c @ 322:840f51824254
untested, add comms timeout code
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Mon, 21 May 2012 07:52:51 +0800 |
parents | 9621436cfa07 |
children | 878be5e353a0 |
line wrap: on
line source
// Matt Johnston 2012 // Based on ds18x20.c by Martin Thomas, in turn based on code by // Peter // Dannegger and others. // #include <stdio.h> #include <avr/pgmspace.h> #include "ds18x20.h" #include "onewire.h" #include "crc8.h" #include "simple_ds18b20.h" uint8_t simple_ds18b20_start_meas(uint8_t id[]) { uint8_t ret; ow_reset(); if( ow_input_pin_state() ) { // only send if bus is "idle" = high ow_command_with_parasite_enable(DS18X20_CONVERT_T, id); ret = DS18X20_OK; } else { ret = DS18X20_START_FAIL; } return ret; } 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; } static int16_t ds18b20_raw_to_decicelsius( 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 // 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 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; } } uint8_t simple_ds18b20_read_decicelsius( uint8_t id[], int16_t *decicelsius ) { uint8_t sp[DS18X20_SP_SIZE]; uint8_t ret; if (id) { ow_reset(); } ret = read_scratchpad( id, sp, DS18X20_SP_SIZE ); if ( ret == DS18X20_OK ) { *decicelsius = ds18b20_raw_to_decicelsius( sp ); } return ret; } static void printhex_nibble(const unsigned char b) { unsigned char c = b & 0x0f; if ( c > 9 ) { c += 'A'-10; } else { c += '0'; } putchar(c); } void printhex_byte( const unsigned char b ) { printhex_nibble( b >> 4 ); printhex_nibble( b ); } void printhex(uint8_t *id, uint8_t n) { for (uint8_t i = 0; i < n; i++) { if (i > 0) { putchar(' '); } printhex_byte(id[i]); } } uint8_t simple_ds18b20_read_all() { uint8_t id[OW_ROMCODE_SIZE]; for( uint8_t diff = OW_SEARCH_FIRST; diff != OW_LAST_DEVICE; ) { diff = ow_rom_search( diff, &id[0] ); if( diff == OW_PRESENCE_ERR ) { printf_P( PSTR("No Sensor found\r") ); return OW_PRESENCE_ERR; // <--- early exit! } if( diff == OW_DATA_ERR ) { printf_P( PSTR("Bus Error\r") ); return OW_DATA_ERR; // <--- early exit! } int16_t decicelsius; uint8_t ret = simple_ds18b20_read_decicelsius(NULL, &decicelsius); if (ret != DS18X20_OK) { printf_P(PSTR("Failed reading\r")); return OW_DATA_ERR; } printf_P(PSTR("DS18B20 %d: "), diff); if (crc8(id, OW_ROMCODE_SIZE)) { printf_P(PSTR("CRC fail")); } printhex(id, OW_ROMCODE_SIZE); printf_P(PSTR(" %d.%d ÂșC\n"), decicelsius/10, decicelsius % 10); } printf_P(PSTR("Done sensors\n")); return DS18X20_OK; }