DS1820 library for multiple devices

Dependencies:   LinkedList

Dependents:   DS1820_HelloWorld FindingTemp ThermalWake ThermalWake2019Code

Fork of DS1820 by Erik -

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS1820.cpp Source File

DS1820.cpp

00001 #include "DS1820.h"
00002 
00003 #ifdef TARGET_STM
00004 //STM targets use opendrain mode since their GPIO code is too bad to be used like the others
00005     #define ONEWIRE_INPUT(pin)  pin->write(1)
00006     #define ONEWIRE_OUTPUT(pin) 
00007     #define ONEWIRE_INIT(pin)   pin->output(); pin->mode(OpenDrain)
00008     
00009     // TEMP, remove once STM fixed their stuff
00010 // Enable GPIO clock and return GPIO base address 
00011 static uint32_t Set_GPIO_Clock(uint32_t port_idx) { 
00012     uint32_t gpio_add = 0; 
00013     switch (port_idx) { 
00014         case PortA: 
00015            gpio_add = GPIOA_BASE; 
00016            __GPIOA_CLK_ENABLE(); 
00017            break; 
00018         case PortB: 
00019             gpio_add = GPIOB_BASE; 
00020             __GPIOB_CLK_ENABLE(); 
00021             break; 
00022 #if defined(GPIOC_BASE) 
00023         case PortC: 
00024             gpio_add = GPIOC_BASE; 
00025             __GPIOC_CLK_ENABLE(); 
00026             break; 
00027 #endif 
00028 #if defined(GPIOD_BASE) 
00029        case PortD: 
00030            gpio_add = GPIOD_BASE; 
00031             __GPIOD_CLK_ENABLE(); 
00032             break; 
00033 #endif 
00034 #if defined(GPIOF_BASE) 
00035         case PortF: 
00036             gpio_add = GPIOF_BASE; 
00037             __GPIOF_CLK_ENABLE(); 
00038             break; 
00039 #endif 
00040       default: 
00041            error("Pinmap error: wrong port number."); 
00042            break; 
00043    } 
00044    return gpio_add; 
00045 } 
00046 
00047 
00048 #else
00049     #define ONEWIRE_INPUT(pin)  pin->input()
00050     #define ONEWIRE_OUTPUT(pin) pin->output()
00051     #define ONEWIRE_INIT(pin)
00052 #endif
00053 
00054 LinkedList<node> DS1820::probes;
00055  
00056  
00057 DS1820::DS1820 (PinName data_pin, PinName power_pin, bool power_polarity) : _datapin(data_pin), _parasitepin(power_pin) {
00058     int byte_counter;
00059     _power_polarity = power_polarity;
00060 
00061     _power_mosfet = power_pin != NC;
00062     
00063     for(byte_counter=0;byte_counter<9;byte_counter++)
00064         RAM[byte_counter] = 0x00;
00065     
00066     ONEWIRE_INIT((&_datapin));
00067     // Temp code since the above doesn't actually do anything in mbed revisions up to 133
00068     #ifdef TARGET_STM
00069     
00070     uint32_t port_index = STM_PORT(data_pin); 
00071     uint32_t pin_index  = STM_PIN(data_pin); 
00072     
00073     // Enable GPIO clock 
00074     uint32_t gpio_add = Set_GPIO_Clock(port_index); 
00075     GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add; 
00076 
00077     gpio->OTYPER |= (uint32_t)(1 << pin_index); 
00078     #endif
00079     
00080     if (!unassignedProbe(&_datapin, _ROM))
00081         error("No unassigned DS1820 found!\n");
00082     else {
00083         _datapin.input();
00084         probes.append(this);
00085         _parasite_power = !read_power_supply();
00086     }
00087 }
00088 
00089 DS1820::~DS1820 (void) {
00090     node *tmp;
00091     for(int i=1; i<=probes.length(); i++)
00092     {
00093         tmp = probes.pop(i);
00094         if (tmp->data == this)
00095             probes.remove(i);
00096     }
00097 }
00098 
00099  
00100 bool DS1820::onewire_reset(DigitalInOut *pin) {
00101 // This will return false if no devices are present on the data bus
00102     bool presence=false;
00103     ONEWIRE_OUTPUT(pin);
00104     pin->write(0);          // bring low for 500 us
00105     wait_us(500);
00106     ONEWIRE_INPUT(pin);       // let the data line float high
00107     wait_us(90);            // wait 90us
00108     if (pin->read()==0) // see if any devices are pulling the data line low
00109         presence=true;
00110     wait_us(410);
00111     return presence;
00112 }
00113  
00114 void DS1820::onewire_bit_out (DigitalInOut *pin, bool bit_data) {
00115     ONEWIRE_OUTPUT(pin);
00116     pin->write(0);
00117     wait_us(3);                 // DXP modified from 5
00118     if (bit_data) {
00119         pin->write(1); // bring data line high
00120         wait_us(55);
00121     } else {
00122         wait_us(55);            // keep data line low
00123         pin->write(1);
00124         wait_us(10);            // DXP added to allow bus to float high before next bit_out
00125     }
00126 }
00127  
00128 void DS1820::onewire_byte_out(char data) { // output data character (least sig bit first).
00129     int n;
00130     for (n=0; n<8; n++) {
00131         onewire_bit_out(&this->_datapin, data & 0x01);
00132         data = data >> 1; // now the next bit is in the least sig bit position.
00133     }
00134 }
00135  
00136 bool DS1820::onewire_bit_in(DigitalInOut *pin) {
00137     bool answer;
00138     ONEWIRE_OUTPUT(pin);
00139     pin->write(0);
00140     wait_us(3);                 // DXP modofied from 5
00141     ONEWIRE_INPUT(pin);
00142     wait_us(10);                // DXP modified from 5
00143     answer = pin->read();
00144     wait_us(45);                // DXP modified from 50
00145     return answer;
00146 }
00147  
00148 char DS1820::onewire_byte_in() { // read byte, least sig byte first
00149     char answer = 0x00;
00150     int i;
00151     for (i=0; i<8; i++) {
00152         answer = answer >> 1; // shift over to make room for the next bit
00153         if (onewire_bit_in(&this->_datapin))
00154             answer = answer | 0x80; // if the data port is high, make this bit a 1
00155     }
00156     return answer;
00157 }
00158 
00159 bool DS1820::unassignedProbe(PinName pin) {
00160     DigitalInOut _pin(pin);
00161     ONEWIRE_INIT((&_pin));
00162     // Temp code since the above doesn't actually do anything in mbed revisions up to 133
00163     #ifdef TARGET_STM
00164     
00165     uint32_t port_index = STM_PORT(pin); 
00166     uint32_t pin_index  = STM_PIN(pin); 
00167     
00168     // Enable GPIO clock 
00169     uint32_t gpio_add = Set_GPIO_Clock(port_index); 
00170     GPIO_TypeDef *gpio = (GPIO_TypeDef *)gpio_add; 
00171 
00172     gpio->OTYPER |= (uint32_t)(1 << pin_index); 
00173     #endif
00174     char ROM_address[8];
00175     return search_ROM_routine(&_pin, 0xF0, ROM_address);
00176 }
00177  
00178 bool DS1820::unassignedProbe(DigitalInOut *pin, char *ROM_address) {
00179     return search_ROM_routine(pin, 0xF0, ROM_address);
00180 }
00181  
00182 bool DS1820::search_ROM_routine(DigitalInOut *pin, char command, char *ROM_address) {
00183     bool DS1820_done_flag = false;
00184     int DS1820_last_descrepancy = 0;
00185     char DS1820_search_ROM[8] = {0, 0, 0, 0, 0, 0, 0, 0};
00186     
00187     int descrepancy_marker, ROM_bit_index;
00188     bool return_value, Bit_A, Bit_B;
00189     char byte_counter, bit_mask;
00190  
00191     return_value=false;
00192     while (!DS1820_done_flag) {
00193         if (!onewire_reset(pin)) {
00194             return false;
00195         } else {
00196             ROM_bit_index=1;
00197             descrepancy_marker=0;
00198             char command_shift = command;
00199             for (int n=0; n<8; n++) {           // Search ROM command or Search Alarm command
00200                 onewire_bit_out(pin, command_shift & 0x01);
00201                 command_shift = command_shift >> 1; // now the next bit is in the least sig bit position.
00202             } 
00203             byte_counter = 0;
00204             bit_mask = 0x01;
00205             while (ROM_bit_index<=64) {
00206                 Bit_A = onewire_bit_in(pin);
00207                 Bit_B = onewire_bit_in(pin);
00208                 if (Bit_A & Bit_B) {
00209                     descrepancy_marker = 0; // data read error, this should never happen
00210                     ROM_bit_index = 0xFF;
00211                 } else {
00212                     if (Bit_A | Bit_B) {
00213                         // Set ROM bit to Bit_A
00214                         if (Bit_A) {
00215                             DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] | bit_mask; // Set ROM bit to one
00216                         } else {
00217                             DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] & ~bit_mask; // Set ROM bit to zero
00218                         }
00219                     } else {
00220                         // both bits A and B are low, so there are two or more devices present
00221                         if ( ROM_bit_index == DS1820_last_descrepancy ) {
00222                             DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] | bit_mask; // Set ROM bit to one
00223                         } else {
00224                             if ( ROM_bit_index > DS1820_last_descrepancy ) {
00225                                 DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] & ~bit_mask; // Set ROM bit to zero
00226                                 descrepancy_marker = ROM_bit_index;
00227                             } else {
00228                                 if (( DS1820_search_ROM[byte_counter] & bit_mask) == 0x00 )
00229                                     descrepancy_marker = ROM_bit_index;
00230                             }
00231                         }
00232                     }
00233                     onewire_bit_out (pin, DS1820_search_ROM[byte_counter] & bit_mask);
00234                     ROM_bit_index++;
00235                     if (bit_mask & 0x80) {
00236                         byte_counter++;
00237                         bit_mask = 0x01;
00238                     } else {
00239                         bit_mask = bit_mask << 1;
00240                     }
00241                 }
00242             }
00243             DS1820_last_descrepancy = descrepancy_marker;
00244             if (ROM_bit_index != 0xFF) {
00245                 int i = 1;
00246                 node *list_container;
00247                 while(1) {
00248                     list_container = probes.pop(i);
00249                     if (list_container == NULL) {                             //End of list, or empty list
00250                         if (ROM_checksum_error(DS1820_search_ROM)) {          // Check the CRC
00251                             return false;
00252                         }
00253                         for(byte_counter=0;byte_counter<8;byte_counter++)
00254                             ROM_address[byte_counter] = DS1820_search_ROM[byte_counter];
00255                         return true;
00256                     } else {                    //Otherwise, check if ROM is already known
00257                         bool equal = true;
00258                         DS1820 *pointer = (DS1820*) list_container->data;
00259                         char *ROM_compare = pointer->_ROM;
00260                         
00261                         for(byte_counter=0;byte_counter<8;byte_counter++) {
00262                             if ( ROM_compare[byte_counter] != DS1820_search_ROM[byte_counter])
00263                                 equal = false;
00264                         }
00265                         if (equal)
00266                             break;
00267                         else
00268                             i++;
00269                     }
00270                 }                        
00271             }
00272         }
00273         if (DS1820_last_descrepancy == 0)
00274             DS1820_done_flag = true;
00275     }
00276     return return_value;
00277 }
00278  
00279 void DS1820::match_ROM() {
00280 // Used to select a specific device
00281     int i;
00282     onewire_reset(&this->_datapin);
00283     onewire_byte_out( 0x55);  //Match ROM command
00284     for (i=0;i<8;i++) {
00285         onewire_byte_out(_ROM[i]);
00286     }
00287 }
00288  
00289 void DS1820::skip_ROM() {
00290     onewire_reset(&this->_datapin);
00291     onewire_byte_out(0xCC);   // Skip ROM command
00292 }
00293  
00294 bool DS1820::ROM_checksum_error(char *_ROM_address) {
00295     char _CRC=0x00;
00296     int i;
00297     for(i=0;i<7;i++) // Only going to shift the lower 7 bytes
00298         _CRC = CRC_byte(_CRC, _ROM_address[i]);
00299     // After 7 bytes CRC should equal the 8th byte (ROM CRC)
00300     return (_CRC!=_ROM_address[7]); // will return true if there is a CRC checksum mis-match         
00301 }
00302  
00303 bool DS1820::RAM_checksum_error() {
00304     char _CRC=0x00;
00305     int i;
00306     for(i=0;i<8;i++) // Only going to shift the lower 8 bytes
00307         _CRC = CRC_byte(_CRC, RAM[i]);
00308     // After 8 bytes CRC should equal the 9th byte (RAM CRC)
00309     return (_CRC!=RAM[8]); // will return true if there is a CRC checksum mis-match        
00310 }
00311  
00312 char DS1820::CRC_byte (char _CRC, char byte ) {
00313     int j;
00314     for(j=0;j<8;j++) {
00315         if ((byte & 0x01 ) ^ (_CRC & 0x01)) {
00316             // DATA ^ LSB CRC = 1
00317             _CRC = _CRC>>1;
00318             // Set the MSB to 1
00319             _CRC = _CRC | 0x80;
00320             // Check bit 3
00321             if (_CRC & 0x04) {
00322                 _CRC = _CRC & 0xFB; // Bit 3 is set, so clear it
00323             } else {
00324                 _CRC = _CRC | 0x04; // Bit 3 is clear, so set it
00325             }
00326             // Check bit 4
00327             if (_CRC & 0x08) {
00328                 _CRC = _CRC & 0xF7; // Bit 4 is set, so clear it
00329             } else {
00330                 _CRC = _CRC | 0x08; // Bit 4 is clear, so set it
00331             }
00332         } else {
00333             // DATA ^ LSB CRC = 0
00334             _CRC = _CRC>>1;
00335             // clear MSB
00336             _CRC = _CRC & 0x7F;
00337             // No need to check bits, with DATA ^ LSB CRC = 0, they will remain unchanged
00338         }
00339         byte = byte>>1;
00340     }
00341 return _CRC;
00342 }
00343  
00344 int DS1820::convertTemperature(bool wait, devices device) {
00345     // Convert temperature into scratchpad RAM for all devices at once
00346     int delay_time = 750; // Default delay time
00347     char resolution;
00348     if (device==all_devices)
00349         skip_ROM();          // Skip ROM command, will convert for ALL devices
00350     else {
00351         match_ROM();
00352         if ((FAMILY_CODE == FAMILY_CODE_DS18B20 ) || (FAMILY_CODE == FAMILY_CODE_DS1822 )) {
00353             resolution = RAM[4] & 0x60;
00354             if (resolution == 0x00) // 9 bits
00355                 delay_time = 94;
00356             if (resolution == 0x20) // 10 bits
00357                 delay_time = 188;
00358             if (resolution == 0x40) // 11 bits. Note 12bits uses the 750ms default
00359                 delay_time = 375;
00360         }
00361     }
00362     
00363     onewire_byte_out( 0x44);  // perform temperature conversion
00364     if (_parasite_power) {
00365         if (_power_mosfet) {
00366             _parasitepin = _power_polarity;     // Parasite power strong pullup
00367             wait_ms(delay_time);
00368             _parasitepin = !_power_polarity;
00369             delay_time = 0;
00370         } else {
00371             _datapin.output();
00372             _datapin.write(1);
00373             wait_ms(delay_time);
00374             _datapin.input();
00375         }
00376     } else {
00377         if (wait) {
00378             wait_ms(delay_time);
00379             delay_time = 0;
00380         }
00381     }
00382     return delay_time;
00383 }
00384  
00385 void DS1820::read_RAM() {
00386     // This will copy the DS1820's 9 bytes of RAM data
00387     // into the objects RAM array. Functions that use
00388     // RAM values will automaticly call this procedure.
00389     int i;
00390     match_ROM();             // Select this device
00391     onewire_byte_out( 0xBE);   //Read Scratchpad command
00392     for(i=0;i<9;i++) {
00393         RAM[i] = onewire_byte_in();
00394     }
00395 //    if (!RAM_checksum_error())
00396 //       crcerr = 1;
00397 }
00398 
00399 bool DS1820::setResolution(unsigned int resolution) {
00400     bool answer = false;
00401     resolution = resolution - 9;
00402     if (resolution < 4) {
00403         resolution = resolution<<5; // align the bits
00404         RAM[4] = (RAM[4] & 0x60) | resolution; // mask out old data, insert new
00405         write_scratchpad ((RAM[2]<<8) + RAM[3]);
00406 //        store_scratchpad (DS1820::this_device); // Need to test if this is required
00407         answer = true;
00408     }
00409     return answer;
00410 }
00411  
00412 void DS1820::write_scratchpad(int data) {
00413     RAM[3] = data;
00414     RAM[2] = data>>8;
00415     match_ROM();
00416     onewire_byte_out(0x4E);   // Copy scratchpad into DS1820 ram memory
00417     onewire_byte_out(RAM[2]); // T(H)
00418     onewire_byte_out(RAM[3]); // T(L)
00419     if ((FAMILY_CODE == FAMILY_CODE_DS18B20 ) || (FAMILY_CODE == FAMILY_CODE_DS1822 )) {
00420         onewire_byte_out(RAM[4]); // Configuration register
00421     }
00422 }
00423  
00424 float DS1820::temperature(char scale) {
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     float answer, remaining_count, count_per_degree;
00431     int reading;
00432     read_RAM();
00433     if (RAM_checksum_error())
00434         // Indicate we got a CRC error
00435         answer = invalid_conversion;
00436     else {
00437         reading = (RAM[1] << 8) + RAM[0];
00438         if (reading & 0x8000) { // negative degrees C
00439             reading = 0-((reading ^ 0xffff) + 1); // 2's comp then convert to signed int
00440         }
00441         answer = reading +0.0; // convert to floating point
00442         if ((FAMILY_CODE == FAMILY_CODE_DS18B20 ) || (FAMILY_CODE == FAMILY_CODE_DS1822 )) {
00443             answer = answer / 16.0f;
00444         }
00445         else {
00446             remaining_count = RAM[6];
00447             count_per_degree = RAM[7];
00448             answer = floor(answer/2.0f) - 0.25f + (count_per_degree - remaining_count) / count_per_degree;
00449         }
00450         if (scale=='F' or scale=='f')
00451             // Convert to deg F
00452             answer = answer * 9.0f / 5.0f + 32.0f;
00453     }
00454     return answer;
00455 }
00456  
00457 bool DS1820::read_power_supply(devices device) {
00458 // This will return true if the device (or all devices) are Vcc powered
00459 // This will return false if the device (or ANY device) is parasite powered
00460     if (device==all_devices)
00461         skip_ROM();          // Skip ROM command, will poll for any device using parasite power
00462     else
00463         match_ROM();
00464     onewire_byte_out(0xB4);   // Read power supply command
00465     return onewire_bit_in(&this->_datapin);
00466 }
00467 
00468 
00469 // Contributed by John M. Larkin (jlarkin@whitworth.edu)
00470 unsigned long long DS1820::whoAmI() {
00471 // This will return the 64 bit address of the connected DS1820
00472     unsigned long long myName = 0;
00473     for (int i = 0; i<8; i++) {
00474         myName = (myName<<8) | _ROM[i];
00475     }
00476     return myName;
00477 }