Subversion Repositories HomeAutomation

Rev

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