GY-63_MS5611/libraries/DS2438/DS2438.cpp
2024-01-27 17:16:37 +01:00

437 lines
8.5 KiB
C++

//
// FILE: DS2438.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// DATE: 2023-07-28
// PURPOSE: Arduino Library for DS2438 battery monitor
// URL: https://github.com/RobTillaart/DS2438
#include "DS2438.h"
// OneWire commands
#define DS2438_READ_TEMPERATURE 0x44
#define DS2438_READ_VOLTAGE 0xB4
#define DS2438_RECALL_SCRATCH 0xB8
#define DS2438_READ_SCRATCH 0xBE
#define DS2438_WRITE_SCRATCH 0x4E
#define DS2438_COPY_SCRATCH 0x48
#define DS2438_CONVERSION_DELAY 10
// bits configuration register
#define DS2438_CFG_IAD 0
#define DS2438_CFG_CA 1
#define DS2438_CFG_EE 2
#define DS2438_CFG_AD 3
DS2438::DS2438(OneWire * ow)
{
_oneWire = ow;
// no sensor found yet
_addressFound = false;
// no data read yet
_temperature = DS2438_INVALID;
_vad = DS2438_INVALID;
_vdd = DS2438_INVALID;
_current = DS2438_INVALID;
_inverseR = DS2438_INVALID;
}
bool DS2438::begin(uint8_t retries)
{
return isConnected(retries);
}
bool DS2438::isConnected(uint8_t retries)
{
if (_oneWire == NULL) return false;
_addressFound = false;
for (uint8_t rtr = retries; (rtr > 0) && (_addressFound == false); rtr--)
{
_oneWire->reset();
_oneWire->reset_search();
_address[0] = 0x00;
_oneWire->search(_address);
_addressFound = (_address[0] != 0x00) && (_oneWire->crc8(_address, 7) == _address[7]);
}
return _addressFound;
}
///////////////////////////////////////////////////////////
//
// TEMPERATURE
//
float DS2438::readTemperature()
{
// requestTemperature()
_oneWire->reset();
_oneWire->select(_address);
_oneWire->write(DS2438_READ_TEMPERATURE, 0);
// async version should return here
delay(DS2438_CONVERSION_DELAY);
readScratchPad(0);
// sign MSB LSB step >> 3
_temperature = (int(_scratchPad[2]) * 256 + _scratchPad[1]) * 0.03125 * 0.125;
return _temperature;
}
float DS2438::getTemperature()
{
return _temperature;
}
///////////////////////////////////////////////////////////
//
// VOLTAGE
//
float DS2438::readVDD()
{
setConfigBit(3);
// requestVoltage
_oneWire->reset();
_oneWire->select(_address);
_oneWire->write(DS2438_READ_VOLTAGE, 0);
delay(DS2438_CONVERSION_DELAY);
readScratchPad(0);
// 10 mV resolution
_vdd = ((_scratchPad[4] & 0x03) * 256 + _scratchPad[3]) * 0.01;
return _vdd;
}
float DS2438::getVDD()
{
return _vdd;
}
float DS2438::readVAD()
{
clearConfigBit(3);
// requestVoltage
_oneWire->reset();
_oneWire->select(_address);
_oneWire->write(DS2438_READ_VOLTAGE, 0);
delay(DS2438_CONVERSION_DELAY);
readScratchPad(0);
// 10 mV resolution
_vad = ((_scratchPad[4] & 0x03) * 256 + _scratchPad[3]) * 0.01;
return _vad;
}
float DS2438::getVAD()
{
return _vad;
}
///////////////////////////////////////////////////////////
//
// CURRENT
//
void DS2438::setResistor(float resistor)
{
_inverseR = 1.0 / (4096.0 * resistor);
}
void DS2438::enableCurrentMeasurement()
{
// The DS2438 will only perform current A/D measurements
// if the IAD bit is set to “1” in the status/Configuration Register.
// The current A/D measures at a rate of 36.41 times per second, or once every 27.46 ms.
readScratchPad(0);
if ((_scratchPad[0] & 0x01) == 0x01) return; // already 1
_scratchPad[0] |= 0x01;
writeScratchPad(0);
}
void DS2438::disableCurrentMeasurement()
{
readScratchPad(0);
if ((_scratchPad[0] & 0x01) == 0x00) return; // already 0
_scratchPad[0] &= ~0x01;
writeScratchPad(0);
}
float DS2438::readCurrent()
{
readScratchPad(0);
int voltageSense = (int(_scratchPad[6]) * 256 + _scratchPad[5]);
_current = voltageSense * _inverseR; // I = V / (4096 * R)
return _current;
}
float DS2438::getCurrent()
{
return _current;
}
void DS2438::writeCurrentOffset(int value)
{
value *= 8;
readScratchPad(1);
_scratchPad[6] = value / 8;
_scratchPad[5] = value % 8;
writeScratchPad(1);
}
int DS2438::readCurrentOffset()
{
readScratchPad(1);
int offset = (int(_scratchPad[6]) * 256 + _scratchPad[5]);
return offset / 8;
}
///////////////////////////////////////////////////////////
//
// ICA + THRESHOLD
//
float DS2438::readRemaining()
{
readScratchPad(1);
// factor 2 from optimization
float remaining = _scratchPad[4] * _inverseR * (2 * 0.4882); // mVhr
return remaining;
}
void DS2438::writeThreshold(uint8_t value)
{
clearConfigBit(0);
readScratchPad(0);
_scratchPad[7] = value & 0xC0; // zero lower 6 bits.
writeScratchPad(0);
setConfigBit(0);
}
uint8_t DS2438::readThreshold()
{
readScratchPad(0);
return _scratchPad[7];
}
///////////////////////////////////////////////////////////
//
// TIME
//
void DS2438::writeElapsedTimeMeter(uint32_t seconds)
{
readScratchPad(1);
_scratchPad[0] = seconds & 0xFF;
seconds >>= 8;
_scratchPad[1] = seconds & 0xFF;
seconds >>= 8;
_scratchPad[2] = seconds & 0xFF;
seconds >>= 8;
_scratchPad[3] = seconds & 0xFF;
writeScratchPad(1);
}
uint32_t DS2438::readElapsedTimeMeter()
{
readScratchPad(1);
uint32_t seconds = _scratchPad[3];
seconds <<= 8;
seconds += _scratchPad[2];
seconds <<= 8;
seconds += _scratchPad[1];
seconds <<= 8;
seconds += _scratchPad[0];
return seconds;
}
uint32_t DS2438::readDisconnectTime()
{
readScratchPad(2);
uint32_t seconds = _scratchPad[3];
seconds <<= 8;
seconds += _scratchPad[2];
seconds <<= 8;
seconds += _scratchPad[1];
seconds <<= 8;
seconds += _scratchPad[0];
return seconds;
}
uint32_t DS2438::readEndOfChargeTime()
{
readScratchPad(2);
uint32_t seconds = _scratchPad[7];
seconds <<= 8;
seconds += _scratchPad[6];
seconds <<= 8;
seconds += _scratchPad[5];
seconds <<= 8;
seconds += _scratchPad[4];
return seconds;
}
///////////////////////////////////////////////////////////
//
// EEPROM
//
void DS2438::writeEEPROM(uint8_t address, uint8_t value)
{
if (address > 39) return; // 0..39
uint8_t page = address / 8;
uint8_t index = address % 8;
readScratchPad(page);
if (_scratchPad[index] == value) return; // no need to write.
_scratchPad[index] = value;
writeScratchPad(page);
}
uint8_t DS2438::readEEPROM(uint8_t address)
{
if (address > 39) return 0; // 0..39
uint8_t page = address / 8;
uint8_t index = address % 8;
readScratchPad(page);
return _scratchPad[index];
}
///////////////////////////////////////////////////////////
//
// Charging + Discharging Current Accumulator
//
void DS2438::enableCCA()
{
readScratchPad(0);
if ((_scratchPad[0] & 0x02) == 0x02) return; // already 1
_scratchPad[0] |= 0x02;
writeScratchPad(0);
}
void DS2438::disableCCA()
{
readScratchPad(0);
if ((_scratchPad[0] & 0x02) != 0x02) return; // already 0
_scratchPad[0] &= ~0x02;
writeScratchPad(0);
}
float DS2438::readCCA()
{
readScratchPad(7);
uint16_t raw = (_scratchPad[5] * 256 + _scratchPad[4]);
return raw * 15.625;
}
float DS2438::readDCA()
{
readScratchPad(7);
uint16_t raw = (_scratchPad[7] * 256 + _scratchPad[6]);
return raw * 15.625;
}
///////////////////////////////////////////////////////////
//
// CONFIG REGISTER
//
void DS2438::setConfigBit(uint8_t bit)
{
uint8_t mask = (0x01 << bit);
readScratchPad(0);
if ((_scratchPad[0] & mask) == mask) return; // already 1
_scratchPad[0] |= mask;
writeScratchPad(0);
}
void DS2438::clearConfigBit(uint8_t bit)
{
uint8_t mask = (0x01 << bit);
readScratchPad(0);
if ((_scratchPad[0] & mask) == 0x00) return; // already 0
_scratchPad[0] &= ~mask;
writeScratchPad(0);
}
uint8_t DS2438::getConfigRegister()
{
readScratchPad(0);
return _scratchPad[0];
}
///////////////////////////////////////////////////////////
//
// PRIVATE
//
void DS2438::readScratchPad(uint8_t page)
{
if (page > 7) return;
_oneWire->reset();
_oneWire->select(_address);
_oneWire->write(DS2438_RECALL_SCRATCH, 0);
_oneWire->write(page, 0);
_oneWire->reset();
_oneWire->select(_address);
_oneWire->write(DS2438_READ_SCRATCH, 0);
_oneWire->write(page, 0);
for (uint8_t i = 0; i < 8; i++) _scratchPad[i] = _oneWire->read();
// skip crc for now.
}
void DS2438::writeScratchPad(uint8_t page)
{
if (page > 7) return;
_oneWire->reset();
_oneWire->select(_address);
_oneWire->write(DS2438_WRITE_SCRATCH, 0);
_oneWire->write(page, 0);
for (uint8_t i = 0; i < 8; i++) _oneWire->write(_scratchPad[i], 0);
_oneWire->reset();
_oneWire->select(_address);
_oneWire->write(DS2438_COPY_SCRATCH, 0);
_oneWire->write(page, 0);
}
// -- END OF FILE --