Yet another DS1820 lib, but this one is make in sweat of struggling with other ones. It's a fork really of <insert original as mbed doesn't track idk why> with *added capability* of not blocking.

Dependents:   Nucleo_praktyki

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS1820.cpp Source File

DS1820.cpp

00001 #include "DS1820.h"
00002 #include "mbed.h"
00003 
00004 // Global variables shared between all DS1820 objects
00005 bool DS1820_done_flag;
00006 int  DS1820_last_descrepancy;
00007 char DS1820_search_ROM[8];
00008 
00009 
00010 DS1820::DS1820 (PinName data_pin, PinName power_pin) : _datapin(data_pin), _parasitepin(power_pin)
00011 {
00012     int byte_counter;
00013 
00014     _last_temperature = NULL;
00015     _parasite_power = true;
00016     for(byte_counter=0; byte_counter<8; byte_counter++)
00017         ROM[byte_counter] = 0xFF;
00018     for(byte_counter=0; byte_counter<9; byte_counter++)
00019         RAM[byte_counter] = 0x00;
00020 }
00021 DS1820::DS1820 (PinName data_pin) : _datapin(data_pin), _parasitepin(NC)
00022 {
00023     int byte_counter;
00024 
00025     _last_temperature = NULL;
00026     _parasite_power = false;
00027     for(byte_counter=0; byte_counter<8; byte_counter++)
00028         ROM[byte_counter] = 0xFF;
00029     for(byte_counter=0; byte_counter<9; byte_counter++)
00030         RAM[byte_counter] = 0x00;
00031 }
00032 
00033 void DS1820::_auto_convert_temperature()
00034 {
00035     convert_temperature(false, DS1820::this_device);
00036 }
00037 
00038 void DS1820::enable_auto_convert(float interval)
00039 {
00040     _autoConvert.attach(this, &DS1820::_auto_convert_temperature, interval);
00041 }
00042 
00043 bool DS1820::onewire_reset()
00044 {
00045 // This will return false if no devices are present on the data bus
00046     bool presence=false;
00047     _datapin.output();
00048     _datapin.mode(PullUp);
00049     _datapin = 0;           // bring low for 500 us
00050     wait_us(500);
00051     _datapin.input();       // let the data line float high
00052     _datapin.mode(PullUp);
00053     wait_us(90);            // wait 90us
00054     if (_datapin.read()==0) // see if any devices are pulling the data line low
00055         presence=true;
00056     wait_us(410);
00057     return presence;
00058 }
00059 
00060 void DS1820::onewire_bit_out (bool bit_data)
00061 {
00062     _datapin.output();
00063     _datapin = 0;
00064     wait_us(5);
00065     if (bit_data) {
00066         _datapin.input(); // bring data line high
00067         _datapin.mode(PullUp);
00068         wait_us(55);
00069     } else {
00070         wait_us(55);            // keep data line low
00071         _datapin.input();
00072         _datapin.mode(PullUp);
00073     }
00074 }
00075 
00076 void DS1820::onewire_byte_out(char data)   // output data character (least sig bit first).
00077 {
00078     int n;
00079     for (n=0; n<8; n++) {
00080         onewire_bit_out(data & 0x01);
00081         data = data >> 1; // now the next bit is in the least sig bit position.
00082     }
00083 }
00084 
00085 bool DS1820::onewire_bit_in()
00086 {
00087     bool answer;
00088     _datapin.output();
00089     _datapin = 0;
00090     wait_us(5);
00091     _datapin.input();
00092     _datapin.mode(PullUp);
00093     wait_us(5);
00094     answer = _datapin.read();
00095     wait_us(50);
00096     return answer;
00097 }
00098 
00099 char DS1820::onewire_byte_in()   // read byte, least sig byte first
00100 {
00101     char answer = 0x00;
00102     int i;
00103     for (i=0; i<8; i++) {
00104         answer = answer >> 1; // shift over to make room for the next bit
00105         if (onewire_bit_in())
00106             answer = answer | 0x80; // if the data port is high, make this bit a 1
00107     }
00108     return answer;
00109 }
00110 
00111 bool DS1820::search_ROM()
00112 {
00113     return search_ROM_routine(0xF0);    // Search ROM command
00114 }
00115 
00116 bool DS1820::search_alarm()
00117 {
00118     return search_ROM_routine(0xEC);    // Search Alarm command
00119 }
00120 
00121 bool DS1820::search_ROM_routine(char command)
00122 {
00123     extern bool DS1820_done_flag;
00124     extern int DS1820_last_descrepancy;
00125     extern char DS1820_search_ROM[8];
00126     int descrepancy_marker, ROM_bit_index;
00127     bool return_value, Bit_A, Bit_B;
00128     char byte_counter, bit_mask;
00129 
00130     return_value=false;
00131     if (!DS1820_done_flag) {
00132         if (!onewire_reset()) {
00133             DS1820_last_descrepancy = 0; // no devices present
00134         } else {
00135             ROM_bit_index=1;
00136             descrepancy_marker=0;
00137             onewire_byte_out(command); // Search ROM command or Search Alarm command
00138             byte_counter = 0;
00139             bit_mask = 0x01;
00140             while (ROM_bit_index<=64) {
00141                 Bit_A = onewire_bit_in();
00142                 Bit_B = onewire_bit_in();
00143                 if (Bit_A & Bit_B) {
00144                     descrepancy_marker = 0; // data read error, this should never happen
00145                     ROM_bit_index = 0xFF;
00146                 } else {
00147                     if (Bit_A | Bit_B) {
00148                         // Set ROM bit to Bit_A
00149                         if (Bit_A) {
00150                             DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] | bit_mask; // Set ROM bit to one
00151                         } else {
00152                             DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] & ~bit_mask; // Set ROM bit to zero
00153                         }
00154                     } else {
00155                         // both bits A and B are low, so there are two or more devices present
00156                         if ( ROM_bit_index == DS1820_last_descrepancy ) {
00157                             DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] | bit_mask; // Set ROM bit to one
00158                         } else {
00159                             if ( ROM_bit_index > DS1820_last_descrepancy ) {
00160                                 DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] & ~bit_mask; // Set ROM bit to zero
00161                                 descrepancy_marker = ROM_bit_index;
00162                             } else {
00163                                 if (( DS1820_search_ROM[byte_counter] & bit_mask) == 0x00 )
00164                                     descrepancy_marker = ROM_bit_index;
00165                             }
00166                         }
00167                     }
00168                     onewire_bit_out (DS1820_search_ROM[byte_counter] & bit_mask);
00169                     ROM_bit_index++;
00170                     if (bit_mask & 0x80) {
00171                         byte_counter++;
00172                         bit_mask = 0x01;
00173                     } else {
00174                         bit_mask = bit_mask << 1;
00175                     }
00176                 }
00177             }
00178             DS1820_last_descrepancy = descrepancy_marker;
00179             if (ROM_bit_index != 0xFF) {
00180                 for(byte_counter=0; byte_counter<8; byte_counter++)
00181                     ROM[byte_counter] = DS1820_search_ROM[byte_counter];
00182                 return_value = true;
00183             }
00184         }
00185         if (DS1820_last_descrepancy == 0)
00186             DS1820_done_flag = true;
00187     }
00188     return return_value;
00189 }
00190 
00191 void DS1820::search_ROM_setup()
00192 {
00193     extern bool DS1820_done_flag;
00194     extern int DS1820_last_descrepancy;
00195     extern char DS1820_search_ROM[8];
00196     DS1820_done_flag = false;
00197     DS1820_last_descrepancy = 0;
00198     int i;
00199     for (i=0; i<8; i++)
00200         DS1820_search_ROM[i]=0x00;
00201 }
00202 
00203 void DS1820::read_ROM()
00204 {
00205     // NOTE: This command can only be used when there is one DS1820 on the bus. If this command
00206     // is used when there is more than one slave present on the bus, a data collision will occur
00207     // when all the DS1820s attempt to respond at the same time.
00208     int i;
00209     onewire_reset();
00210     onewire_byte_out(0x33);   // Read ROM id
00211     for (i=0; i<8; i++)
00212         ROM[i]=onewire_byte_in();
00213 }
00214 
00215 void DS1820::match_ROM()
00216 {
00217 // Used to select a specific device
00218     int i;
00219     onewire_reset();
00220     onewire_byte_out( 0x55);  //Match ROM command
00221     for (i=0; i<8; i++)
00222         onewire_byte_out(ROM[i]);
00223 }
00224 
00225 void DS1820::skip_ROM()
00226 {
00227     onewire_reset();
00228     onewire_byte_out(0xCC);   // Skip ROM command
00229 }
00230 
00231 bool DS1820::ROM_checksum_error()
00232 {
00233     char xCRC=0x00;
00234     int i;
00235     for(i=0; i<7; i++) // Only going to shift the lower 7 bytes
00236         xCRC = CRC_byte(xCRC, ROM[i]);
00237     // After 7 bytes CRC should equal the 8th byte (ROM CRC)
00238     return (xCRC!=ROM[7]); // will return true if there is a CRC checksum error
00239 }
00240 
00241 bool DS1820::RAM_checksum_error()
00242 {
00243     char xCRC=0x00;
00244     int i;
00245     read_RAM();
00246     for(i=0; i<8; i++) // Only going to shift the lower 8 bytes
00247         xCRC = CRC_byte(xCRC, RAM[i]);
00248     // After 8 bytes CRC should equal the 9th byte (RAM CRC)
00249     return (xCRC!=RAM[8]); // will return true if there is a CRC checksum error
00250 }
00251 
00252 char DS1820::CRC_byte (char xCRC, char byte )
00253 {
00254     int j;
00255     for(j=0; j<8; j++) {
00256         if ((byte & 0x01 ) ^ (xCRC & 0x01)) {
00257             // DATA ^ LSB CRC = 1
00258             xCRC = xCRC>>1;
00259             // Set the MSB to 1
00260             xCRC = xCRC | 0x80;
00261             // Check bit 3
00262             if (xCRC & 0x04) {
00263                 xCRC = xCRC & 0xFB; // Bit 3 is set, so clear it
00264             } else {
00265                 xCRC = xCRC | 0x04; // Bit 3 is clear, so set it
00266             }
00267             // Check bit 4
00268             if (xCRC & 0x08) {
00269                 xCRC = xCRC & 0xF7; // Bit 4 is set, so clear it
00270             } else {
00271                 xCRC = xCRC | 0x08; // Bit 4 is clear, so set it
00272             }
00273         } else {
00274             // DATA ^ LSB xCRC = 0
00275             xCRC = xCRC>>1;
00276             // clear MSB
00277             xCRC = xCRC & 0x7F;
00278             // No need to check bits, with DATA ^ LSB xCRC = 0, they will remain unchanged
00279         }
00280         byte = byte>>1;
00281     }
00282     return xCRC;
00283 }
00284 
00285 void DS1820::convert_temperature(bool blocking, devices device)
00286 {
00287     // Convert temperature into scratchpad RAM for all devices at once
00288     int delay_time = 750; // Default delay time (for 12 bits)
00289     char resolution;
00290     if (device==all_devices)
00291         skip_ROM();          // Skip ROM command, will convert for ALL devices
00292     else {
00293         match_ROM();
00294         if (FAMILY_CODE == FAMILY_CODE_DS18B20 ) {
00295             resolution = RAM[4] & 0x60;
00296             if (resolution == 0x00) // 9 bits
00297                 delay_time = 94;
00298             if (resolution == 0x20) // 10 bits
00299                 delay_time = 188;
00300             if (resolution == 0x40) // 11 bits. Note 12bits uses the 750ms default
00301                 delay_time = 375;
00302         }
00303     }
00304     onewire_byte_out( 0x44);  // perform temperature conversion
00305     if (_parasite_power)
00306         _parasitepin = 1;       // Parasite power strong pullup
00307     if (blocking)  { // blocking
00308         wait_ms(delay_time);
00309         _temperature_raw();
00310     } else { // non-blocking
00311         float timeout_time = ((float)delay_time)/1000.0;
00312         auto_get_new_temperature.attach(callback(this, &DS1820::_temperature_raw), timeout_time); // update _last_temperture automagically
00313     }
00314     if (_parasite_power)
00315         _parasitepin = 0;
00316 }
00317 
00318 void DS1820::read_RAM()
00319 {
00320     // This will copy the DS1820's 9 bytes of RAM data
00321     // into the objects RAM array. Functions that use
00322     // RAM values will automaticly call this procedure.
00323     int i;
00324     match_ROM();             // Select this device
00325     onewire_byte_out( 0xBE);   //Read Scratchpad command
00326     for(i=0; i<9; i++) {
00327         RAM[i] = onewire_byte_in();
00328     }
00329 }
00330 
00331 bool DS1820::set_configuration_bits(unsigned int resolution, devices device)
00332 {
00333     bool answer = false;
00334     resolution = resolution - 9;
00335     if (resolution < 4) {
00336         if (device==all_devices)
00337             skip_ROM();
00338         else
00339             match_ROM();
00340         resolution = resolution<<5; // align the bits
00341         RAM[4] = (RAM[4] & 0b00011111) | resolution; // mask out old data, insert new
00342         write_scratchpad ((RAM[2]<<8) + RAM[3]);
00343 //        store_scratchpad (DS1820::this_device); // Need to test if this is required
00344         answer = true;
00345     }
00346     return answer;
00347 }
00348 
00349 int DS1820::read_scratchpad()
00350 {
00351     int answer;
00352     read_RAM();
00353     answer = (RAM[2]<<8) + RAM[3];
00354     return answer;
00355 }
00356 
00357 void DS1820::write_scratchpad(int data)
00358 {
00359     RAM[3] = data;
00360     RAM[2] = data>>8;
00361     match_ROM();
00362     onewire_byte_out(0x4E);   // Copy scratchpad into DS1820 ram memory
00363     onewire_byte_out(RAM[2]); // T(H)
00364     onewire_byte_out(RAM[3]); // T(L)
00365     if ( FAMILY_CODE == FAMILY_CODE_DS18B20 ) {
00366         onewire_byte_out(RAM[4]); // Configuration register
00367     }
00368 }
00369 
00370 void DS1820::store_scratchpad(devices device)
00371 {
00372     if (device==all_devices)
00373         skip_ROM();          // Skip ROM command, will store for ALL devices
00374     else
00375         match_ROM();
00376     onewire_byte_out(0x48);   // Write scratchpad into E2 command
00377     if (_parasite_power)
00378         _parasitepin=1;
00379     wait_ms(10);            // Parasite power strong pullup for 10ms
00380     if (_parasite_power)
00381         _parasitepin=0;
00382 }
00383 
00384 int DS1820::recall_scratchpad(devices device)
00385 {
00386 // This copies the E2 values into the DS1820's memory.
00387 // If you specify all_devices this will return zero, otherwise
00388 // it will return the value of the scratchpad memory.
00389     int answer=0;
00390     if (device==all_devices)
00391         skip_ROM();          // Skip ROM command, will recall for ALL devices
00392     else
00393         match_ROM();
00394     onewire_byte_out(0xB8);   // Recall E2 data to scratchpad command
00395     wait_ms(10); // not sure I like polling for completion
00396     // it could cause an infinite loop
00397     if (device==DS1820::this_device) {
00398         read_RAM();
00399         answer = read_scratchpad();
00400     }
00401     return answer;
00402 }
00403 void DS1820::_temperature_raw()
00404 {
00405     float answer, remaining_count, count_per_degree;
00406     int reading;
00407     read_RAM();
00408     reading = (RAM[1] << 8) + RAM[0];
00409     if (reading & 0x8000) { // negative degrees C
00410         reading = 0-((reading ^ 0xffff) + 1); // 2's comp then convert to signed int
00411     }
00412     answer = reading +0.0; // convert to floating point
00413     if ( FAMILY_CODE == FAMILY_CODE_DS18B20 ) {
00414         answer = answer / 8.0;
00415     } else {
00416         remaining_count = RAM[6];
00417         count_per_degree = RAM[7];
00418         answer = answer - 0.25 + (count_per_degree - remaining_count) / count_per_degree;
00419     }
00420     _last_temperature = answer;
00421 }
00422 
00423 float DS1820::temperature(char scale)
00424 {
00425 // The data specs state that count_per_degree should be 0x10 (16), I found my devices
00426 // to have a count_per_degree of 0x4B (75). With the standard resolution of 1/2 deg C
00427 // this allowed an expanded resolution of 1/150th of a deg C. I wouldn't rely on this
00428 // being super acurate, but it does allow for a smooth display in the 1/10ths of a
00429 // deg C or F scales.
00430     if (_last_temperature == NULL) {
00431         convert_temperature(true);
00432     }
00433     float answer = _last_temperature;
00434     if (scale=='C' or scale=='c')
00435         answer = answer / 2.0;
00436     else
00437         // Convert to deg F
00438         answer = answer * 9.0 / 10.0 + 32.0;
00439     return answer;
00440 }
00441 
00442 bool DS1820::read_power_supply(devices device)
00443 {
00444 // This will return true if the device (or all devices) are Vcc powered
00445 // This will return false if the device (or ANY device) is parasite powered
00446     if (device==all_devices)
00447         skip_ROM();          // Skip ROM command, will poll for any device using parasite power
00448     else
00449         match_ROM();
00450     onewire_byte_out(0xB4);   // Read power supply command
00451     return onewire_bit_in();
00452 }