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