Mercurial > templog
changeset 315:7d409dded901
Import ds18x20 code
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 18 May 2012 23:57:08 +0800 |
parents | 7aebb1452422 |
children | 8f32eb67a279 |
files | Makefile crc8.c crc8.h crc8.o diskio.h ds18x20.c ds18x20.h main.c onewire.h uart_addon.c uart_addon.h |
diffstat | 11 files changed, 1359 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Fri May 18 20:38:40 2012 +0800 +++ b/Makefile Fri May 18 23:57:08 2012 +0800 @@ -19,12 +19,18 @@ DEVICE = atmega328 PROGDEVICE = atmega328p -CLOCK = 1000000 +CLOCK = 2000000 PROGRAMMER = #-c stk500v2 -P avrdoper PROGRAMMER = -c stk500 -P ~/dev/stk500 -p $(PROGDEVICE) -OBJECTS = main.o #ff.o mmc.o onewire.o +OBJS_1WIRE = onewire.o ds18x20.o uart_addon.o crc8.o +OBJS_SD = ff.o mmc.o +OBJECTS = main.o +OBJECTS += $(OBJS_1WIRE) +#OBJECTS += OBJS_SD LIBS = -lm -FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m + +# default but 2mhz +FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x62:m # ATMega8 fuse bits used above (fuse bits for other devices are different!): # Example for 8 MHz internal oscillator @@ -33,17 +39,17 @@ # ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 # | | | | | +-------- BOOTSZ1 # | | | | +---------- EESAVE (set to 0 to preserve EEPROM over chip erase) -# | | | +-------------- CKOPT (clock option, depends on oscillator type) +# | | | +-------------- WDTON # | | +---------------- SPIEN (if set to 1, serial programming is disabled) -# | +------------------ WDTON (if set to 0, watchdog is always on) +# | +------------------ DWEN # +-------------------- RSTDISBL (if set to 0, RESET pin is disabled) # Fuse low byte: -# 0x24 = 0 0 1 0 0 1 0 0 +# 0x62 = 0 1 1 0 0 0 1 0 # ^ ^ \ / \--+--/ # | | | +------- CKSEL 3..0 (8M internal RC) # | | +--------------- SUT 1..0 (slowly rising power) -# | +------------------ BODEN (if 0, brown-out detector is enabled) -# +-------------------- BODLEVEL (if 0: 4V, if 1: 2.7V) +# | +------------------ CKOUT +# +-------------------- CLKDIV8 # # For computing fuse byte values for other devices and options see # the fuse bit calculator at http://www.engbedded.com/fusecalc/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc8.c Fri May 18 23:57:08 2012 +0800 @@ -0,0 +1,63 @@ +/* please read copyright-notice at EOF */ + +#include <stdint.h> + +#define CRC8INIT 0x00 +#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0 + +uint8_t crc8( uint8_t *data, uint16_t number_of_bytes_in_data ) +{ + uint8_t crc; + uint16_t loop_count; + uint8_t bit_counter; + uint8_t b; + uint8_t feedback_bit; + + crc = CRC8INIT; + + for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++) + { + b = data[loop_count]; + + bit_counter = 8; + do { + feedback_bit = (crc ^ b) & 0x01; + + if ( feedback_bit == 0x01 ) { + crc = crc ^ CRC8POLY; + } + crc = (crc >> 1) & 0x7F; + if ( feedback_bit == 0x01 ) { + crc = crc | 0x80; + } + + b = b >> 1; + bit_counter--; + + } while (bit_counter > 0); + } + + return crc; +} + +/* +This code is from Colin O'Flynn - Copyright (c) 2002 +only minor changes by M.Thomas 9/2004 + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc8.h Fri May 18 23:57:08 2012 +0800 @@ -0,0 +1,40 @@ +#ifndef CRC8_H_ +#define CRC8_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +uint8_t crc8( uint8_t* data, uint16_t number_of_bytes_in_data ); + +#ifdef __cplusplus +} +#endif + +#endif + +/* +This is based on code from : + +Copyright (c) 2002 Colin O'Flynn + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/diskio.h Fri May 18 23:57:08 2012 +0800 @@ -0,0 +1,74 @@ +/*----------------------------------------------------------------------- +/ Low level disk interface modlue include file (C)ChaN, 2010 +/-----------------------------------------------------------------------*/ + +#ifndef _DISKIO + +#define _READONLY 0 /* 1: Remove write functions */ +#define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */ + +#include "integer.h" + + +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + +DSTATUS disk_initialize (BYTE); +DSTATUS disk_status (BYTE); +DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE); +#if _READONLY == 0 +DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE); +#endif +DRESULT disk_ioctl (BYTE, BYTE, void*); +void disk_timerproc (void); + + + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic command (mandatory for FatFs) */ +#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */ +#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */ + +/* Generic command */ +#define CTRL_POWER 4 /* Get/Set power status */ +#define CTRL_LOCK 5 /* Lock/Unlock media removal */ +#define CTRL_EJECT 6 /* Eject media */ + +/* MMC/SDC command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ + +/* ATA/CF command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + + +#define _DISKIO +#endif
--- /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 */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ds18x20.h Fri May 18 23:57:08 2012 +0800 @@ -0,0 +1,140 @@ +#ifndef DS18X20_H_ +#define DS18X20_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdint.h> + +// DS18x20 EERPROM support disabled(0) or enabled(1) : +#define DS18X20_EEPROMSUPPORT 1 +// decicelsius functions disabled(0) or enabled(1): +#define DS18X20_DECICELSIUS 1 +// max. resolution functions disabled(0) or enabled(1): +#define DS18X20_MAX_RESOLUTION 1 +// extended output via UART disabled(0) or enabled(1) : +#define DS18X20_VERBOSE 1 + + +/* return values */ +#define DS18X20_OK 0x00 +#define DS18X20_ERROR 0x01 +#define DS18X20_START_FAIL 0x02 +#define DS18X20_ERROR_CRC 0x03 + +#define DS18X20_INVALID_DECICELSIUS 2000 + +#define DS18X20_POWER_PARASITE 0x00 +#define DS18X20_POWER_EXTERN 0x01 + +#define DS18X20_CONVERSION_DONE 0x00 +#define DS18X20_CONVERTING 0x01 + +/* DS18X20 specific values (see datasheet) */ +#define DS18S20_FAMILY_CODE 0x10 +#define DS18B20_FAMILY_CODE 0x28 +#define DS1822_FAMILY_CODE 0x22 + +#define DS18X20_CONVERT_T 0x44 +#define DS18X20_READ 0xBE +#define DS18X20_WRITE 0x4E +#define DS18X20_EE_WRITE 0x48 +#define DS18X20_EE_RECALL 0xB8 +#define DS18X20_READ_POWER_SUPPLY 0xB4 + +#define DS18B20_CONF_REG 4 +#define DS18B20_9_BIT 0 +#define DS18B20_10_BIT (1<<5) +#define DS18B20_11_BIT (1<<6) +#define DS18B20_12_BIT ((1<<6)|(1<<5)) +#define DS18B20_RES_MASK ((1<<6)|(1<<5)) + +// undefined bits in LSB if 18B20 != 12bit +#define DS18B20_9_BIT_UNDF ((1<<0)|(1<<1)|(1<<2)) +#define DS18B20_10_BIT_UNDF ((1<<0)|(1<<1)) +#define DS18B20_11_BIT_UNDF ((1<<0)) +#define DS18B20_12_BIT_UNDF 0 + +// conversion times in milliseconds +#define DS18B20_TCONV_12BIT 750 +#define DS18B20_TCONV_11BIT DS18B20_TCONV_12_BIT/2 +#define DS18B20_TCONV_10BIT DS18B20_TCONV_12_BIT/4 +#define DS18B20_TCONV_9BIT DS18B20_TCONV_12_BIT/8 +#define DS18S20_TCONV DS18B20_TCONV_12_BIT + +// constant to convert the fraction bits to cel*(10^-4) +#define DS18X20_FRACCONV 625 + +// scratchpad size in bytes +#define DS18X20_SP_SIZE 9 + +// DS18X20 EEPROM-Support +#define DS18X20_WRITE_SCRATCHPAD 0x4E +#define DS18X20_COPY_SCRATCHPAD 0x48 +#define DS18X20_RECALL_E2 0xB8 +#define DS18X20_COPYSP_DELAY 10 /* ms */ +#define DS18X20_TH_REG 2 +#define DS18X20_TL_REG 3 + +#define DS18X20_DECIMAL_CHAR '.' + + +extern uint8_t DS18X20_find_sensor(uint8_t *diff, + uint8_t id[]); +extern uint8_t DS18X20_get_power_status(uint8_t id[]); +extern uint8_t DS18X20_start_meas( uint8_t with_external, + uint8_t id[]); +// returns 1 if conversion is in progress, 0 if finished +// not available when parasite powered +extern uint8_t DS18X20_conversion_in_progress(void); + + +#if DS18X20_DECICELSIUS +extern uint8_t DS18X20_read_decicelsius( uint8_t id[], + int16_t *decicelsius ); +extern uint8_t DS18X20_read_decicelsius_single( uint8_t familycode, + int16_t *decicelsius ); +extern uint8_t DS18X20_format_from_decicelsius( int16_t decicelsius, + char s[], uint8_t n); +#endif /* DS18X20_DECICELSIUS */ + + +#if DS18X20_MAX_RESOLUTION +// temperature unit for max. resolution is �C * 10e-4 +// examples: -250625 -> -25.0625�C, 1250000 -> 125.0000 �C +extern uint8_t DS18X20_read_maxres( uint8_t id[], + int32_t *temperaturevalue ); +extern uint8_t DS18X20_read_maxres_single( uint8_t familycode, + int32_t *temperaturevalue ); +extern uint8_t DS18X20_format_from_maxres( int32_t temperaturevalue, + char s[], uint8_t n); +#endif /* DS18X20_MAX_RESOLUTION */ + + +#if DS18X20_EEPROMSUPPORT +// write th, tl and config-register to scratchpad (config ignored on DS18S20) +uint8_t DS18X20_write_scratchpad( uint8_t id[], + uint8_t th, uint8_t tl, uint8_t conf); +// read scratchpad into array SP +uint8_t DS18X20_read_scratchpad( uint8_t id[], uint8_t sp[], uint8_t n); +// copy values int scratchpad into DS18x20 eeprom +uint8_t DS18X20_scratchpad_to_eeprom( uint8_t with_power_extern, + uint8_t id[] ); +// copy values from DS18x20 eeprom into scratchpad +uint8_t DS18X20_eeprom_to_scratchpad( uint8_t id[] ); +#endif /* DS18X20_EEPROMSUPPORT */ + + +#if DS18X20_VERBOSE +extern void DS18X20_show_id_uart( uint8_t *id, size_t n ); +extern uint8_t DS18X20_read_meas_all_verbose( void ); +#endif /* DS18X20_VERBOSE */ + + +#ifdef __cplusplus +} +#endif + +#endif
--- a/main.c Fri May 18 20:38:40 2012 +0800 +++ b/main.c Fri May 18 23:57:08 2012 +0800 @@ -14,6 +14,7 @@ #include <util/crc16.h> #include "integer.h" +#include "onewire.h" // configuration params // - measurement interval @@ -186,8 +187,6 @@ comms_count = 0; need_comms = 1; } - - PORT_LED ^= _BV(PIN_LED); } DWORD get_fattime (void) @@ -313,7 +312,7 @@ blink() { PORT_LED &= ~_BV(PIN_LED); - _delay_ms(100); + _delay_ms(1); PORT_LED |= _BV(PIN_LED); } @@ -334,8 +333,26 @@ printf_P(PSTR("Bad interrupt\n")); } +static void +set_2mhz() +{ + cli(); + CLKPR = _BV(CLKPCE); + // divide by 4 + CLKPR = _BV(CLKPS1); + sei(); +} + +static void +test1wire() +{ + ow_reset(); +} + int main(void) { + set_2mhz(); + DDR_LED |= _BV(PIN_LED); blink(); @@ -376,6 +393,9 @@ } #else for(;;){ + + test1wire(); + /* insert your main loop code here */ if (need_measurement) { @@ -390,6 +410,7 @@ } deep_sleep(); + blink(); } #endif return 0; /* never reached */
--- a/onewire.h Fri May 18 20:38:40 2012 +0800 +++ b/onewire.h Fri May 18 23:57:08 2012 +0800 @@ -16,14 +16,14 @@ If not defined make sure to call ow_set_bus() before using a bus. Runtime bus-select increases code size by around 300 bytes so use OW_ONE_BUS if possible */ -// #define OW_ONE_BUS +#define OW_ONE_BUS #ifdef OW_ONE_BUS -#define OW_PIN PD6 -#define OW_IN PIND -#define OW_OUT PORTD -#define OW_DDR DDRD +#define OW_PIN PB1 +#define OW_IN PINB +#define OW_OUT PORTB +#define OW_DDR DDRB #define OW_CONF_DELAYOFFSET 0 #else
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uart_addon.c Fri May 18 23:57:08 2012 +0800 @@ -0,0 +1,118 @@ +/************************************************************************* +Title: UART addon-library +Author: Martin Thomas <[email protected]> + http://www.siwawi.arubi.uni-kl.de/avr_projects +Software: AVR-GCC 3.3/3.4, Peter Fleury's UART-Library + +DESCRIPTION: + +USAGE: + Refere to the header file uart_addon.h for a description of the routines. + +*************************************************************************/ + +#include <stdlib.h> + +#include <avr/io.h> +#include "uart.h" + + +/************************************************************************* +Function: uart_put_int() +Purpose: transmit integer as ASCII to UART +Input: integer value +Returns: none +**************************************************************************/ +void uart_put_int( const int val ) +{ + char buffer[10]; + uart_puts( itoa( val, buffer, 10 ) ); +} /* uart_puti */ + +/************************************************************************* +Function: uart_put_longint() +Purpose: transmit long integer as ASCII to UART +Input: integer value +Returns: none +**************************************************************************/ +void uart_put_longint( const long int val ) +{ + char buffer[15]; + uart_puts( ltoa( val, buffer, 10 ) ); +} /* uart_puti */ + +/************************************************************************* +Function: uart_put_ulongint() +Purpose: transmit long integer as ASCII to UART +Input: integer value +Returns: none +**************************************************************************/ +void uart_put_ulongint( const unsigned long int val ) +{ + char buffer[15]; + uart_puts( utoa( val, buffer, 10 ) ); +} /* uart_puti */ + +/************************************************************************* +Function: uart_puthex_nibble() +Purpose: transmit lower nibble as ASCII-hex to UART +Input: byte value +Returns: none +**************************************************************************/ +void uart_puthex_nibble(const unsigned char b) +{ + unsigned char c = b & 0x0f; + if ( c > 9 ) { + c += 'A'-10; + } + else { + c += '0'; + } + uart_putc(c); +} /* uart_puthex_nibble */ + +/************************************************************************* +Function: uart_puthex_byte() +Purpose: transmit upper and lower nibble as ASCII-hex to UART +Input: byte value +Returns: none +**************************************************************************/ +void uart_puthex_byte( const unsigned char b ) +{ + uart_puthex_nibble( b >> 4 ); + uart_puthex_nibble( b ); +} /* uart_puthex_byte */ + +/************************************************************************* +Function: uart_puthex_long() +Purpose: transmit unsigned long as ASCII-hex to UART +Input: uint32_t value +Returns: none +**************************************************************************/ +void uart_puthex_long( const unsigned long l ) +{ + uart_puthex_byte( (unsigned char)( l >> 24 ) ); + uart_puthex_byte( (unsigned char)( l >> 16 ) ); + uart_puthex_byte( (unsigned char)( l >> 8 ) ); + uart_puthex_byte( (unsigned char)( l ) ); +} /* uart_puthex_byte */ + + +/************************************************************************* +Function: uart_putbin_byte() +Purpose: transmit byte as ASCII-bin to UART +Input: byte value +Returns: none +**************************************************************************/ +void uart_putbin_byte( const unsigned char b ) +{ + signed char i; + for ( i= 7;i >= 0;i-- ) { + if ( b & ( 1 << i ) ) { + uart_putc( '1' ); + } + else { + uart_putc( '0' ); + } + } +} /* uart_putbin_byte */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uart_addon.h Fri May 18 23:57:08 2012 +0800 @@ -0,0 +1,121 @@ +#ifndef UART_ADDON_H +#define UART_ADDON_H +/************************************************************************ +Title: UART addon-library +Author: Martin Thomas <[email protected]> + http://www.siwawi.arubi.uni-kl.de/avr_projects +Software: AVR-GCC 3.3/3.4, Peter Fleury's UART-Library +************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup UART library-addon + * @code #include <uart_addon.h> @endcode + * + * @brief Additional functions for send numbers as decimal and hex to UART + * + * @note needs Peter Fleury's UART-Library http://jump.to/fleury + * @author Martin Thomas [email protected] + */ + +/*@{*/ + +/** + * @brief Put long integer to ringbuffer for transmitting via UART. + * + * The integer is converted to a string which is buffered by the uart + * library in a circular buffer and one character at a time is transmitted + * to the UART using interrupts. + * + * @param value to transfer + * @return none + * @see uart_puts_p + */ +extern void uart_put_longint( long int i ); + + +/** + * @brief Put unsigned long integer to ringbuffer for transmitting via UART. + * + * The integer is converted to a string which is buffered by the uart + * library in a circular buffer and one character at a time is transmitted + * to the UART using interrupts. + * + * @param value to transfer + * @return none + * @see uart_puts_p + */ +extern void uart_put_ulongint( unsigned long int i ); + + +/** + * @brief Put integer to ringbuffer for transmitting via UART. + * + * The integer is converted to a string which is buffered by the uart + * library in a circular buffer and one character at a time is transmitted + * to the UART using interrupts. + * + * @param value to transfer + * @return none + * @see uart_puts_p + */ +extern void uart_put_int( int i ); + + +/** + * @brief Put nibble as hex to ringbuffer for transmit via UART. + * + * The lower nibble of the parameter is convertet to correspondig + * hex-char and put in a circular buffer and one character at a time + * is transmitted to the UART using interrupts. + * + * @param value to transfer (byte, only lower nibble converted) + * @return none + * @see uart_putc + */ +extern void uart_puthex_nibble( const unsigned char b ); + +/** + * @brief Put byte as hex to ringbuffer for transmit via UART. + * + * The upper and lower nibble of the parameter are convertet to + * correspondig hex-chars and put in a circular buffer and one + * character at a time is transmitted to the UART using interrupts. + * + * @param value to transfer + * @return none + * @see uart_puthex_nibble + */ +extern void uart_puthex_byte( const unsigned char b ); + +/** + * @brief Put unsigned long as ASCII to ringbuffer for transmit via UART. + * + * @param value to transfer + * @return none + * @see none + */ +extern void uart_puthex_long( unsigned long l ); + +/** + * @brief Put byte as bin to ringbuffer for transmit via UART. + * + * @param value to transfer + * @return none + * @see uart_putc + */ +extern void uart_putbin_byte( const unsigned char b ); + + +/*@}*/ + +#ifdef __cplusplus +} +#endif + + +#endif /* UART_ADDON_H */ +