Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Wed Aug 17 2022 05:29:14 by
1.7.2