zzz
OneWire.h@6:d6e084297fb9, 2019-01-20 (annotated)
- Committer:
- hudakz
- Date:
- Sun Jan 20 10:10:20 2019 +0000
- Revision:
- 6:d6e084297fb9
- Parent:
- 0:acf75feb0947
- Child:
- 9:4af0015b0f47
Reading data bits improved.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:acf75feb0947 | 1 | #ifndef OneWire_h |
hudakz | 0:acf75feb0947 | 2 | #define OneWire_h |
hudakz | 0:acf75feb0947 | 3 | |
hudakz | 0:acf75feb0947 | 4 | #include <inttypes.h> |
hudakz | 0:acf75feb0947 | 5 | #include <mbed.h> |
hudakz | 0:acf75feb0947 | 6 | |
hudakz | 0:acf75feb0947 | 7 | // You can exclude certain features from OneWire. In theory, this |
hudakz | 0:acf75feb0947 | 8 | // might save some space. In practice, the compiler automatically |
hudakz | 0:acf75feb0947 | 9 | // removes unused code (technically, the linker, using -fdata-sections |
hudakz | 0:acf75feb0947 | 10 | // and -ffunction-sections when compiling, and Wl,--gc-sections |
hudakz | 0:acf75feb0947 | 11 | // when linking), so most of these will not result in any code size |
hudakz | 0:acf75feb0947 | 12 | // reduction. Well, unless you try to use the missing features |
hudakz | 0:acf75feb0947 | 13 | // and redesign your program to not need them! ONEWIRE_CRC8_TABLE |
hudakz | 0:acf75feb0947 | 14 | // is the exception, because it selects a fast but large algorithm |
hudakz | 0:acf75feb0947 | 15 | // or a small but slow algorithm. |
hudakz | 0:acf75feb0947 | 16 | |
hudakz | 0:acf75feb0947 | 17 | // you can exclude onewire_search by defining that to 0 |
hudakz | 0:acf75feb0947 | 18 | #ifndef ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 19 | #define ONEWIRE_SEARCH 1 |
hudakz | 0:acf75feb0947 | 20 | #endif |
hudakz | 0:acf75feb0947 | 21 | |
hudakz | 0:acf75feb0947 | 22 | // You can exclude CRC checks altogether by defining this to 0 |
hudakz | 0:acf75feb0947 | 23 | #ifndef ONEWIRE_CRC |
hudakz | 0:acf75feb0947 | 24 | #define ONEWIRE_CRC 1 |
hudakz | 0:acf75feb0947 | 25 | #endif |
hudakz | 0:acf75feb0947 | 26 | |
hudakz | 0:acf75feb0947 | 27 | class OneWire |
hudakz | 0:acf75feb0947 | 28 | { |
hudakz | 0:acf75feb0947 | 29 | private: |
hudakz | 0:acf75feb0947 | 30 | DigitalInOut wire; |
hudakz | 6:d6e084297fb9 | 31 | Timer timer; |
hudakz | 0:acf75feb0947 | 32 | |
hudakz | 0:acf75feb0947 | 33 | #if ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 34 | // global search state |
hudakz | 0:acf75feb0947 | 35 | unsigned char ROM_NO[8]; |
hudakz | 0:acf75feb0947 | 36 | uint8_t LastDiscrepancy; |
hudakz | 0:acf75feb0947 | 37 | uint8_t LastFamilyDiscrepancy; |
hudakz | 0:acf75feb0947 | 38 | uint8_t LastDeviceFlag; |
hudakz | 0:acf75feb0947 | 39 | #endif |
hudakz | 0:acf75feb0947 | 40 | |
hudakz | 0:acf75feb0947 | 41 | public: |
hudakz | 0:acf75feb0947 | 42 | OneWire(PinName pin); |
hudakz | 0:acf75feb0947 | 43 | |
hudakz | 0:acf75feb0947 | 44 | // Perform a 1-Wire reset cycle. Returns 1 if a device responds |
hudakz | 0:acf75feb0947 | 45 | // with a presence pulse. Returns 0 if there is no device or the |
hudakz | 0:acf75feb0947 | 46 | // bus is shorted or otherwise held low for more than 250uS |
hudakz | 0:acf75feb0947 | 47 | uint8_t reset(void); |
hudakz | 0:acf75feb0947 | 48 | |
hudakz | 0:acf75feb0947 | 49 | // Issue a 1-Wire rom select command, you do the reset first. |
hudakz | 0:acf75feb0947 | 50 | void select(const uint8_t rom[8]); |
hudakz | 0:acf75feb0947 | 51 | |
hudakz | 0:acf75feb0947 | 52 | // Issue a 1-Wire rom skip command, to address all on bus. |
hudakz | 0:acf75feb0947 | 53 | void skip(void); |
hudakz | 0:acf75feb0947 | 54 | |
hudakz | 0:acf75feb0947 | 55 | // Write a byte. If 'power' is one then the wire is held high at |
hudakz | 0:acf75feb0947 | 56 | // the end for parasitically powered devices. You are responsible |
hudakz | 0:acf75feb0947 | 57 | // for eventually depowering it by calling depower() or doing |
hudakz | 0:acf75feb0947 | 58 | // another read or write. |
hudakz | 0:acf75feb0947 | 59 | void write(uint8_t v, uint8_t power = 0); |
hudakz | 0:acf75feb0947 | 60 | |
hudakz | 0:acf75feb0947 | 61 | void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0); |
hudakz | 0:acf75feb0947 | 62 | |
hudakz | 0:acf75feb0947 | 63 | // Read a byte. |
hudakz | 0:acf75feb0947 | 64 | uint8_t read(void); |
hudakz | 0:acf75feb0947 | 65 | |
hudakz | 0:acf75feb0947 | 66 | void read_bytes(uint8_t *buf, uint16_t count); |
hudakz | 0:acf75feb0947 | 67 | |
hudakz | 0:acf75feb0947 | 68 | // Write a bit. The bus is always left powered at the end, see |
hudakz | 0:acf75feb0947 | 69 | // note in write() about that. |
hudakz | 0:acf75feb0947 | 70 | void write_bit(uint8_t v); |
hudakz | 0:acf75feb0947 | 71 | |
hudakz | 0:acf75feb0947 | 72 | // Read a bit. |
hudakz | 0:acf75feb0947 | 73 | uint8_t read_bit(void); |
hudakz | 0:acf75feb0947 | 74 | |
hudakz | 0:acf75feb0947 | 75 | // Stop forcing power onto the bus. You only need to do this if |
hudakz | 0:acf75feb0947 | 76 | // you used the 'power' flag to write() or used a write_bit() call |
hudakz | 0:acf75feb0947 | 77 | // and aren't about to do another read or write. You would rather |
hudakz | 0:acf75feb0947 | 78 | // not leave this powered if you don't have to, just in case |
hudakz | 0:acf75feb0947 | 79 | // someone shorts your bus. |
hudakz | 0:acf75feb0947 | 80 | void depower(void); |
hudakz | 0:acf75feb0947 | 81 | |
hudakz | 0:acf75feb0947 | 82 | #if ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 83 | // Clear the search state so that if will start from the beginning again. |
hudakz | 0:acf75feb0947 | 84 | void reset_search(); |
hudakz | 0:acf75feb0947 | 85 | |
hudakz | 0:acf75feb0947 | 86 | // Setup the search to find the device type 'family_code' on the next call |
hudakz | 0:acf75feb0947 | 87 | // to search(*newAddr) if it is present. |
hudakz | 0:acf75feb0947 | 88 | void target_search(uint8_t family_code); |
hudakz | 0:acf75feb0947 | 89 | |
hudakz | 0:acf75feb0947 | 90 | // Look for the next device. Returns 1 if a new address has been |
hudakz | 0:acf75feb0947 | 91 | // returned. A zero might mean that the bus is shorted, there are |
hudakz | 0:acf75feb0947 | 92 | // no devices, or you have already retrieved all of them. It |
hudakz | 0:acf75feb0947 | 93 | // might be a good idea to check the CRC to make sure you didn't |
hudakz | 0:acf75feb0947 | 94 | // get garbage. The order is deterministic. You will always get |
hudakz | 0:acf75feb0947 | 95 | // the same devices in the same order. |
hudakz | 0:acf75feb0947 | 96 | uint8_t search(uint8_t *newAddr); |
hudakz | 0:acf75feb0947 | 97 | #endif |
hudakz | 0:acf75feb0947 | 98 | |
hudakz | 0:acf75feb0947 | 99 | #if ONEWIRE_CRC |
hudakz | 0:acf75feb0947 | 100 | // Compute a Dallas Semiconductor 8 bit CRC, these are used in the |
hudakz | 0:acf75feb0947 | 101 | // ROM and scratchpad registers. |
hudakz | 0:acf75feb0947 | 102 | static uint8_t crc8(const uint8_t *addr, uint8_t len); |
hudakz | 0:acf75feb0947 | 103 | |
hudakz | 0:acf75feb0947 | 104 | #if ONEWIRE_CRC16 |
hudakz | 0:acf75feb0947 | 105 | // Compute the 1-Wire CRC16 and compare it against the received CRC. |
hudakz | 0:acf75feb0947 | 106 | // Example usage (reading a DS2408): |
hudakz | 0:acf75feb0947 | 107 | // // Put everything in a buffer so we can compute the CRC easily. |
hudakz | 0:acf75feb0947 | 108 | // uint8_t buf[13]; |
hudakz | 0:acf75feb0947 | 109 | // buf[0] = 0xF0; // Read PIO Registers |
hudakz | 0:acf75feb0947 | 110 | // buf[1] = 0x88; // LSB address |
hudakz | 0:acf75feb0947 | 111 | // buf[2] = 0x00; // MSB address |
hudakz | 0:acf75feb0947 | 112 | // WriteBytes(net, buf, 3); // Write 3 cmd bytes |
hudakz | 0:acf75feb0947 | 113 | // ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16 |
hudakz | 0:acf75feb0947 | 114 | // if (!CheckCRC16(buf, 11, &buf[11])) { |
hudakz | 0:acf75feb0947 | 115 | // // Handle error. |
hudakz | 0:acf75feb0947 | 116 | // } |
hudakz | 0:acf75feb0947 | 117 | // |
hudakz | 0:acf75feb0947 | 118 | // @param input - Array of bytes to checksum. |
hudakz | 0:acf75feb0947 | 119 | // @param len - How many bytes to use. |
hudakz | 0:acf75feb0947 | 120 | // @param inverted_crc - The two CRC16 bytes in the received data. |
hudakz | 0:acf75feb0947 | 121 | // This should just point into the received data, |
hudakz | 0:acf75feb0947 | 122 | // *not* at a 16-bit integer. |
hudakz | 0:acf75feb0947 | 123 | // @param crc - The crc starting value (optional) |
hudakz | 0:acf75feb0947 | 124 | // @return True, iff the CRC matches. |
hudakz | 0:acf75feb0947 | 125 | static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0); |
hudakz | 0:acf75feb0947 | 126 | |
hudakz | 0:acf75feb0947 | 127 | // Compute a Dallas Semiconductor 16 bit CRC. This is required to check |
hudakz | 0:acf75feb0947 | 128 | // the integrity of data received from many 1-Wire devices. Note that the |
hudakz | 0:acf75feb0947 | 129 | // CRC computed here is *not* what you'll get from the 1-Wire network, |
hudakz | 0:acf75feb0947 | 130 | // for two reasons: |
hudakz | 0:acf75feb0947 | 131 | // 1) The CRC is transmitted bitwise inverted. |
hudakz | 0:acf75feb0947 | 132 | // 2) Depending on the endian-ness of your processor, the binary |
hudakz | 0:acf75feb0947 | 133 | // representation of the two-byte return value may have a different |
hudakz | 0:acf75feb0947 | 134 | // byte order than the two bytes you get from 1-Wire. |
hudakz | 0:acf75feb0947 | 135 | // @param input - Array of bytes to checksum. |
hudakz | 0:acf75feb0947 | 136 | // @param len - How many bytes to use. |
hudakz | 0:acf75feb0947 | 137 | // @param crc - The crc starting value (optional) |
hudakz | 0:acf75feb0947 | 138 | // @return The CRC16, as defined by Dallas Semiconductor. |
hudakz | 0:acf75feb0947 | 139 | static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0); |
hudakz | 0:acf75feb0947 | 140 | #endif |
hudakz | 0:acf75feb0947 | 141 | #endif |
hudakz | 0:acf75feb0947 | 142 | }; |
hudakz | 0:acf75feb0947 | 143 | |
hudakz | 0:acf75feb0947 | 144 | #endif |