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) : 00128 DigitalInOut(pin) 00129 { 00130 MODE(); // set mode to either OpenDrain for STM or PullUp for others 00131 INIT_WAIT; 00132 #if ONEWIRE_SEARCH 00133 reset_search(); 00134 #endif 00135 } 00136 00137 /** 00138 * @brief Performs the onewire reset function. 00139 * @note We will wait up to 250uS for the bus to come high, 00140 * if it doesn't then it is broken or shorted and we return a 0; 00141 * @param 00142 * @retval 1 if a device asserted a presence pulse, 0 otherwise. 00143 */ 00144 uint8_t OneWire::reset(void) 00145 { 00146 uint8_t present; 00147 00148 OUTPUT(); 00149 WRITE(0); // pull down the 1-wire bus do create reset pulse 00150 WAIT_US(500); // wait at least 480 us 00151 INPUT(); // release the 1-wire bus and go into receive mode 00152 WAIT_US(90); // DS1820 waits about 15 to 60 us and generates a 60 to 240 us presence pulse 00153 present = !READ(); // read the presence pulse 00154 WAIT_US(420); 00155 00156 return present; 00157 } 00158 00159 /** 00160 * @brief Writes a bit. 00161 * @note GPIO registers are used for STM chips to cut time. 00162 * @param 00163 * @retval 00164 */ 00165 void OneWire::write_bit(uint8_t v) 00166 { 00167 OUTPUT(); 00168 if (v & 1) { 00169 WRITE(0); // drive output low 00170 WAIT_US(1); 00171 WRITE(1); // drive output high 00172 WAIT_US(60); 00173 } 00174 else { 00175 WRITE(0); // drive output low 00176 WAIT_US(60); 00177 WRITE(1); // drive output high 00178 WAIT_US(1); 00179 } 00180 } 00181 00182 /** 00183 * @brief Reads a bit. 00184 * @note GPIO registers are used for STM chips to cut time. 00185 * @param 00186 * @retval 00187 */ 00188 uint8_t OneWire::read_bit(void) 00189 { 00190 //const int SAMPLE_POINT = 9; // 10 works for f401re 00191 uint8_t r; 00192 //int t; 00193 00194 OUTPUT(); 00195 WRITE(0); 00196 //timer.start(); 00197 INPUT(); 00198 //t = timer.read_us(); 00199 //if (t < SAMPLE_POINT) 00200 // WAIT_US(SAMPLE_POINT - t); 00201 WAIT_US(1); 00202 r = READ(); 00203 //timer.stop(); 00204 //timer.reset(); 00205 WAIT_US(55); 00206 //printf("t = %d\r\n", t); 00207 return r; 00208 } 00209 00210 /** 00211 * @brief Writes a byte. 00212 * @note The writing code uses the active drivers to raise the 00213 pin high, if you need power after the write (e.g. DS18S20 in 00214 parasite power mode) then set 'power' to 1, otherwise the pin will 00215 go tri-state at the end of the write to avoid heating in a short or 00216 other mishap. 00217 * @param 00218 * @retval 00219 */ 00220 void OneWire::write_byte(uint8_t v, uint8_t power /* = 0 */ ) 00221 { 00222 uint8_t bitMask; 00223 00224 for (bitMask = 0x01; bitMask; bitMask <<= 1) 00225 write_bit((bitMask & v) ? 1 : 0); 00226 if (!power) 00227 INPUT(); 00228 } 00229 00230 /** 00231 * @brief Writes bytes. 00232 * @note 00233 * @param 00234 * @retval 00235 */ 00236 void OneWire::write_bytes(const uint8_t* buf, uint16_t count, bool power /* = 0 */ ) 00237 { 00238 for (uint16_t i = 0; i < count; i++) 00239 write_byte(buf[i]); 00240 if (!power) 00241 INPUT(); 00242 } 00243 00244 /** 00245 * @brief Reads a byte. 00246 * @note 00247 * @param 00248 * @retval 00249 */ 00250 uint8_t OneWire::read_byte() 00251 { 00252 uint8_t bitMask; 00253 uint8_t r = 0; 00254 00255 for (bitMask = 0x01; bitMask; bitMask <<= 1) { 00256 if (read_bit()) 00257 r |= bitMask; 00258 } 00259 00260 return r; 00261 } 00262 00263 /** 00264 * @brief Reads bytes. 00265 * @note 00266 * @param 00267 * @retval 00268 */ 00269 void OneWire::read_bytes(uint8_t* buf, uint16_t count) 00270 { 00271 for (uint16_t i = 0; i < count; i++) 00272 buf[i] = read_byte(); 00273 } 00274 00275 /** 00276 * @brief Selects ROM. 00277 * @note 00278 * @param 00279 * @retval 00280 */ 00281 void OneWire::select(const uint8_t rom[8]) 00282 { 00283 uint8_t i; 00284 00285 write_byte(0x55); // Choose ROM 00286 for (i = 0; i < 8; i++) 00287 write_byte(rom[i]); 00288 } 00289 00290 /** 00291 * @brief Skips ROM select. 00292 * @note 00293 * @param 00294 * @retval 00295 */ 00296 void OneWire::skip() 00297 { 00298 write_byte(0xCC); // Skip ROM 00299 } 00300 00301 /** 00302 * @brief Unpowers the chip. 00303 * @note 00304 * @param 00305 * @retval 00306 */ 00307 void OneWire::depower() 00308 { 00309 INPUT(); 00310 } 00311 00312 #if ONEWIRE_SEARCH 00313 // 00314 00315 /** 00316 * @brief Resets the search state. 00317 * @note We need to use this function to start a search again from the beginning. 00318 * We do not need to do it for the first search, though we could. 00319 * @param 00320 * @retval 00321 */ 00322 void OneWire::reset_search() 00323 { 00324 // reset the search state 00325 LastDiscrepancy = 0; 00326 LastDeviceFlag = false; 00327 LastFamilyDiscrepancy = 0; 00328 for (int i = 7;; i--) { 00329 ROM_NO[i] = 0; 00330 if (i == 0) 00331 break; 00332 } 00333 } 00334 00335 /** 00336 * @brief Sets the search state to find SearchFamily type devices. 00337 * @note 00338 * @param 00339 * @retval 00340 */ 00341 void OneWire::target_search(uint8_t family_code) 00342 { 00343 // set the search state to find SearchFamily type devices 00344 ROM_NO[0] = family_code; 00345 for (uint8_t i = 1; i < 8; i++) 00346 ROM_NO[i] = 0; 00347 LastDiscrepancy = 64; 00348 LastFamilyDiscrepancy = 0; 00349 LastDeviceFlag = false; 00350 } 00351 00352 /** 00353 * @brief Performs a search. 00354 * @note Perform a search. If this function returns a '1' then it has 00355 enumerated the next device and you may retrieve the ROM from the 00356 OneWire::address variable. If there are no devices, no further 00357 devices, or something horrible happens in the middle of the 00358 enumeration then a 0 is returned. If a new device is found then 00359 its address is copied to newAddr. Use OneWire::reset_search() to 00360 start over. 00361 00362 --- Replaced by the one from the Dallas Semiconductor web site --- 00363 ------------------------------------------------------------------------- 00364 Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing 00365 search state. 00366 * @param 00367 * @retval true : device found, ROM number in ROM_NO buffer 00368 * false : device not found, end of search 00369 */ 00370 uint8_t OneWire::search(uint8_t* newAddr) 00371 { 00372 uint8_t id_bit_number; 00373 uint8_t last_zero, rom_byte_number, search_result; 00374 uint8_t id_bit, cmp_id_bit; 00375 00376 unsigned char rom_byte_mask, search_direction; 00377 00378 // initialize for search 00379 id_bit_number = 1; 00380 last_zero = 0; 00381 rom_byte_number = 0; 00382 rom_byte_mask = 1; 00383 search_result = 0; 00384 00385 // if the last call was not the last one 00386 if (!LastDeviceFlag) { 00387 // 1-Wire reset 00388 if (!reset()) { 00389 // reset the search 00390 LastDiscrepancy = 0; 00391 LastDeviceFlag = false; 00392 LastFamilyDiscrepancy = 0; 00393 return false; 00394 } 00395 00396 // issue the search command 00397 write_byte(0xF0); 00398 00399 // loop to do the search 00400 do { 00401 // read a bit and its complement 00402 id_bit = read_bit(); 00403 cmp_id_bit = read_bit(); 00404 00405 // check for no devices on 1-wire 00406 if ((id_bit == 1) && (cmp_id_bit == 1)) 00407 break; 00408 else { 00409 // all devices coupled have 0 or 1 00410 if (id_bit != cmp_id_bit) 00411 search_direction = id_bit; // bit write value for search 00412 else { 00413 // if this discrepancy if before the Last Discrepancy 00414 // on a previous next then pick the same as last time 00415 if (id_bit_number < LastDiscrepancy) 00416 search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); 00417 else 00418 // if equal to last pick 1, if not then pick 0 00419 search_direction = (id_bit_number == LastDiscrepancy); 00420 00421 // if 0 was picked then record its position in LastZero 00422 if (search_direction == 0) { 00423 last_zero = id_bit_number; 00424 00425 // check for Last discrepancy in family 00426 if (last_zero < 9) 00427 LastFamilyDiscrepancy = last_zero; 00428 } 00429 } 00430 00431 // set or clear the bit in the ROM byte rom_byte_number 00432 // with mask rom_byte_mask 00433 if (search_direction == 1) 00434 ROM_NO[rom_byte_number] |= rom_byte_mask; 00435 else 00436 ROM_NO[rom_byte_number] &= ~rom_byte_mask; 00437 00438 // serial number search direction write bit 00439 write_bit(search_direction); 00440 00441 // increment the byte counter id_bit_number 00442 // and shift the mask rom_byte_mask 00443 id_bit_number++; 00444 rom_byte_mask <<= 1; 00445 00446 // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask 00447 if (rom_byte_mask == 0) { 00448 rom_byte_number++; 00449 rom_byte_mask = 1; 00450 } 00451 } 00452 } while (rom_byte_number < 8); 00453 // loop until through all ROM bytes 0-7 00454 // if the search was successful then 00455 if (!(id_bit_number < 65)) { 00456 // search successful so set LastDiscrepancy,LastDeviceFlag,search_result 00457 LastDiscrepancy = last_zero; 00458 00459 // check for last device 00460 if (LastDiscrepancy == 0) 00461 LastDeviceFlag = true; 00462 00463 search_result = true; 00464 } 00465 } 00466 00467 // if no device found then reset counters so next 'search' will be like a first 00468 if (!search_result || !ROM_NO[0]) { 00469 LastDiscrepancy = 0; 00470 LastDeviceFlag = false; 00471 LastFamilyDiscrepancy = 0; 00472 search_result = false; 00473 } 00474 00475 for (int i = 0; i < 8; i++) 00476 newAddr[i] = ROM_NO[i]; 00477 return search_result; 00478 } 00479 #endif 00480 // 00481 #if ONEWIRE_CRC 00482 // 00483 /** 00484 * @brief Computes a Dallas Semiconductor 8 bit CRC directly. 00485 * @note The 1-Wire CRC scheme is described in Maxim Application Note 27: 00486 "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products" 00487 * @param 00488 * @retval 00489 */ 00490 uint8_t OneWire::crc8(const uint8_t* addr, uint8_t len) 00491 { 00492 uint8_t crc = 0; 00493 00494 while (len--) { 00495 uint8_t inbyte = *addr++; 00496 for (uint8_t i = 8; i; i--) { 00497 uint8_t mix = (crc ^ inbyte) & 0x01; 00498 crc >>= 1; 00499 if (mix) 00500 crc ^= 0x8C; 00501 inbyte >>= 1; 00502 } 00503 } 00504 00505 return crc; 00506 } 00507 #endif
Generated on Wed Jul 27 2022 22:37:19 by
1.7.2