Subversion Repositories HomeAutomation

Rev

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