MAX31850, DS18B20, DS2450, thermocouple

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS18X20.cpp Source File

DS18X20.cpp

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 (Published 01/03/2012 www.mbed.org)
00006 */
00007 #include "mbed.h"
00008 #include "onewire.h"
00009 #include "DS18X20.h"
00010 #include "crc8.h"
00011 #include "utils.h"
00012 //**********************************************************************************************************
00013 //*                                  DS18X20_show_temp
00014 //**********************************************************************************************************
00015 
00016 /**
00017 *     @brief DS18X20_show_temp
00018 *    @param  [in] id[] = rom_code
00019 *    @param  [in] n number of id[n]
00020 *    @param  [out] text temp in degre celsius
00021 
00022 *     @date 20/06/2011
00023 */
00024 void DS18X20_show_temp(uint8_t subzero, uint8_t cel, uint8_t cel_frac_bits,char *text) {
00025     uint16_t decicelsius;
00026     char s[10];
00027     float temperature;
00028     sprintf(text,"");
00029     sprintf(s,"%s", (subzero)?"-":"");
00030     strcat(text,s);
00031     decicelsius = DS18X20_temp_to_decicel(subzero, cel, cel_frac_bits);
00032     temperature = decicelsius;
00033     temperature = temperature/10;
00034     sprintf(s,"%4.1f", temperature);
00035     strcat(text,s);
00036 
00037 }
00038 /**
00039 *     @brief DS18X20_show_temp
00040 *    @param  [in] id[] = rom_code
00041 *    @param  [in] n number of id[n]
00042 *    @return temp in degre celsius
00043 
00044 *     @date 21/10/2011
00045 */
00046 float DS18X20_temp(uint8_t subzero, uint8_t cel, uint8_t cel_frac_bits) {
00047     return ((subzero)?-1:1)*DS18X20_temp_to_decicel(subzero, cel, cel_frac_bits)/10;
00048 }
00049 //**********************************************************************************************************
00050 //*                                  DS18X20_get_power_status
00051 //**********************************************************************************************************
00052  
00053 /**
00054 *     @brief get power status of DS18x20
00055 *    @param  [in] id[] = rom_code
00056 *    @return DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE
00057 *     @date 20/06/2011
00058 */
00059 uint8_t DS18X20_get_power_status(uint8_t id[]) {
00060     uint8_t pstat;
00061     ow_reset();
00062     ow_command(DS18X20_READ_POWER_SUPPLY, id);
00063     pstat=ow_bit_io(1); // pstat 0=is parasite/ !=0 ext. powered
00064     ow_reset();
00065     return (pstat) ? DS18X20_POWER_EXTERN:DS18X20_POWER_PARASITE;
00066 }
00067 
00068 /**
00069 *     @brief get power status of DS18x20
00070 *    @param  [in] n num bus onewire
00071 *    @param  [in] id[] = rom_code
00072 *    @return DS18X20_POWER_EXTERN or DS18X20_POWER_PARASITE
00073 *     @date 6/09/2011
00074 */
00075 uint8_t DS18X20_get_power_status(uint8_t n,uint8_t id[]) {
00076     uint8_t pstat;
00077     ow_reset(n);
00078     ow_command(n,DS18X20_READ_POWER_SUPPLY, id);
00079     pstat=ow_bit_io(n,1); // pstat 0=is parasite/ !=0 ext. powered
00080     ow_reset(n);
00081     return (pstat) ? DS18X20_POWER_EXTERN:DS18X20_POWER_PARASITE;
00082 }
00083 //**********************************************************************************************************
00084 //*                                  DS18X20_start_meas
00085 //**********************************************************************************************************
00086 /**
00087 *   @brief reads temperature (scratchpad) of sensor with rom-code id
00088    output: subzero==1 if temp.<0, cel: full celsius, mcel: frac
00089    in millicelsius*0.1
00090    i.e.: subzero=1, cel=18, millicel=5000 = -18,5000&#65533;C
00091 *    @param  [in] n num bus onewire
00092 *    @param  [in] id[] = rom_code
00093 *    @param  [out] temperature
00094 *    @return DS18X20_OK or DS18X20_ERROR_CRC
00095 *     @date 07/12/2012
00096 */
00097 uint8_t DS18X20_read_meas(uint8_t n,uint8_t id[], float* temperature) {
00098     uint8_t i;
00099     uint8_t sp[DS18X20_SP_SIZE];
00100     uint8_t subzero;
00101     uint8_t cel;
00102     uint8_t cel_frac_bits;
00103     
00104     ow_reset(n);
00105     ow_command(n,DS18X20_READ, id);
00106     for ( i=0 ; i< DS18X20_SP_SIZE; i++ )
00107         sp[i]=ow_byte_rd(n);
00108     if ( crc8( &sp[0], DS18X20_SP_SIZE ) ){
00109           if ((sp[DS18X20_SP_SIZE-1]==0xFF) && (sp[DS18X20_SP_SIZE-2]==0xFF))
00110             return OW_ERROR;    // bus error
00111         return DS18X20_ERROR_CRC;    // data error
00112     }
00113         
00114     DS18X20_meas_to_cel(id[0], sp, &subzero, &cel, &cel_frac_bits);
00115     *temperature = cel_frac_bits*.0625;
00116     *temperature += cel;
00117     if (subzero)
00118        *temperature *= -1; 
00119     return DS18X20_OK;
00120 }
00121 /**
00122 *   @brief start measurement (CONVERT_T) for all sensors if input id==NULL
00123    or for single sensor. then id is the rom-code
00124 *    @param  [in] with_power_extern
00125 *    @param  [in] rom_code
00126 *    @return DS18X20_OK or DS18X20_START_FAIL
00127 *     @date 20/06/2011
00128 */
00129 uint8_t DS18X20_start_meas( uint8_t with_power_extern, uint8_t id[]) {
00130     ow_reset(); //**
00131     if ( ow_test_pin() ) { // only send if bus is "idle" = high
00132         ow_command( DS18X20_CONVERT_T, id );
00133         if (with_power_extern != DS18X20_POWER_EXTERN)
00134             ow_parasite_enable();
00135         return DS18X20_OK;
00136     }
00137     return DS18X20_START_FAIL;
00138 
00139 }
00140 /**
00141 *   @brief start measurement (CONVERT_T) for all sensors if input id==NULL
00142    or for single sensor. then id is the rom-code
00143 *    @param  [in] n num bus onewire
00144 *    @param  [in] with_power_extern
00145 *    @param  [in] rom_code
00146 *    @return DS18X20_OK or DS18X20_START_FAIL
00147 *     @date 06/09/2011
00148 */
00149 uint8_t DS18X20_start_meas(uint8_t n, uint8_t with_power_extern, uint8_t id[]) {
00150     ow_reset(n); //**
00151     if ( ow_test_pin(n) ) { // only send if bus is "idle" = high
00152         ow_command(n, DS18X20_CONVERT_T, id );
00153         if (with_power_extern != DS18X20_POWER_EXTERN)
00154             ow_parasite_enable(n);
00155         return DS18X20_OK;
00156     }
00157     return DS18X20_START_FAIL;
00158 
00159 }
00160 //**********************************************************************************************************
00161 //*                                  DS18X20_read_meas
00162 //**********************************************************************************************************
00163 
00164 /**
00165 *   @brief reads temperature (scratchpad) of sensor with rom-code id
00166    output: subzero==1 if temp.<0, cel: full celsius, mcel: frac
00167    in millicelsius*0.1
00168    i.e.: subzero=1, cel=18, millicel=5000 = -18,5000&#65533;C
00169 *    @param  [in] id[] = rom_code
00170 *    @param  [out] subzero
00171 *    @param  [out] cel
00172 *    @param  [out] cel_frac_bits
00173 *    @return DS18X20_OK or DS18X20_ERROR_CRC
00174 *     @date 20/06/2011
00175 */
00176 uint8_t DS18X20_read_meas(uint8_t id[], uint8_t *subzero,
00177                           uint8_t *cel, uint8_t *cel_frac_bits) {
00178     uint8_t i;
00179     uint8_t sp[DS18X20_SP_SIZE];
00180 
00181     ow_reset();
00182     ow_command(DS18X20_READ, id);
00183     for ( i=0 ; i< DS18X20_SP_SIZE; i++ )
00184         sp[i]=ow_byte_rd();
00185     if ( crc8( &sp[0], DS18X20_SP_SIZE ) ){
00186           if ((sp[DS18X20_SP_SIZE-1]==0xFF) && (sp[DS18X20_SP_SIZE-2]==0xFF))
00187             return OW_ERROR;    // bus error
00188         return DS18X20_ERROR_CRC;    // data error
00189     }
00190         
00191     DS18X20_meas_to_cel(id[0], sp, subzero, cel, cel_frac_bits);
00192     return DS18X20_OK;
00193 }
00194 /**
00195 *   @brief reads temperature (scratchpad) of sensor with rom-code id
00196    output: subzero==1 if temp.<0, cel: full celsius, mcel: frac
00197    in millicelsius*0.1
00198    i.e.: subzero=1, cel=18, millicel=5000 = -18,5000&#65533;C
00199 *    @param  [in] n num bus onewire
00200 *    @param  [in] id[] = rom_code
00201 *    @param  [out] subzero
00202 *    @param  [out] cel
00203 *    @param  [out] cel_frac_bits
00204 *    @return DS18X20_OK or DS18X20_ERROR_CRC
00205 *     @date 06/09/2011
00206 */
00207 uint8_t DS18X20_read_meas(uint8_t n,uint8_t id[], uint8_t *subzero,
00208                           uint8_t *cel, uint8_t *cel_frac_bits) {
00209     uint8_t i;
00210     uint8_t sp[DS18X20_SP_SIZE];
00211 
00212     ow_reset(n);
00213     ow_command(n,DS18X20_READ, id);
00214     for ( i=0 ; i< DS18X20_SP_SIZE; i++ )
00215         sp[i]=ow_byte_rd(n);
00216     if ( crc8( &sp[0], DS18X20_SP_SIZE ) ){
00217           if ((sp[DS18X20_SP_SIZE-1]==0xFF) && (sp[DS18X20_SP_SIZE-2]==0xFF))
00218             return OW_ERROR;    // bus error
00219         return DS18X20_ERROR_CRC;    // data error
00220     }
00221         
00222     DS18X20_meas_to_cel(id[0], sp, subzero, cel, cel_frac_bits);
00223     return DS18X20_OK;
00224 }
00225 /**
00226 *   @brief convert raw value from DS18x20 to Celsius
00227    input is:
00228    - familycode fc (0x10/0x28 see header)
00229    - scratchpad-buffer
00230    output is:
00231    - cel full celsius
00232    - fractions of celsius in millicelsius*(10^-1)/625 (the 4 LS-Bits)
00233    - subzero =0 positiv / 1 negativ
00234    always returns  DS18X20_OK
00235    TODO invalid-values detection (but should be covered by CRC)
00236 *    @param  [in] fc
00237 *    @param  [in] sp
00238 *    @param  [out] subzero
00239 *    @param  [out] cel
00240 *    @param  [out] cel_frac_bits
00241 *    @return DS18X20_OK
00242 *     @date 20/06/2011
00243 */
00244 uint8_t DS18X20_meas_to_cel( uint8_t fc, uint8_t *sp,
00245                              uint8_t* subzero, uint8_t* cel, uint8_t* cel_frac_bits) {
00246     uint16_t meas;
00247     uint8_t  i;
00248 
00249     meas = sp[0];  // LSB
00250     meas |= ((uint16_t)sp[1])<<8; // MSB
00251     //meas = 0xff5e; meas = 0xfe6f;
00252 
00253     //  only work on 12bit-base
00254     if ( fc == DS18S20_ID ) { // 9 -> 12 bit if 18S20
00255         /* Extended measurements for DS18S20 contributed by Carsten Foss */
00256         meas &= (uint16_t) 0xfffe;    // Discard LSB , needed for later extended precicion calc
00257         meas <<= 3;                    // Convert to 12-bit , now degrees are in 1/16 degrees units
00258         meas += (16 - sp[6]) - 4;    // Add the compensation , and remember to subtract 0.25 degree (4/16)
00259     }
00260 
00261     // check for negative
00262     if ( meas & 0x8000 )  {
00263         *subzero=1;      // mark negative
00264         meas ^= 0xffff;  // convert to positive => (twos complement)++
00265         meas++;
00266     } else *subzero=0;
00267 
00268     // clear undefined bits for B != 12bit
00269     if ( fc == DS18B20_ID ) { // check resolution 18B20
00270         i = sp[DS18B20_CONF_REG];
00271         if ( (i & DS18B20_12_BIT) == DS18B20_12_BIT ) ;
00272         else if ( (i & DS18B20_11_BIT) == DS18B20_11_BIT )
00273             meas &= ~(DS18B20_11_BIT_UNDF);
00274         else if ( (i & DS18B20_10_BIT) == DS18B20_10_BIT )
00275             meas &= ~(DS18B20_10_BIT_UNDF);
00276         else { // if ( (i & DS18B20_9_BIT) == DS18B20_9_BIT ) {
00277             meas &= ~(DS18B20_9_BIT_UNDF);
00278         }
00279     }
00280 
00281     *cel  = (uint8_t)(meas >> 4);
00282     *cel_frac_bits = (uint8_t)(meas & 0x000F);
00283 
00284     return DS18X20_OK;
00285 }
00286 
00287 /**
00288 *   @brief converts to decicelsius
00289    input is ouput from meas_to_cel
00290     i.e.: sz=0, c=28, frac=15 returns 289 (=28.9&#65533;C)
00291 0    0    0
00292 1    625    625    1
00293 2    1250    250
00294 3    1875    875    3
00295 4    2500    500    4
00296 5    3125    125
00297 6    3750    750    6
00298 7    4375    375
00299 8    5000    0
00300 9    5625    625    9
00301 10    6250    250
00302 11    6875    875    11
00303 12    7500    500    12
00304 13    8125    125
00305 14    8750    750    14
00306 15    9375    375
00307 *    @param  [in]  subzero
00308 *    @param  [in]  cel
00309 *    @param  [in]  cel_frac_bits
00310 *    @return absolute value of temperatur in decicelsius
00311 *     @date 20/06/2011
00312 */
00313 uint16_t DS18X20_temp_to_decicel(uint8_t subzero, uint8_t cel,
00314                                  uint8_t cel_frac_bits) {
00315     uint16_t h;
00316     uint8_t  i;
00317     uint8_t need_rounding[] = { 1, 3, 4, 6, 9, 11, 12, 14 };
00318 
00319     h = cel_frac_bits*DS18X20_FRACCONV/1000;
00320     h += cel*10;
00321     if (!subzero) {
00322         for (i=0; i<sizeof(need_rounding); i++) {
00323             if ( cel_frac_bits == need_rounding[i] ) {
00324                 h++;
00325                 break;
00326             }
00327         }
00328     }
00329     return h;
00330 }
00331 /**
00332 *   @brief  compare temperature values (full celsius only)
00333 *    @param  [in] subzero1
00334 *    @param  [in] cel1
00335 *    @param  [in] subzero2
00336 *    @param  [in] cel2
00337 *    @return -1 if param-pair1 < param-pair2
00338             0 if ==
00339             1 if >
00340 *     @date 20/06/2011
00341 */
00342 int8_t DS18X20_temp_cmp(uint8_t subzero1, uint16_t cel1,
00343                         uint8_t subzero2, uint16_t cel2) {
00344     int16_t t1 = (subzero1) ? (cel1*(-1)) : (cel1);
00345     int16_t t2 = (subzero2) ? (cel2*(-1)) : (cel2);
00346 
00347     if (t1<t2) return -1;
00348     if (t1>t2) return 1;
00349     return 0;
00350 }