Subversion Repositories HomeAutomation

Rev

Blame | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************************
  2. Title:    DS18X20-Functions via One-Wire-Bus
  3. Author:   Martin Thomas <eversmith@heizung-thomas.de>  
  4.           http://www.siwawi.arubi.uni-kl.de/avr-projects
  5. Software: avr-gcc 3.4.1 / avr-libc 1.0.4
  6. Hardware: any AVR - tested with ATmega16/ATmega32 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.  
  16. **********************************************************************************/
  17.  
  18. #include <avr/io.h>
  19.  
  20. #include "ds18x20.h"
  21. #include "onewire.h"
  22. #include "crc8.h"
  23.  
  24. #ifdef DS18X20_EEPROMSUPPORT
  25. // for 10ms delay in copy scratchpad
  26. #include "delay.h"
  27. #endif
  28.  
  29. /*
  30.    convert raw value from DS18x20 to Celsius
  31.    input is:
  32.    - familycode fc (0x10/0x28 see header)
  33.    - scratchpad-buffer
  34.    output is:
  35.    - cel full celsius
  36.    - fractions of celsius in millicelsius*(10^-1)/625 (the 4 LS-Bits)
  37.    - subzero =0 positiv / 1 negativ
  38.    always returns  DS18X20_OK
  39.    TODO invalid-values detection (but should be covered by CRC)
  40. */
  41. uint8_t DS18X20_meas_to_cel( uint8_t fc, uint8_t *sp,
  42.     uint8_t* subzero, uint8_t* cel, uint8_t* cel_frac_bits)
  43. {
  44.     uint16_t meas;
  45.     uint8_t  i;
  46.    
  47.     meas = sp[0];  // LSB
  48.     meas |= ((uint16_t)sp[1])<<8; // MSB
  49.     //meas = 0xff5e; meas = 0xfe6f;
  50.    
  51.     //  only work on 12bit-base
  52.     if( fc == DS18S20_ID ) { // 9 -> 12 bit if 18S20
  53.         /* Extended measurements for DS18S20 contributed by Carsten Foss */
  54.         meas &= (uint16_t) 0xfffe;  // Discard LSB , needed for later extended precicion calc
  55.         meas <<= 3;                 // Convert to 12-bit , now degrees are in 1/16 degrees units
  56.         meas += (16 - sp[6]) - 4;   // Add the compensation , and remember to subtract 0.25 degree (4/16)
  57.     }
  58.    
  59.     // check for negative
  60.     if ( meas & 0x8000 )  {
  61.         *subzero=1;      // mark negative
  62.         meas ^= 0xffff;  // convert to positive => (twos complement)++
  63.         meas++;
  64.     }
  65.     else *subzero=0;
  66.    
  67.     // clear undefined bits for B != 12bit
  68.     if ( fc == DS18B20_ID ) { // check resolution 18B20
  69.         i = sp[DS18B20_CONF_REG];
  70.         if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) ;
  71.         else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT )
  72.             meas &= ~(DS18B20_11_BIT_UNDF);
  73.         else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT )
  74.             meas &= ~(DS18B20_10_BIT_UNDF);
  75.         else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) {
  76.             meas &= ~(DS18B20_9_BIT_UNDF);
  77.         }
  78.     }          
  79.    
  80.     *cel  = (uint8_t)(meas >> 4);
  81.     *cel_frac_bits = (uint8_t)(meas & 0x000F);
  82.    
  83.     return DS18X20_OK;
  84. }
  85.  
  86. /* converts to decicelsius
  87.    input is ouput from meas_to_cel
  88.    returns absolute value of temperatur in decicelsius
  89.     i.e.: sz=0, c=28, frac=15 returns 289 (=28.9�C)
  90. 0   0   0  
  91. 1   625 625 1
  92. 2   1250    250
  93. 3   1875    875 3
  94. 4   2500    500 4
  95. 5   3125    125
  96. 6   3750    750 6
  97. 7   4375    375
  98. 8   5000    0  
  99. 9   5625    625 9
  100. 10  6250    250
  101. 11  6875    875 11
  102. 12  7500    500 12
  103. 13  8125    125
  104. 14  8750    750 14
  105. 15  9375    375 */
  106. uint16_t DS18X20_temp_to_decicel(uint8_t subzero, uint8_t cel,
  107.     uint8_t cel_frac_bits)
  108. {
  109.     uint16_t h;
  110.     uint8_t  i;
  111.     uint8_t need_rounding[] = { 1, 3, 4, 6, 9, 11, 12, 14 };
  112.    
  113.     h = cel_frac_bits*DS18X20_FRACCONV/1000;
  114.     h += cel*10;
  115.     if (!subzero) {
  116.         for (i=0; i<sizeof(need_rounding); i++) {
  117.             if ( cel_frac_bits == need_rounding[i] ) {
  118.                 h++;
  119.                 break;
  120.             }
  121.         }
  122.     }
  123.     return h;
  124. }
  125.  
  126. /* compare temperature values (full celsius only)
  127.    returns -1 if param-pair1 < param-pair2
  128.             0 if ==
  129.             1 if >    */
  130. int8_t DS18X20_temp_cmp(uint8_t subzero1, uint16_t cel1,
  131.     uint8_t subzero2, uint16_t cel2)
  132. {
  133.     int16_t t1 = (subzero1) ? (cel1*(-1)) : (cel1);
  134.     int16_t t2 = (subzero2) ? (cel2*(-1)) : (cel2);
  135.    
  136.     if (t1<t2) return -1;
  137.     if (t1>t2) return 1;
  138.     return 0;
  139. }
  140.  
  141. /* find DS18X20 Sensors on 1-Wire-Bus
  142.    input/ouput: diff is the result of the last rom-search
  143.    output: id is the rom-code of the sensor found */
  144. void DS18X20_find_sensor(uint8_t *diff, uint8_t id[])
  145. {
  146.     for (;;) {
  147.         *diff = ow_rom_search( *diff, &id[0] );
  148.         if ( *diff==OW_PRESENCE_ERR || *diff==OW_DATA_ERR ||
  149.           *diff == OW_LAST_DEVICE ) return;
  150.         if ( id[0] == DS18B20_ID || id[0] == DS18S20_ID ) return;
  151.     }
  152. }
  153.  
  154. /* get power status of DS18x20
  155.    input  : id = rom_code
  156.    returns: DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE */
  157. uint8_t DS18X20_get_power_status(uint8_t id[])
  158. {
  159.     uint8_t pstat;
  160.     ow_reset();
  161.     ow_command(DS18X20_READ_POWER_SUPPLY, id);
  162.     pstat=ow_bit_io(1); // pstat 0=is parasite/ !=0 ext. powered
  163.     ow_reset();
  164.     return (pstat) ? DS18X20_POWER_EXTERN:DS18X20_POWER_PARASITE;
  165. }
  166.  
  167. /* start measurement (CONVERT_T) for all sensors if input id==NULL
  168.    or for single sensor. then id is the rom-code */
  169. uint8_t DS18X20_start_meas( uint8_t with_power_extern, uint8_t id[])
  170. {
  171.     ow_reset(); //**
  172.     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
  173.         ow_command( DS18X20_CONVERT_T, id );
  174.         if (with_power_extern != DS18X20_POWER_EXTERN)
  175.             ow_parasite_enable();
  176.         return DS18X20_OK;
  177.     }
  178.     else {
  179.         #ifdef DS18X20_VERBOSE
  180.         uart_puts_P( "DS18X20_start_meas: Short Circuit !\r" );
  181.         #endif
  182.         return DS18X20_START_FAIL;
  183.     }
  184. }
  185.  
  186. /* reads temperature (scratchpad) of sensor with rom-code id
  187.    output: subzero==1 if temp.<0, cel: full celsius, mcel: frac
  188.    in millicelsius*0.1
  189.    i.e.: subzero=1, cel=18, millicel=5000 = -18,5000�C */
  190. uint8_t DS18X20_read_meas(uint8_t id[], uint8_t *subzero,
  191.     uint8_t *cel, uint8_t *cel_frac_bits)
  192. {
  193.     uint8_t i;
  194.     uint8_t sp[DS18X20_SP_SIZE];
  195.    
  196.     ow_reset(); //**
  197.     ow_command(DS18X20_READ, id);
  198.     for ( i=0 ; i< DS18X20_SP_SIZE; i++ ) sp[i]=ow_byte_rd();
  199.     if ( crc8( &sp[0], DS18X20_SP_SIZE ) )
  200.         return DS18X20_ERROR_CRC;
  201.     DS18X20_meas_to_cel(id[0], sp, subzero, cel, cel_frac_bits);
  202.     return DS18X20_OK;
  203. }
  204.  
  205. /* reads temperature (scratchpad) of a single sensor (uses skip-rom)
  206.    output: subzero==1 if temp.<0, cel: full celsius, mcel: frac
  207.    in millicelsius*0.1
  208.    i.e.: subzero=1, cel=18, millicel=5000 = -18,5000�C */
  209. uint8_t DS18X20_read_meas_single(uint8_t familycode, uint8_t *subzero,
  210.     uint8_t *cel, uint8_t *cel_frac_bits)
  211. {
  212.     uint8_t i;
  213.     uint8_t sp[DS18X20_SP_SIZE];
  214.    
  215.     ow_command(DS18X20_READ, NULL);
  216.     for ( i=0 ; i< DS18X20_SP_SIZE; i++ ) sp[i]=ow_byte_rd();
  217.     if ( crc8( &sp[0], DS18X20_SP_SIZE ) )
  218.         return DS18X20_ERROR_CRC;
  219.     DS18X20_meas_to_cel(familycode, sp, subzero, cel, cel_frac_bits);
  220.     return DS18X20_OK;
  221. }
  222.  
  223. #ifdef DS18X20_EEPROMSUPPORT
  224.  
  225. uint8_t DS18X20_write_scratchpad( uint8_t id[],
  226.     uint8_t th, uint8_t tl, uint8_t conf)
  227. {
  228.     ow_reset(); //**
  229.     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
  230.         ow_command( DS18X20_WRITE_SCRATCHPAD, id );
  231.         ow_byte_wr(th);
  232.         ow_byte_wr(tl);
  233.         if (id[0] == DS18B20_ID) ow_byte_wr(conf); // config avail. on B20 only
  234.         return DS18X20_OK;
  235.     }
  236.     else {
  237.         #ifdef DS18X20_VERBOSE
  238.         uart_puts_P( "DS18X20_write_scratchpad: Short Circuit !\r" );
  239.         #endif
  240.         return DS18X20_ERROR;
  241.     }
  242. }
  243.  
  244. uint8_t DS18X20_read_scratchpad( uint8_t id[], uint8_t sp[] )
  245. {
  246.     uint8_t i;
  247.    
  248.     ow_reset(); //**
  249.     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
  250.         ow_command( DS18X20_READ, id );
  251.         for ( i=0 ; i< DS18X20_SP_SIZE; i++ )   sp[i]=ow_byte_rd();
  252.         return DS18X20_OK;
  253.     }
  254.     else {
  255.         #ifdef DS18X20_VERBOSE
  256.         uart_puts_P( "DS18X20_read_scratchpad: Short Circuit !\r" );
  257.         #endif
  258.         return DS18X20_ERROR;
  259.     }
  260. }
  261.  
  262. uint8_t DS18X20_copy_scratchpad( uint8_t with_power_extern,
  263.     uint8_t id[] )
  264. {
  265.     ow_reset(); //**
  266.     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
  267.         ow_command( DS18X20_COPY_SCRATCHPAD, id );
  268.         if (with_power_extern != DS18X20_POWER_EXTERN)
  269.             ow_parasite_enable();
  270.         delay_ms(DS18X20_COPYSP_DELAY); // wait for 10 ms
  271.         if (with_power_extern != DS18X20_POWER_EXTERN)
  272.             ow_parasite_disable();
  273.         return DS18X20_OK;
  274.     }
  275.     else {
  276.         #ifdef DS18X20_VERBOSE
  277.         uart_puts_P( "DS18X20_copy_scratchpad: Short Circuit !\r" );
  278.         #endif
  279.         return DS18X20_START_FAIL;
  280.     }
  281. }
  282.  
  283. uint8_t DS18X20_recall_E2( uint8_t id[] )
  284. {
  285.     ow_reset(); //**
  286.     if( ow_input_pin_state() ) { // only send if bus is "idle" = high
  287.         ow_command( DS18X20_RECALL_E2, id );
  288.         // TODO: wait until status is "1" (then eeprom values
  289.         // have been copied). here simple delay to avoid timeout
  290.         // handling
  291.         delay_ms(DS18X20_COPYSP_DELAY);
  292.         return DS18X20_OK;
  293.     }
  294.     else {
  295.         #ifdef DS18X20_VERBOSE
  296.         uart_puts_P( "DS18X20_recall_E2: Short Circuit !\r" );
  297.         #endif
  298.         return DS18X20_ERROR;
  299.     }
  300. }
  301. #endif
  302.  
  303.  
  304.  
  305. /*----------- start of "debug-functions" ---------------*/
  306. #ifdef DS18X20_VERBOSE
  307. /* functions for debugging-output - undef DS18X20_VERBOSE in .h
  308.    if you run out of program-memory */
  309. #include <string.h>
  310. #include "uart.h"
  311.  
  312. void DS18X20_uart_put_temp(const uint8_t subzero,
  313.     const uint8_t cel,  const uint8_t cel_frac_bits)
  314. {
  315.     uint8_t buffer[sizeof(int)*8+1];
  316.     int i;
  317.    
  318.     uart_putc((subzero)?'-':'+');
  319.     uart_puti((int)cel);
  320.     uart_puts_P(".");
  321.     itoa(cel_frac_bits*DS18X20_FRACCONV,buffer,10);
  322.     for (i=0;i<4-strlen(buffer);i++) uart_puts_P("0");
  323.     uart_puts(buffer);
  324.     uart_puts_P(" C");
  325. }
  326.  
  327. void DS18X20_show_id_uart( uint8_t *id, size_t n )
  328. {
  329.     size_t i;
  330.     for( i = 0; i < n; i++ ) {
  331.         if ( i == 0 ) uart_puts_P( "FC:" );
  332.         else if ( i == n-1 ) uart_puts_P( "CRC:" );
  333.         if ( i == 1 ) uart_puts_P( "SN: " );
  334.         uart_puthex_byte(id[i]);
  335.         uart_puts_P(" ");
  336.         if ( i == 0 ) {
  337.             if ( id[0] == DS18S20_ID ) uart_puts_P ("(18S)");
  338.             else if ( id[0] == DS18B20_ID ) uart_puts_P ("(18B)");
  339.             else uart_puts_P ("( ? )");
  340.         }
  341.     }
  342.     if ( crc8( id, OW_ROMCODE_SIZE) )
  343.         uart_puts_P( " CRC FAIL " );
  344.     else
  345.         uart_puts_P( " CRC O.K. " );
  346. }
  347.  
  348. void show_sp_uart( uint8_t *sp, size_t n )
  349. {
  350.     size_t i;
  351.     uart_puts_P( "SP:" );
  352.     for( i = 0; i < n; i++ ) {
  353.         if ( i == n-1 ) uart_puts_P( "CRC:" );
  354.         uart_puthex_byte(sp[i]);
  355.         uart_puts_P(" ");
  356.     }
  357. }
  358.  
  359. /* verbose output rom-search follows read-scratchpad in one loop */
  360. uint8_t DS18X20_read_meas_all_verbose( void )
  361. {
  362.     uint8_t id[OW_ROMCODE_SIZE], sp[DS18X20_SP_SIZE], diff;
  363.    
  364.     uint8_t i;
  365.     uint16_t meas;
  366.    
  367.     uint8_t subzero, cel, cel_frac_bits;
  368.    
  369.     for( diff = OW_SEARCH_FIRST; diff != OW_LAST_DEVICE; )
  370.     {
  371.         diff = ow_rom_search( diff, &id[0] );
  372.  
  373.         if( diff == OW_PRESENCE_ERR ) {
  374.           uart_puts_P( "No Sensor found\r" );
  375.           return OW_PRESENCE_ERR;
  376.         }
  377.        
  378.         if( diff == OW_DATA_ERR ) {
  379.           uart_puts_P( "Bus Error\r" );
  380.           return OW_DATA_ERR;
  381.         }
  382.        
  383.         DS18X20_show_id_uart( id, OW_ROMCODE_SIZE );
  384.        
  385.         if( id[0] == DS18B20_ID || id[0] == DS18S20_ID ) {   // temperature sensor
  386.            
  387.             uart_putc ('\r');
  388.            
  389.             ow_byte_wr( DS18X20_READ );         // read command
  390.            
  391.             for ( i=0 ; i< DS18X20_SP_SIZE; i++ )
  392.                 sp[i]=ow_byte_rd();
  393.            
  394.             show_sp_uart( sp, DS18X20_SP_SIZE );
  395.  
  396.             if ( crc8( &sp[0], DS18X20_SP_SIZE ) )
  397.                 uart_puts_P( " CRC FAIL " );
  398.             else
  399.                 uart_puts_P( " CRC O.K. " );
  400.             uart_putc ('\r');
  401.        
  402.             meas = sp[0]; // LSB Temp. from Scrachpad-Data
  403.             meas |= (uint16_t) (sp[1] << 8); // MSB
  404.            
  405.             uart_puts_P(" T_raw=");
  406.             uart_puthex_byte((uint8_t)(meas>>8));
  407.             uart_puthex_byte((uint8_t)meas);
  408.             uart_puts_P(" ");
  409.  
  410.             if( id[0] == DS18S20_ID ) { // 18S20
  411.                 uart_puts_P( "S20/09" );
  412.             }
  413.             else if ( id[0] == DS18B20_ID ) { // 18B20
  414.                 i=sp[DS18B20_CONF_REG];
  415.                 if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) {
  416.                     uart_puts_P( "B20/12" );
  417.                 }
  418.                 else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT ) {
  419.                     uart_puts_P( "B20/11" );
  420.                 }
  421.                 else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT ) {
  422.                     uart_puts_P( " B20/10 " );
  423.                 }
  424.                 else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) {
  425.                     uart_puts_P( "B20/09" );
  426.                 }
  427.             }          
  428.             uart_puts_P(" ");
  429.            
  430.             DS18X20_meas_to_cel(id[0], sp, &subzero, &cel, &cel_frac_bits);
  431.            
  432.             DS18X20_uart_put_temp(subzero, cel, cel_frac_bits);
  433.            
  434.             uart_puts("\r");
  435.            
  436.         } // if meas-sensor
  437.        
  438.     } // loop all sensors
  439.    
  440.     uart_puts_P( "\r" );
  441.    
  442.     return DS18X20_OK;
  443. }
  444. #endif
  445.  
  446. /*----------- end of "debug-functions" ---------------*/
  447.