/* * DS2438.cpp * * by Joe Bechter * * (C) 2012, bechter.com * * All files, software, schematics and designs are provided as-is with no warranty. * All files, software, schematics and designs are for experimental/hobby use. * Under no circumstances should any part be used for critical systems where safety, * life or property depends upon it. You are responsible for all use. * You are free to use, modify, derive or otherwise extend for your own non-commercial purposes provided * 1. No part of this software or design may be used to cause injury or death to humans or animals. * 2. Use is non-commercial. * 3. Credit is given to the author (i.e. portions © bechter.com), and provide a link to the original source. * */ #include "DS2438.h" // DSROM FIELDS #define DSROM_FAMILY 0 #define DSROM_CRC 7 #define DS2438MODEL 0x26 DS2438::DS2438(OneWire *ow, float currentShunt = 1.0f) { _ow = ow; _currentShunt = currentShunt; }; void DS2438::begin(){ DeviceAddress searchDeviceAddress; _ow->reset_search(); memset(searchDeviceAddress,0, 8); _temperature = 0; _voltageA = 0.0; _voltageB = 0.0; _error = true; _mode = (DS2438_MODE_CHA | DS2438_MODE_CHB | DS2438_MODE_TEMPERATURE); deviceFound = false; // Reset the number of devices when we enumerate wire devices while (_ow->search(searchDeviceAddress)) { if (validAddress(searchDeviceAddress)) { if (validFamily(searchDeviceAddress)) { memcpy(_address,searchDeviceAddress,8); DEFAULT_PAGE0(defaultConfig); writePage(0, defaultConfig); deviceFound = true; } } } } bool DS2438::isFound(){ return deviceFound; } bool DS2438::validAddress(const uint8_t* deviceAddress) { return (_ow->crc8(deviceAddress, 7) == deviceAddress[DSROM_CRC]); } bool DS2438::validFamily(const uint8_t* deviceAddress) { switch (deviceAddress[DSROM_FAMILY]) { case DS2438MODEL: return true; default: return false; } } void DS2438::update() { uint8_t data[9]; _error = true; if(!isFound()){ return; } if (_mode & DS2438_MODE_CHA || _mode == DS2438_MODE_TEMPERATURE) { boolean doTemperature = _mode & DS2438_MODE_TEMPERATURE; if (!startConversion(DS2438_CHA, doTemperature)) { Serial.println("Error starting temp conversion ds2438 channel a"); return; } if (!readPage(0, data)){ Serial.println("Error reading zero page ds2438 channel a"); return; } Serial.print(data[0],16); Serial.print(" "); Serial.print(data[1],16); Serial.print(" "); Serial.print(data[2],16); Serial.print(" "); Serial.print(data[3],16); Serial.print(" "); Serial.print(data[4],16); Serial.print(" "); Serial.print(data[5],16); Serial.print(" "); Serial.print(data[6],16); Serial.print(" "); Serial.println(data[7],16); if (doTemperature) { _temperature = (double)(((((int16_t)data[2]) << 8) | (data[1] & 0x0ff)) >> 3) * 0.03125; } if (_mode & DS2438_MODE_CHA) { _voltageA = (((data[4] << 8) & 0x00300) | (data[3] & 0x0ff)) / 100.0; } } if (_mode & DS2438_MODE_CHB) { boolean doTemperature = _mode & DS2438_MODE_TEMPERATURE && !(_mode & DS2438_MODE_CHA); if (!startConversion(DS2438_CHB, doTemperature)) { Serial.println("Error starting temp conversion channel b ds2438"); return; } if (!readPage(0, data)){ Serial.println("Error reading zero page ds2438 channel b"); return; } if (doTemperature) { int16_t upperByte = ((int16_t)data[2]) << 8; int16_t lowerByte = data[1] >> 3; int16_t fullByte = (upperByte | lowerByte); _temperature = ((double)fullByte) * 0.03125; } _voltageB = (((data[4] << 8) & 0x00300) | (data[3] & 0x0ff)) / 100.0; } int16_t upperByte = ((int16_t)data[6]) << 8; int16_t lowerByte = data[5]; int16_t fullByte = (int16_t)(upperByte | lowerByte); float fullByteb = fullByte; _current = (fullByteb) / ((4096.0f * _currentShunt)); _error = false; Serial.print(data[0],16); Serial.print(" "); Serial.print(data[1],16); Serial.print(" "); Serial.print(data[2],16); Serial.print(" "); Serial.print(data[3],16); Serial.print(" "); Serial.print(data[4],16); Serial.print(" "); Serial.print(data[5],16); Serial.print(" "); Serial.print(data[6],16); Serial.print(" "); Serial.println(data[7],16); Serial.println("-"); uint16_t ICA = 0; if (readPage(1, data)){ PageOne_t *pOne = (PageOne_t *) data; Serial.println(pOne->ICA); float Ah = pOne->ICA / (2048.0f * _currentShunt); Serial.print("Ah="); Serial.println(Ah); ICA = pOne->ICA; } if (readPage(7, data)){ PageSeven_t *pSeven = (PageSeven_t *) data; int16_t CCA = pSeven->CCA0 | ((int16_t) pSeven->CCA1) << 8; int16_t DCA = pSeven->DCA0 | ((int16_t) pSeven->DCA1) << 8; Serial.println("ICA, DCA, CCA"); Serial.print(ICA); Serial.print(", "); Serial.print(DCA); Serial.print(", "); Serial.println(CCA); } } double DS2438::getTemperature() { return _temperature; } float DS2438::getVoltage(int channel) { if (channel == DS2438_CHA) { return _voltageA; } else if (channel == DS2438_CHB) { return _voltageB; } else { return 0.0; } } float DS2438::getCurrent() { return _current; } boolean DS2438::isError() { return _error; } boolean DS2438::startConversion(int channel, boolean doTemperature) { if(!isFound()){ return false; } if (!selectChannel(channel)){ return false; } _ow->reset(); _ow->select(_address); if (doTemperature) { _ow->write(DS2438_TEMPERATURE_CONVERSION_COMMAND, 0); delay(DS2438_TEMPERATURE_DELAY); _ow->reset(); _ow->select(_address); } _ow->write(DS2438_VOLTAGE_CONVERSION_COMMAND, 0); delay(DS2438_VOLTAGE_CONVERSION_DELAY); return true; } boolean DS2438::selectChannel(int channel) { if(!isFound()){ return false; } uint8_t data[9]; if (readPage(0, data)) { if (channel == DS2438_CHB){ data[0] = data[0] | 0x08; } else { data[0] = data[0] & 0xf7; } writePage(0, data); return true; } Serial.println("Could not read page zero data"); return false; } void DS2438::writePage(int page, uint8_t *data) { _ow->reset(); _ow->select(_address); _ow->write(DS2438_WRITE_SCRATCHPAD_COMMAND, 0); if ((page >= PAGE_MIN) && (page <= PAGE_MAX)) { _ow->write(page, 0); } else { return; } for (int i = 0; i < 8; i++){ _ow->write(data[i], 0); } _ow->reset(); _ow->select(_address); _ow->write(DS2438_COPY_SCRATCHPAD_COMMAND, 0); _ow->write(page, 0); } boolean DS2438::readPage(int page, uint8_t *data) { //TODO if all data is 0 0 is a valid crc, but most likly not as intended _ow->reset(); _ow->select(_address); _ow->write(DS2438_RECALL_MEMORY_COMMAND, 0); if ((page >= PAGE_MIN) && (page <= PAGE_MAX)) { _ow->write(page, 0); } else { return false; } _ow->reset(); _ow->select(_address); _ow->write(DS2438_READ_SCRATCHPAD_COMMAND, 0); _ow->write(page, 0); for (int i = 0; i < 9; i++){ data[i] = _ow->read(); } return _ow->crc8(data, 8) == data[8]; }