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.
OneWire.cpp
00001 /* 00002 Copyright (c) 2007, Jim Studt (original old version - many contributors since) 00003 00004 The latest version of this library may be found at: 00005 http://www.pjrc.com/teensy/td_libs_Onehtml 00006 00007 OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since 00008 January 2010. At the time, it was in need of many bug fixes, but had 00009 been abandoned the original author (Jim Studt). None of the known 00010 contributors were interested in maintaining One Paul typically 00011 works on OneWire every 6 to 12 months. Patches usually wait that 00012 long. If anyone is interested in more actively maintaining OneWire, 00013 please contact Paul. 00014 00015 Version 2.2: 00016 Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com 00017 Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030 00018 Fix DS18B20 example negative temperature 00019 Fix DS18B20 example's low res modes, Ken Butcher 00020 Improve reset timing, Mark Tillotson 00021 Add const qualifiers, Bertrik Sikken 00022 Add initial value input to crc16, Bertrik Sikken 00023 Add target_search() function, Scott Roberts 00024 00025 Version 2.1: 00026 Arduino 1.0 compatibility, Paul Stoffregen 00027 Improve temperature example, Paul Stoffregen 00028 DS250x_PROM example, Guillermo Lovato 00029 PIC32 (chipKit) compatibility, Jason Dangel, dangel.jason AT gmail.com 00030 Improvements from Glenn Trewitt: 00031 - crc16() now works 00032 - check_crc16() does all of calculation/checking work. 00033 - Added read_bytes() and write_bytes(), to reduce tedious loops. 00034 - Added ds2408 example. 00035 Delete very old, out-of-date readme file (info is here) 00036 00037 Version 2.0: Modifications by Paul Stoffregen, January 2010: 00038 http://www.pjrc.com/teensy/td_libs_Onehtml 00039 Search fix from Robin James 00040 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27 00041 Use direct optimized I/O in all cases 00042 Disable interrupts during timing critical sections 00043 (this solves many random communication errors) 00044 Disable interrupts during read-modify-write I/O 00045 Reduce RAM consumption by eliminating unnecessary 00046 variables and trimming many to 8 bits 00047 Optimize both crc8 - table version moved to flash 00048 00049 Modified to work with larger numbers of devices - avoids loop. 00050 Tested in Arduino 11 alpha with 12 sensors. 00051 26 Sept 2008 -- Robin James 00052 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27 00053 00054 Updated to work with arduino-0008 and to include skip() as of 00055 2007/07/06. --RJL20 00056 00057 Modified to calculate the 8-bit CRC directly, avoiding the need for 00058 the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010 00059 -- Tom Pollard, Jan 23, 2008 00060 00061 Jim Studt's original library was modified by Josh Larios. 00062 00063 Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008 00064 00065 Permission is hereby granted, free of charge, to any person obtaining 00066 a copy of this software and associated documentation files (the 00067 "Software"), to deal in the Software without restriction, including 00068 without limitation the rights to use, copy, modify, merge, publish, 00069 distribute, sublicense, and/or sell copies of the Software, and to 00070 permit persons to whom the Software is furnished to do so, subject to 00071 the following conditions: 00072 00073 The above copyright notice and this permission notice shall be 00074 included in all copies or substantial portions of the Software. 00075 00076 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00077 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00078 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00079 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 00080 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00081 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00082 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00083 00084 Much of the code was inspired by Derek Yerger's code, though I don't 00085 think much of that remains. In any event that was.. 00086 (copyleft) 2006 by Derek Yerger - Free to distribute freely. 00087 00088 The CRC code was excerpted and inspired by the Dallas Semiconductor 00089 sample code bearing this copyright. 00090 //--------------------------------------------------------------------------- 00091 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. 00092 // 00093 // Permission is hereby granted, free of charge, to any person obtaining a 00094 // copy of this software and associated documentation files (the "Software"), 00095 // to deal in the Software without restriction, including without limitation 00096 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 00097 // and/or sell copies of the Software, and to permit persons to whom the 00098 // Software is furnished to do so, subject to the following conditions: 00099 // 00100 // The above copyright notice and this permission notice shall be included 00101 // in all copies or substantial portions of the Software. 00102 // 00103 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00104 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00105 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00106 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES 00107 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00108 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00109 // OTHER DEALINGS IN THE SOFTWARE. 00110 // 00111 // Except as contained in this notice, the name of Dallas Semiconductor 00112 // shall not be used except as stated in the Dallas Semiconductor 00113 // Branding Policy. 00114 //-------------------------------------------------------------------------- 00115 */ 00116 #include "OneWire.h" 00117 00118 00119 /** 00120 * @brief Constructs a OneWire object. 00121 * @note GPIO is configured as output and an internal pull up resistor is connected. 00122 * But because for STM chips it takes very long time to change from output 00123 * to input an open drain mode is used rather and the GPIO remains output forever. 00124 * @param 00125 * @retval 00126 */ 00127 OneWire::OneWire(PinName pin, int sample_point_us /* = 13 */) : 00128 DigitalInOut(pin), 00129 _sample_point_us(sample_point_us) 00130 { 00131 Timer timer; 00132 00133 MODE(); // set mode to either OpenDrain for STM or PullUp for others 00134 00135 // Measure bus transition time from ouput to input 00136 timer.reset(); 00137 OUTPUT(); // set as output 00138 WRITE(0); // pull the line down 00139 timer.start(); 00140 INPUT(); // set as input (and release the bus) 00141 timer.stop(); 00142 _out_to_in_transition_us = timer.read_us(); 00143 00144 MBED_ASSERT(_out_to_in_transition_us < _sample_point_us); 00145 00146 INIT_WAIT; 00147 #if ONEWIRE_SEARCH 00148 reset_search(); 00149 #endif 00150 } 00151 00152 /** 00153 * @brief Performs the onewire reset function. 00154 * @note We will wait up to 250uS for the bus to come high, 00155 * if it doesn't then it is broken or shorted and we return a 0; 00156 * @param 00157 * @retval 1 if a device asserted a presence pulse, 0 otherwise. 00158 */ 00159 uint8_t OneWire::reset(void) 00160 { 00161 uint8_t present; 00162 00163 OUTPUT(); 00164 WRITE(0); // pull down the 1-wire bus do create reset pulse 00165 WAIT_US(500); // wait at least 480 us 00166 INPUT(); // release the 1-wire bus and go into receive mode 00167 WAIT_US(90); // DS1820 waits about 15 to 60 us and generates a 60 to 240 us presence pulse 00168 present = !READ(); // read the presence pulse 00169 WAIT_US(420); 00170 00171 return present; 00172 } 00173 00174 /** 00175 * @brief Writes a bit. 00176 * @note GPIO registers are used for STM chips to cut time. 00177 * @param 00178 * @retval 00179 */ 00180 void OneWire::write_bit(uint8_t v) 00181 { 00182 OUTPUT(); 00183 if (v & 1) { 00184 WRITE(0); // drive output low 00185 WAIT_US(1); 00186 WRITE(1); // drive output high 00187 WAIT_US(60); 00188 } 00189 else { 00190 WRITE(0); // drive output low 00191 WAIT_US(60); 00192 WRITE(1); // drive output high 00193 WAIT_US(1); 00194 } 00195 } 00196 00197 /** 00198 * @brief Reads a bit. 00199 * @note GPIO registers are used for STM chips to cut time. 00200 * @param 00201 * @retval 00202 */ 00203 uint8_t OneWire::read_bit(void) 00204 { 00205 uint8_t r; 00206 00207 OUTPUT(); 00208 WRITE(0); 00209 INPUT(); 00210 wait_us(_sample_point_us - _out_to_in_transition_us); // wait till sample point 00211 r = READ(); 00212 WAIT_US(55); 00213 return r; 00214 } 00215 00216 /** 00217 * @brief Writes a byte. 00218 * @note The writing code uses the active drivers to raise the 00219 pin high, if you need power after the write (e.g. DS18S20 in 00220 parasite power mode) then set 'power' to 1, otherwise the pin will 00221 go tri-state at the end of the write to avoid heating in a short or 00222 other mishap. 00223 * @param 00224 * @retval 00225 */ 00226 void OneWire::write_byte(uint8_t v, uint8_t power /* = 0 */ ) 00227 { 00228 uint8_t bitMask; 00229 00230 for (bitMask = 0x01; bitMask; bitMask <<= 1) 00231 write_bit((bitMask & v) ? 1 : 0); 00232 if (!power) 00233 INPUT(); 00234 } 00235 00236 /** 00237 * @brief Writes bytes. 00238 * @note 00239 * @param 00240 * @retval 00241 */ 00242 void OneWire::write_bytes(const uint8_t* buf, uint16_t count, bool power /* = 0 */ ) 00243 { 00244 for (uint16_t i = 0; i < count; i++) 00245 write_byte(buf[i]); 00246 if (!power) 00247 INPUT(); 00248 } 00249 00250 /** 00251 * @brief Reads a byte. 00252 * @note 00253 * @param 00254 * @retval 00255 */ 00256 uint8_t OneWire::read_byte() 00257 { 00258 uint8_t bitMask; 00259 uint8_t r = 0; 00260 00261 for (bitMask = 0x01; bitMask; bitMask <<= 1) { 00262 if (read_bit()) 00263 r |= bitMask; 00264 } 00265 00266 return r; 00267 } 00268 00269 /** 00270 * @brief Reads bytes. 00271 * @note 00272 * @param 00273 * @retval 00274 */ 00275 void OneWire::read_bytes(uint8_t* buf, uint16_t count) 00276 { 00277 for (uint16_t i = 0; i < count; i++) 00278 buf[i] = read_byte(); 00279 } 00280 00281 /** 00282 * @brief Selects ROM. 00283 * @note 00284 * @param 00285 * @retval 00286 */ 00287 void OneWire::select(const uint8_t rom[8]) 00288 { 00289 uint8_t i; 00290 00291 write_byte(0x55); // Choose ROM 00292 for (i = 0; i < 8; i++) 00293 write_byte(rom[i]); 00294 } 00295 00296 /** 00297 * @brief Skips ROM select. 00298 * @note 00299 * @param 00300 * @retval 00301 */ 00302 void OneWire::skip() 00303 { 00304 write_byte(0xCC); // Skip ROM 00305 } 00306 00307 /** 00308 * @brief Unpowers the chip. 00309 * @note 00310 * @param 00311 * @retval 00312 */ 00313 void OneWire::depower() 00314 { 00315 INPUT(); 00316 } 00317 00318 #if ONEWIRE_SEARCH 00319 // 00320 00321 /** 00322 * @brief Resets the search state. 00323 * @note We need to use this function to start a search again from the beginning. 00324 * We do not need to do it for the first search, though we could. 00325 * @param 00326 * @retval 00327 */ 00328 void OneWire::reset_search() 00329 { 00330 // reset the search state 00331 LastDiscrepancy = 0; 00332 LastDeviceFlag = false; 00333 LastFamilyDiscrepancy = 0; 00334 for (int i = 7;; i--) { 00335 ROM_NO[i] = 0; 00336 if (i == 0) 00337 break; 00338 } 00339 } 00340 00341 /** 00342 * @brief Sets the search state to find SearchFamily type devices. 00343 * @note 00344 * @param 00345 * @retval 00346 */ 00347 void OneWire::target_search(uint8_t family_code) 00348 { 00349 // set the search state to find SearchFamily type devices 00350 ROM_NO[0] = family_code; 00351 for (uint8_t i = 1; i < 8; i++) 00352 ROM_NO[i] = 0; 00353 LastDiscrepancy = 64; 00354 LastFamilyDiscrepancy = 0; 00355 LastDeviceFlag = false; 00356 } 00357 00358 /** 00359 * @brief Performs a search. 00360 * @note Perform a search. If this function returns a '1' then it has 00361 enumerated the next device and you may retrieve the ROM from the 00362 OneWire::address variable. If there are no devices, no further 00363 devices, or something horrible happens in the middle of the 00364 enumeration then a 0 is returned. If a new device is found then 00365 its address is copied to newAddr. Use OneWire::reset_search() to 00366 start over. 00367 00368 --- Replaced by the one from the Dallas Semiconductor web site --- 00369 ------------------------------------------------------------------------- 00370 Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing 00371 search state. 00372 * @param 00373 * @retval true : device found, ROM number in ROM_NO buffer 00374 * false : device not found, end of search 00375 */ 00376 uint8_t OneWire::search(uint8_t* newAddr) 00377 { 00378 uint8_t id_bit_number; 00379 uint8_t last_zero, rom_byte_number, search_result; 00380 uint8_t id_bit, cmp_id_bit; 00381 00382 unsigned char rom_byte_mask, search_direction; 00383 00384 // initialize for search 00385 id_bit_number = 1; 00386 last_zero = 0; 00387 rom_byte_number = 0; 00388 rom_byte_mask = 1; 00389 search_result = 0; 00390 00391 // if the last call was not the last one 00392 if (!LastDeviceFlag) { 00393 // 1-Wire reset 00394 if (!reset()) { 00395 // reset the search 00396 LastDiscrepancy = 0; 00397 LastDeviceFlag = false; 00398 LastFamilyDiscrepancy = 0; 00399 return false; 00400 } 00401 00402 // issue the search command 00403 write_byte(0xF0); 00404 00405 // loop to do the search 00406 do { 00407 // read a bit and its complement 00408 id_bit = read_bit(); 00409 cmp_id_bit = read_bit(); 00410 00411 // check for no devices on 1-wire 00412 if ((id_bit == 1) && (cmp_id_bit == 1)) 00413 break; 00414 else { 00415 // all devices coupled have 0 or 1 00416 if (id_bit != cmp_id_bit) 00417 search_direction = id_bit; // bit write value for search 00418 else { 00419 // if this discrepancy if before the Last Discrepancy 00420 // on a previous next then pick the same as last time 00421 if (id_bit_number < LastDiscrepancy) 00422 search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); 00423 else 00424 // if equal to last pick 1, if not then pick 0 00425 search_direction = (id_bit_number == LastDiscrepancy); 00426 00427 // if 0 was picked then record its position in LastZero 00428 if (search_direction == 0) { 00429 last_zero = id_bit_number; 00430 00431 // check for Last discrepancy in family 00432 if (last_zero < 9) 00433 LastFamilyDiscrepancy = last_zero; 00434 } 00435 } 00436 00437 // set or clear the bit in the ROM byte rom_byte_number 00438 // with mask rom_byte_mask 00439 if (search_direction == 1) 00440 ROM_NO[rom_byte_number] |= rom_byte_mask; 00441 else 00442 ROM_NO[rom_byte_number] &= ~rom_byte_mask; 00443 00444 // serial number search direction write bit 00445 write_bit(search_direction); 00446 00447 // increment the byte counter id_bit_number 00448 // and shift the mask rom_byte_mask 00449 id_bit_number++; 00450 rom_byte_mask <<= 1; 00451 00452 // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask 00453 if (rom_byte_mask == 0) { 00454 rom_byte_number++; 00455 rom_byte_mask = 1; 00456 } 00457 } 00458 } while (rom_byte_number < 8); 00459 // loop until through all ROM bytes 0-7 00460 // if the search was successful then 00461 if (!(id_bit_number < 65)) { 00462 // search successful so set LastDiscrepancy,LastDeviceFlag,search_result 00463 LastDiscrepancy = last_zero; 00464 00465 // check for last device 00466 if (LastDiscrepancy == 0) 00467 LastDeviceFlag = true; 00468 00469 search_result = true; 00470 } 00471 } 00472 00473 // if no device found then reset counters so next 'search' will be like a first 00474 if (!search_result || !ROM_NO[0]) { 00475 LastDiscrepancy = 0; 00476 LastDeviceFlag = false; 00477 LastFamilyDiscrepancy = 0; 00478 search_result = false; 00479 } 00480 00481 for (int i = 0; i < 8; i++) 00482 newAddr[i] = ROM_NO[i]; 00483 return search_result; 00484 } 00485 #endif 00486 // 00487 #if ONEWIRE_CRC 00488 // 00489 /** 00490 * @brief Computes a Dallas Semiconductor 8 bit CRC directly. 00491 * @note The 1-Wire CRC scheme is described in Maxim Application Note 27: 00492 "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products" 00493 * @param 00494 * @retval 00495 */ 00496 uint8_t OneWire::crc8(const uint8_t* addr, uint8_t len) 00497 { 00498 uint8_t crc = 0; 00499 00500 while (len--) { 00501 uint8_t inbyte = *addr++; 00502 for (uint8_t i = 8; i; i--) { 00503 uint8_t mix = (crc ^ inbyte) & 0x01; 00504 crc >>= 1; 00505 if (mix) 00506 crc ^= 0x8C; 00507 inbyte >>= 1; 00508 } 00509 } 00510 00511 return crc; 00512 } 00513 #endif
Generated on Thu Jul 14 2022 20:23:26 by
1.7.2