Simple cpp wrapper of a ds18b20, onewire 'c' library. Supports multiple sensors.

Dependencies:   mbed

Dependents:   LPC11U68_DS18B20Sensor

Fork of DS18B20Sensor by Steve Spence

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS18X20.c Source File

DS18X20.c

00001 /**
00002 * @file DS18x20.c
00003 * @brief library of DS18X20 1-Wire digital thermometer (http://www.maxim-ic.com/datasheet/index.mvp/id/2812)
00004 * @author Maciej Rajtar (Published 10 May 2010 www.mbed.org)
00005 * @author Frederic BLANC
00006 */
00007 #include "mbed.h"
00008 #include "onewire.h"
00009 #include "DS18X20.h"
00010 #include "crc8.h"
00011 /**
00012 *     @brief get power status of DS18x20
00013 *    @param  [in] uint8_t id[] = rom_code
00014 *    @return DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE
00015 *     @date 20/06/2011
00016 */
00017 uint8_t DS18X20_get_power_status(uint8_t id[]) {
00018     uint8_t pstat;
00019     ow_reset();
00020     ow_command(DS18X20_READ_POWER_SUPPLY, id);
00021     pstat=ow_bit_io(1); // pstat 0=is parasite/ !=0 ext. powered
00022     ow_reset();
00023     return (pstat) ? DS18X20_POWER_EXTERN:DS18X20_POWER_PARASITE;
00024 }
00025 
00026 
00027 
00028 /**
00029 *   @brief start measurement (CONVERT_T) for all sensors if input id==NULL
00030    or for single sensor. then id is the rom-code
00031 *    @param  [in] uint8_t with_power_extern
00032 *    @param  [in] uint8_t id[] = rom_code
00033 *    @return DS18X20_OK or DS18X20_START_FAIL
00034 *     @date 20/06/2011
00035 */
00036 uint8_t DS18X20_start_meas( uint8_t with_power_extern, uint8_t id[]) {
00037     ow_reset(); //**
00038     if ( ow_test_pin() ) { // only send if bus is "idle" = high
00039         ow_command( DS18X20_CONVERT_T, id );
00040         if (with_power_extern != DS18X20_POWER_EXTERN)
00041             ow_parasite_enable();
00042         return DS18X20_OK;
00043     }
00044     return DS18X20_START_FAIL;
00045 
00046 }
00047 
00048 /**
00049 *   @brief reads temperature (scratchpad) of sensor with rom-code id
00050    output: subzero==1 if temp.<0, cel: full celsius, mcel: frac
00051    in millicelsius*0.1
00052    i.e.: subzero=1, cel=18, millicel=5000 = -18,5000&#65533;C
00053 *    @param  [in] id[] = rom_code
00054 *    @param  [out] subzero
00055 *    @param  [out] cel
00056 *    @param  [out] cel_frac_bits
00057 *    @return DS18X20_OK or DS18X20_ERROR_CRC
00058 *     @date 20/06/2011
00059 */
00060 uint8_t DS18X20_read_meas(uint8_t id[], uint8_t *subzero,
00061                           uint8_t *cel, uint8_t *cel_frac_bits) {
00062     uint8_t i;
00063     uint8_t sp[DS18X20_SP_SIZE];
00064 
00065     ow_reset();
00066     ow_command(DS18X20_READ, id);
00067     for ( i=0 ; i< DS18X20_SP_SIZE; i++ )
00068         sp[i]=ow_byte_rd();
00069     if ( crc8( &sp[0], DS18X20_SP_SIZE ) ){
00070           if ((sp[DS18X20_SP_SIZE-1]==0xFF) && (sp[DS18X20_SP_SIZE-2]==0xFF))
00071             return OW_ERROR;    // bus error
00072         return DS18X20_ERROR_CRC;    // data error
00073     }
00074         
00075     DS18X20_meas_to_cel(id[0], sp, subzero, cel, cel_frac_bits);
00076     return DS18X20_OK;
00077 }
00078 
00079 /**
00080 *   @brief convert raw value from DS18x20 to Celsius
00081    input is:
00082    - familycode fc (0x10/0x28 see header)
00083    - scratchpad-buffer
00084    output is:
00085    - cel full celsius
00086    - fractions of celsius in millicelsius*(10^-1)/625 (the 4 LS-Bits)
00087    - subzero =0 positiv / 1 negativ
00088    always returns  DS18X20_OK
00089    TODO invalid-values detection (but should be covered by CRC)
00090 *    @param  [in] fc
00091 *    @param  [in] sp
00092 *    @param  [out] subzero
00093 *    @param  [out] cel
00094 *    @param  [out] cel_frac_bits
00095 *    @return DS18X20_OK
00096 *     @date 20/06/2011
00097 */
00098 uint8_t DS18X20_meas_to_cel( uint8_t fc, uint8_t *sp,
00099                              uint8_t* subzero, uint8_t* cel, uint8_t* cel_frac_bits) {
00100     uint16_t meas;
00101     uint8_t  i;
00102 
00103     meas = sp[0];  // LSB
00104     meas |= ((uint16_t)sp[1])<<8; // MSB
00105     //meas = 0xff5e; meas = 0xfe6f;
00106 
00107     //  only work on 12bit-base
00108     if ( fc == DS18S20_ID ) { // 9 -> 12 bit if 18S20
00109         /* Extended measurements for DS18S20 contributed by Carsten Foss */
00110         meas &= (uint16_t) 0xfffe;    // Discard LSB , needed for later extended precicion calc
00111         meas <<= 3;                    // Convert to 12-bit , now degrees are in 1/16 degrees units
00112         meas += (16 - sp[6]) - 4;    // Add the compensation , and remember to subtract 0.25 degree (4/16)
00113     }
00114 
00115     // check for negative
00116     if ( meas & 0x8000 )  {
00117         *subzero=1;      // mark negative
00118         meas ^= 0xffff;  // convert to positive => (twos complement)++
00119         meas++;
00120     } else *subzero=0;
00121 
00122     // clear undefined bits for B != 12bit
00123     if ( fc == DS18B20_ID ) { // check resolution 18B20
00124         i = sp[DS18B20_CONF_REG];
00125         if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) ;
00126         else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT )
00127             meas &= ~(DS18B20_11_BIT_UNDF);
00128         else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT )
00129             meas &= ~(DS18B20_10_BIT_UNDF);
00130         else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) {
00131             meas &= ~(DS18B20_9_BIT_UNDF);
00132         }
00133     }
00134 
00135     *cel  = (uint8_t)(meas >> 4);
00136     *cel_frac_bits = (uint8_t)(meas & 0x000F);
00137 
00138     return DS18X20_OK;
00139 }
00140 
00141 /**
00142 *   @brief converts to decicelsius
00143    input is ouput from meas_to_cel
00144     i.e.: sz=0, c=28, frac=15 returns 289 (=28.9&#65533;C)
00145 0    0    0
00146 1    625    625    1
00147 2    1250    250
00148 3    1875    875    3
00149 4    2500    500    4
00150 5    3125    125
00151 6    3750    750    6
00152 7    4375    375
00153 8    5000    0
00154 9    5625    625    9
00155 10    6250    250
00156 11    6875    875    11
00157 12    7500    500    12
00158 13    8125    125
00159 14    8750    750    14
00160 15    9375    375
00161 *    @param  [in]  subzero
00162 *    @param  [in]  cel
00163 *    @param  [in]  cel_frac_bits
00164 *    @return absolute value of temperatur in decicelsius
00165 *     @date 20/06/2011
00166 */
00167 uint16_t DS18X20_temp_to_decicel(uint8_t subzero, uint8_t cel,
00168                                  uint8_t cel_frac_bits) {
00169     uint16_t h;
00170     uint8_t  i;
00171     uint8_t need_rounding[] = { 1, 3, 4, 6, 9, 11, 12, 14 };
00172 
00173     h = cel_frac_bits*DS18X20_FRACCONV/1000;
00174     h += cel*10;
00175     if (!subzero) {
00176         for (i=0; i<sizeof(need_rounding); i++) {
00177             if ( cel_frac_bits == need_rounding[i] ) {
00178                 h++;
00179                 break;
00180             }
00181         }
00182     }
00183     return h;
00184 }
00185 /**
00186 *   @brief  compare temperature values (full celsius only)
00187 *    @param  [in] subzero1
00188 *    @param  [in] cel1
00189 *    @param  [in] subzero2
00190 *    @param  [in] cel2
00191 *    @return -1 if param-pair1 < param-pair2
00192             0 if ==
00193             1 if >
00194 *     @date 20/06/2011
00195 */
00196 int8_t DS18X20_temp_cmp(uint8_t subzero1, uint16_t cel1,
00197                         uint8_t subzero2, uint16_t cel2) {
00198     int16_t t1 = (subzero1) ? (cel1*(-1)) : (cel1);
00199     int16_t t2 = (subzero2) ? (cel2*(-1)) : (cel2);
00200 
00201     if (t1<t2) return -1;
00202     if (t1>t2) return 1;
00203     return 0;
00204 }