Dallas 1-wire driver with DS18B20 temperature sensor support; custom bus driver to work with https://emir.googlecode.com/svn/emir2/trunk/eagle/emir-shield.sch
Dependents: testing_RTC_OneWire EMIRv2
Revision 0:445fe6e6bd68, committed 2014-04-28
- Comitter:
- alpov
- Date:
- Mon Apr 28 06:52:49 2014 +0000
- Commit message:
- initial version, working
Changed in this revision
1wire.cpp | Show annotated file Show diff for this revision Revisions of this file |
1wire.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 445fe6e6bd68 1wire.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1wire.cpp Mon Apr 28 06:52:49 2014 +0000 @@ -0,0 +1,257 @@ +#include "mbed.h" +#include "1wire.h" + +OneWire::OneWire(PinName OwUp, PinName OwDn, PinName OwIn) : _OwUp(OwUp, !0), _OwDn(OwDn, !1), _OwIn(OwIn, PullNone) +{ +} + +int OneWire::Reset(void) +{ + int result; + + DELAY_G(); + __disable_irq(); + _OwDn = !0; + DELAY_H(); + _OwDn = !1; + DELAY_I(); + result = _OwIn; + __enable_irq(); + DELAY_J(); + return result; +} + +void OneWire::WriteBit(int bit) +{ + __disable_irq(); + if (bit) { + _OwDn = !0; + DELAY_A(); + _OwDn = !1; + DELAY_B(); + } else { + _OwDn = !0; + DELAY_C(); + _OwDn = !1; + DELAY_D(); + } + __enable_irq(); +} + +int OneWire::ReadBit(void) +{ + int result; + + __disable_irq(); + _OwDn = !0; + DELAY_A(); + _OwDn = !1; + DELAY_E(); + result = _OwIn; + __enable_irq(); + DELAY_F(); + return result; +} + +void OneWire::WriteByte(uint8_t data) +{ + for (int i = 0; i < 8; i++) { + WriteBit(data & 0x01); + data >>= 1; + } +} + +uint8_t OneWire::ReadByte(void) +{ + uint8_t result = 0; + + for (int i = 0; i < 8; i++) { + result >>= 1; + if (ReadBit()) + result |= 0x80; + } + return result; +} + +void OneWire::SendCmd(uint8_t *ROMID, uint8_t cmd) +{ + Reset(); + if (ROMID == NULL) { + WriteByte(OW_SKIP_ROM_CMD); + } else { + WriteByte(OW_MATCH_ROM_CMD); + for (int i = 0; i < 8; i++) + WriteByte(ROMID[i]); + } + WriteByte(cmd); +} + +int OneWire::First(uint8_t *ROMID) +{ + /* Reset state */ + OW_LastDiscrepancy = 0; + OW_LastDevice = 0; + OW_LastFamilyDiscrepancy = 0; + + /* Go looking */ + return Next(ROMID); +} + +int OneWire::Next(uint8_t *ROMID) +{ + uint8_t bit_test, search_direction, bit_number; + uint8_t last_zero, rom_byte_number, rom_byte_mask; + uint8_t lastcrc8, crcaccum; + int next_result; + + /* Init for search */ + bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + next_result = OW_NOMODULES; + lastcrc8 = 0; + crcaccum = 0; + + /* if the last call was not the last one */ + if (!OW_LastDevice) { + /* reset the 1-wire if there are no parts on 1-wire, return 0 */ + if (Reset()) { + /* reset the search */ + OW_LastDiscrepancy = 0; + OW_LastFamilyDiscrepancy = 0; + return OW_NOPRESENCE; + } + + WriteByte(OW_SEARCH_ROM_CMD); /* issue the search command */ + + /* pause before beginning the search - removed */ + /* loop to do the search */ + do { + /* read a bit and its compliment */ + bit_test = ReadBit() << 1; + bit_test |= ReadBit(); + + /* check for no devices on 1-wire */ + if (bit_test == 3) { + return(OW_BADWIRE); + } else { + /* all devices coupled have 0 or 1 */ + if (bit_test > 0) + search_direction = !(bit_test & 0x01); /* bit write value for search */ + else { + /* if this discrepancy is before the Last Discrepancy + * on a previous OWNext then pick the same as last time */ + if (bit_number < OW_LastDiscrepancy) + search_direction = ((ROMID[rom_byte_number] & rom_byte_mask) > 0); + else + /* if equal to last pick 1, if not then pick 0 */ + search_direction = (bit_number == OW_LastDiscrepancy); + + /* if 0 was picked then record its position in LastZero */ + if (search_direction == 0) { + last_zero = bit_number; + /* check for Last discrepancy in family */ + if (last_zero < 9) + OW_LastFamilyDiscrepancy = last_zero; + } + } + + /* set or clear the bit in the ROM byte rom_byte_number + * with mask rom_byte_mask */ + if (search_direction == 1) + ROMID[rom_byte_number] |= rom_byte_mask; + else + ROMID[rom_byte_number] &= ~rom_byte_mask; + + /* serial number search direction write bit */ + WriteBit(search_direction); + + /* increment the byte counter bit_number + * and shift the mask rom_byte_mask */ + bit_number++; + rom_byte_mask <<= 1; + + /* if the mask is 0 then go to new ROM byte rom_byte_number + * and reset mask */ + if (rom_byte_mask == 0) { + CRC(ROMID[rom_byte_number], &crcaccum); /* accumulate the CRC */ + lastcrc8 = crcaccum; + + rom_byte_number++; + rom_byte_mask = 1; + } + } + } while (rom_byte_number < 8); /* loop until through all ROM bytes 0-7 */ + + /* if the search was successful then */ + if (!(bit_number < 65) || lastcrc8) { + if (lastcrc8) { + next_result = OW_BADCRC; + } else { + /* search successful so set LastDiscrepancy,LastDevice,next_result */ + OW_LastDiscrepancy = last_zero; + OW_LastDevice = (OW_LastDiscrepancy == 0); + next_result = OW_FOUND; + } + } + } + + /* if no device found then reset counters so next 'next' will be like a first */ + if (next_result != OW_FOUND || ROMID[0] == 0) { + OW_LastDiscrepancy = 0; + OW_LastDevice = 0; + OW_LastFamilyDiscrepancy = 0; + } + + if (next_result == OW_FOUND && ROMID[0] == 0x00) + next_result = OW_BADWIRE; + + return next_result; +} + +void OneWire::CRC(uint8_t x, uint8_t *crc) +{ + for (int j = 0; j < 8; j++) { + uint8_t mix = (*crc ^ x) & 0x01; + *crc >>= 1; + if (mix) *crc ^= 0x8C; + x >>= 1; + } +} + +void OneWire::ConvertAll(bool wait) +{ + SendCmd(NULL, OW_CONVERT_T_CMD); + if (wait) { + _OwUp = !1; + wait_ms(CONVERT_T_DELAY); + _OwUp = !0; + } +} + +int OneWire::ReadTemperature(uint8_t *ROMID, int *result) +{ + uint8_t crc = 0, buf[8]; + + SendCmd(ROMID, OW_RD_SCR_CMD); + for (int i = 0; i < 8; i++) { + buf[i] = ReadByte(); + CRC(buf[i], &crc); + } + if (crc != ReadByte()) { + return ERR_BADCRC; + } + + switch (ROMID[0]) { + case 0x10: // ds18s20 + *result = (signed char)((buf[1] & 0x80) | (buf[0] >> 1)) * 100 + 75 - buf[6] * 100 / 16; + break; + case 0x28: // ds18b20 + *result = (signed char)((buf[1] << 4) | (buf[0] >> 4)) * 100 + (buf[0] & 0x0F) * 100 / 16; + break; + default: + return ERR_BADFAMILY; + } + return 0; +}
diff -r 000000000000 -r 445fe6e6bd68 1wire.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/1wire.h Mon Apr 28 06:52:49 2014 +0000 @@ -0,0 +1,94 @@ +#ifndef _1WIRE_H +#define _1WIRE_H + +/* Dallas 1-wire driver with DS18B20 temperature sensor support + * + * Copyright (c) 2014 Ales Povalac, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +class OneWire +{ +public: + OneWire(PinName OwUp, PinName OwDn, PinName OwIn); + + void ConvertAll(bool wait); + int ReadTemperature(uint8_t *ROMID, int *result); + + int First(uint8_t *ROMID); + int Next(uint8_t *ROMID); + + void WriteByte(uint8_t data); + uint8_t ReadByte(void); + void SendCmd(uint8_t *ROMID, uint8_t cmd); + void CRC(uint8_t x, uint8_t *crc); + +private: + DigitalOut _OwUp; + DigitalOut _OwDn; + DigitalIn _OwIn; + + uint8_t OW_LastDevice; + uint8_t OW_LastDiscrepancy; + uint8_t OW_LastFamilyDiscrepancy; + + int Reset(void); + void WriteBit(int bit); + int ReadBit(void); +}; + + +/* INTERNAL CONSTANTS everything below this line */ + +#define ERR_BADCRC 0x8000 +#define ERR_BADFAMILY 0x8001 + +/* Return codes for OWFirst()/OWNext() */ +#define OW_BADWIRE -3 +#define OW_BADCRC -2 +#define OW_NOPRESENCE -1 +#define OW_NOMODULES 0 +#define OW_FOUND 1 + +/* General 1 wire commands */ +#define OW_SEARCH_ROM_CMD 0xF0 +#define OW_READ_ROM_CMD 0x33 +#define OW_MATCH_ROM_CMD 0x55 +#define OW_SKIP_ROM_CMD 0xCC + +/* DS1820 commands */ +#define OW_CONVERT_T_CMD 0x44 +#define OW_RD_SCR_CMD 0xBE +#define OW_WR_SCR_CMD 0x4E + + +/* 1-wire delays */ +#define DELAY_A() wait_us(6) +#define DELAY_B() wait_us(64) +#define DELAY_C() wait_us(60) +#define DELAY_D() wait_us(10) +#define DELAY_E() wait_us(9) +#define DELAY_F() wait_us(55) +#define DELAY_G() +#define DELAY_H() wait_us(480) +#define DELAY_I() wait_us(70) +#define DELAY_J() wait_us(410) + +/* Other */ +#define CONVERT_T_DELAY 750 + +#endif