Marco Zecchini / OneWire

Dependents:   DS1820

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers OneWire.cpp Source File

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