Working version for L-tek FF1705

Dependencies:   OneWire

Dependents:   FROST

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