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

1wire.cpp

Committer:
alpov
Date:
2014-04-28
Revision:
0:445fe6e6bd68

File content as of revision 0:445fe6e6bd68:

#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;
}