Dallas' DS1820 family temperature sensor. For more details see [https://developer.mbed.org/users/hudakz/code/DS1820/wiki/Homepage]

Dependencies:   OneWire

Fork of DS1820 by Zoltan Hudak

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS1820.cpp Source File

DS1820.cpp

00001 /*
00002  * Dallas' DS1820 family temperature sensor.
00003  * This library depends on the OneWire library (Dallas' 1-Wire bus protocol implementation)
00004  * available at <http://developer.mbed.org/users/hudakz/code/OneWire/>
00005  *
00006  * Example of use:
00007  * 
00008  * #include "DS1820.h"
00009  *
00010  * Serial serial(USBTX, USBRX);
00011  * 
00012  * int main() {
00013  *     DS1820  ds1820(PA_9);    // substitute PA_9 with actual mbed pin name connected to the DS1820 data pin
00014  *
00015  *     if(ds1820.begin()) {
00016  *        ds1820.startConversion();
00017  *        wait(1.0);
00018  *        while(1) {
00019  *            serial.printf("temp = %3.1f\r\n", ds1820.read());     // read temperature
00020  *            ds1820.startConversion();     // start temperature conversion
00021  *            wait(1.0);                    // let DS1820 complete the temperature conversion
00022  *        }
00023  *    } else
00024  *        serial.printf("No DS1820 sensor found!\r\n");
00025  * }
00026  *
00027  * 
00028  * Note: Don't forget to connect a 4.7k Ohm resistor 
00029  *       between the DS1820's data pin and the +3.3V pin
00030  *
00031  */
00032  
00033 #include "DS1820.h"
00034 
00035 #define DEBUG 0
00036 
00037 #if DEBUG
00038 extern Serial serial;
00039 #endif
00040 
00041 /**
00042  * @brief   Constructs a generic DS1820 sensor
00043  * @note    begin() must be called to detect and initialize the actual model
00044  * @param   pin: Name of data pin
00045  * @retval
00046  */
00047 DS1820::DS1820(PinName pin) :
00048     oneWire(pin) {
00049     present = false;
00050     model_s = false;
00051 }
00052 
00053 /**
00054  * @brief   Constructs a specific model
00055  * @note    No need to call begin() to detect and initialize the model
00056  * @param   model:  One character model name: 'S', 's', 'B' or 'b'
00057  *          pin:    Name of data pin
00058  * @retval
00059  */
00060 DS1820::DS1820(char model, PinName pin) :
00061     oneWire(pin) {
00062     if((model == 'S') or (model == 's')) {
00063         present = true;
00064         model_s = true;
00065     }
00066     else if((model == 'B') or (model == 'b')) {
00067         present = true;
00068         model_s = false;
00069     }
00070     else
00071         present = false;
00072 }
00073 
00074 /**
00075  * @brief   Detects and initializes the actual DS1820 model
00076  * @note
00077  * @param
00078  * @retval  true:   if a DS1820 family sensor was detected and initialized
00079             false:  otherwise
00080  */
00081 bool DS1820::begin(void) {
00082     oneWire.reset_search();
00083     wait_ms(250);
00084     if(!oneWire.search(addr)) {
00085 #if DEBUG
00086         serial.printf("No addresses.\r\n");
00087 #endif
00088         oneWire.reset_search();
00089         wait_ms(250);
00090         return false;
00091     }
00092 
00093 #if DEBUG
00094     serial.printf("ROM =");
00095     for(uint8_t i = 0; i < 8; i++) {
00096         serial.printf(" %x", addr[i]);
00097     }
00098     serial.printf("\r\n");
00099 #endif
00100 
00101     if(OneWire::crc8(addr, 7) == addr[7]) {
00102         present = true;
00103 
00104         // the first ROM byte indicates which chip
00105         switch(addr[0]) {
00106         case 0x10:
00107             model_s = true;
00108 #if DEBUG
00109             serial.printf("DS18S20 or old DS1820\r\n");
00110 #endif            
00111             break;
00112 
00113         case 0x28:
00114             model_s = false;
00115 #if DEBUG
00116             serial.printf("DS18B20\r\n");
00117 #endif            
00118             break;
00119 
00120         case 0x22:
00121             model_s = false;
00122 #if DEBUG
00123             serial.printf("DS1822\r\n");
00124 #endif            
00125             break;
00126 
00127         default:
00128             present = false;
00129 #if DEBUG
00130             serial.printf("Device doesn't belong to the DS1820 family\r\n");
00131 #endif            
00132             return false;
00133         }
00134         return true;
00135     }
00136     else {
00137 #if DEBUG    
00138         serial.printf("Invalid CRC!\r\n");
00139 #endif    
00140         return false;
00141     }
00142 }
00143 
00144 /**
00145  * @brief   Informs about presence of a DS1820 sensor.
00146  * @note    begin() shall be called before using this function
00147  *          if a generic DS1820 instance was created by the user. 
00148  *          No need to call begin() for a specific DS1820 instance.
00149  * @param
00150  * @retval  true:   when a DS1820 sensor is present
00151  *          false:  otherwise
00152  */
00153 bool DS1820::isPresent(void) {
00154     return present;
00155 }
00156 
00157 /**
00158  * @brief   Sets temperature-to-digital conversion resolution.
00159  * @note    The configuration register allows the user to set the resolution
00160  *          of the temperature-to-digital conversion to 9, 10, 11, or 12 bits.
00161  *          Defaults to 12-bit resolution for DS18B20.
00162  *          DS18S20 allows only 9-bit resolution.
00163  * @param   res:    Resolution of the temperature-to-digital conversion in bits.
00164  * @retval
00165  */
00166 void DS1820::setResolution(uint8_t res) {
00167     // keep resolution within limits
00168     if(res > 12)
00169         res = 12;
00170     if(res < 9)
00171         res = 9;      
00172     if(model_s)
00173         res = 9;
00174        
00175     oneWire.reset();
00176     oneWire.skip();
00177     oneWire.write(0xBE);            // to read Scratchpad
00178     for(uint8_t i = 0; i < 9; i++)  // read Scratchpad bytes
00179         data[i] = oneWire.read();   
00180 
00181     data[4] |= (res - 9) << 5;      // update configuration byte (set resolution)  
00182     oneWire.reset();
00183     oneWire.skip();
00184     oneWire.write(0x4E);            // to write into Scratchpad
00185     for(uint8_t i = 2; i < 5; i++)  // write three bytes (2nd, 3rd, 4th) into Scratchpad
00186         oneWire.write(data[i]);
00187 }
00188 
00189 /**
00190  * @brief   Starts temperature conversion
00191  * @note    The time to complete the converion depends on the selected resolution:
00192  *           9-bit resolution -> max conversion time = 93.75ms
00193  *          10-bit resolution -> max conversion time = 187.5ms
00194  *          11-bit resolution -> max conversion time = 375ms
00195  *          12-bit resolution -> max conversion time = 750ms
00196  * @param
00197  * @retval
00198  */
00199 void DS1820::startConversion(void) {
00200     if(present) {
00201         oneWire.reset();
00202         oneWire.skip();
00203         oneWire.write(0x44);    //start temperature conversion
00204     }
00205 }
00206 
00207 /**
00208  * @brief   Reads temperature from the chip's Scratchpad
00209  * @note
00210  * @param
00211  * @retval  Floating point temperature value
00212  */
00213 float DS1820::read(void) {
00214     if(present) {
00215         oneWire.reset();
00216         oneWire.skip();
00217         oneWire.write(0xBE);            // to read Scratchpad
00218         for(uint8_t i = 0; i < 9; i++)  // read Scratchpad bytes
00219             data[i] = oneWire.read();   
00220 
00221         // Convert the raw bytes to a 16-bit unsigned value
00222         uint16_t*   p_word = reinterpret_cast < uint16_t * > (&data[0]);
00223 
00224 #if DEBUG
00225         serial.printf("raw = %#x\r\n", *p_word);
00226 #endif            
00227 
00228         if(model_s) {
00229             *p_word = *p_word << 3;         // 9-bit resolution
00230             if(data[7] == 0x10) {
00231 
00232                 // "count remain" gives full 12-bit resolution
00233                 *p_word = (*p_word & 0xFFF0) + 12 - data[6];
00234             }
00235         }
00236         else {
00237             uint8_t cfg = (data[4] & 0x60); // default 12-bit resolution
00238             
00239             // at lower resolution, the low bits are undefined, so let's clear them
00240             if(cfg == 0x00)
00241                 *p_word = *p_word &~7;      //  9-bit resolution
00242             else
00243             if(cfg == 0x20)
00244                 *p_word = *p_word &~3;      // 10-bit resolution
00245             else
00246             if(cfg == 0x40)
00247                 *p_word = *p_word &~1;      // 11-bit resolution
00248                                                
00249         }
00250 
00251         // Convert the raw bytes to a 16-bit signed fixed point value :
00252         // 1 sign bit, 7 integer bits, 8 fractional bits (two’s compliment
00253         // and the LSB of the 16-bit binary number represents 1/256th of a unit).
00254         *p_word = *p_word << 4;
00255         
00256         // Convert to floating point value
00257         return(toFloat(*p_word));
00258     }
00259     else
00260         return 0;
00261 }
00262 
00263 /**
00264  * @brief   Reads temperature from chip's scratchpad.
00265  * @note    Verifies data integrity by calculating cyclic redundancy check (CRC).
00266  *          If the calculated CRC dosn't match the one stored in chip's scratchpad register
00267  *          the temperature variable is not updated and CRC error code is returned.
00268  * @param   temp: The temperature variable to be updated by this routine.
00269  *                (It's passed as reference to floating point.)
00270  * @retval  error code:
00271  *              0 - no errors ('temp' contains the temperature measured)
00272  *              1 - sensor not present ('temp' is not updated)
00273  *              2 - CRC error ('temp' is not updated)
00274  */
00275 uint8_t DS1820::read(float& temp) {
00276     if(present) {
00277         oneWire.reset();
00278         oneWire.skip();
00279         oneWire.write(0xBE);            // to read Scratchpad
00280         for(uint8_t i = 0; i < 9; i++)  // reading scratchpad registers
00281             data[i] = oneWire.read();
00282 
00283         if(oneWire.crc8(data, 8) != data[8])    // if calculated CRC does not match the stored one
00284             return 2;                           // return with CRC error
00285 
00286         // Convert the raw bytes to a 16bit unsigned value
00287         uint16_t*   p_word = reinterpret_cast < uint16_t * > (&data[0]);
00288 
00289 #if DEBUG
00290         serial.printf("raw = %#x\r\n", *p_word);
00291 #endif
00292 
00293         if(model_s) {
00294             *p_word = *p_word << 3;         // 9 bit resolution,  max conversion time = 750ms
00295             if(data[7] == 0x10) {
00296 
00297                 // "count remain" gives full 12 bit resolution
00298                 *p_word = (*p_word & 0xFFF0) + 12 - data[6];
00299             }
00300 
00301             // Convert the raw bytes to a 16bit signed fixed point value :
00302             // 1 sign bit, 7 integer bits, 8 fractional bits (two's compliment
00303             // and the LSB of the 16bit binary number represents 1/256th of a unit).
00304             *p_word = *p_word << 4;
00305             // Convert to floating point value
00306             temp = toFloat(*p_word);
00307             return 0;   // return with no errors
00308         }
00309         else {
00310             uint8_t cfg = (data[4] & 0x60); // default 12bit resolution, max conversion time = 750ms
00311 
00312             // at lower resolution, the low bits are undefined, so let's clear them
00313             if(cfg == 0x00)
00314                 *p_word = *p_word &~7;      //  9bit resolution, max conversion time = 93.75ms
00315             else
00316             if(cfg == 0x20)
00317                 *p_word = *p_word &~3;      // 10bit resolution, max conversion time = 187.5ms
00318             else
00319             if(cfg == 0x40)
00320                 *p_word = *p_word &~1;      // 11bit resolution, max conversion time = 375ms
00321 
00322             // Convert the raw bytes to a 16bit signed fixed point value :
00323             // 1 sign bit, 7 integer bits, 8 fractional bits (two's compliment
00324             // and the LSB of the 16bit binary number represents 1/256th of a unit).
00325             *p_word = *p_word << 4;
00326             // Convert to floating point value
00327             temp = toFloat(*p_word);
00328             return 0;   // return with no errors
00329         }
00330     }
00331     else
00332         return 1;   // error, sensor is not present
00333 }
00334 
00335 /**
00336  * @brief   Converts a 16-bit signed fixed point value to floating point value
00337  * @note    The 16-bit unsigned integer represnts actually
00338  *          a 16-bit signed fixed point value:
00339  *          1 sign bit, 7 integer bits, 8 fractional bits (two’s compliment
00340  *          and the LSB of the 16-bit binary number represents 1/256th of a unit).       
00341  * @param   16-bit unsigned integer
00342  * @retval  Floating point value
00343  */
00344 float DS1820::toFloat(uint16_t word) {
00345     if(word & 0x8000)
00346         return (-float(uint16_t(~word + 1)) / 256.0f);
00347     else
00348         return (float(word) / 256.0f);
00349 }
00350 
00351