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
--- /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;
+}