mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
331 lines
6.5 KiB
C++
331 lines
6.5 KiB
C++
// FILE: INA266.h
|
|
// AUTHOR: Rob Tillaart
|
|
// VERSION: 0.1.4
|
|
// DATE: 2021-05-18
|
|
// PURPOSE: Arduino library for INA266 power sensor
|
|
// URL: https://github.com/RobTillaart/INA226
|
|
//
|
|
// HISTORY:
|
|
// 0.1.0 2021-05-18 initial version
|
|
// 0.1.1 2021-06-21 improved calibration + added functions
|
|
// 0.1.2 2021-06-22 add check of parameters of several functions + unit tests
|
|
// add getShunt() , getMaxCurrent()
|
|
// 0.1.3 2021-06-22 add getCurrentLSB_uA() + improve examples
|
|
// fix for calibration
|
|
// 0.1.4 2021-08-07 fix getCurrent()
|
|
|
|
#include "INA226.h"
|
|
|
|
#define INA226_CONFIGURATION 0x00
|
|
#define INA226_SHUNT_VOLTAGE 0x01
|
|
#define INA226_BUS_VOLTAGE 0x02
|
|
#define INA226_POWER 0x03
|
|
#define INA226_CURRENT 0x04
|
|
#define INA226_CALIBRATION 0x05
|
|
#define INA226_MASK_ENABLE 0x06
|
|
#define INA226_ALERT_LIMIT 0x07
|
|
#define INA226_MANUFACTURER 0xFE
|
|
#define INA226_DIE_ID 0xFF
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// Constructor
|
|
//
|
|
INA226::INA226(const int8_t address, TwoWire *wire)
|
|
{
|
|
_address = address;
|
|
_wire = wire;
|
|
// as these
|
|
_current_LSB = 0;
|
|
_maxCurrent = 0;
|
|
_shunt = 0;
|
|
}
|
|
|
|
|
|
#if defined (ESP8266) || defined(ESP32)
|
|
bool INA226::begin(const uint8_t sda, const uint8_t scl)
|
|
{
|
|
_wire = &Wire;
|
|
_wire->begin(sda, scl);
|
|
if (! isConnected()) return false;
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
|
|
bool INA226::begin()
|
|
{
|
|
_wire->begin();
|
|
if (! isConnected()) return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool INA226::isConnected()
|
|
{
|
|
_wire->beginTransmission(_address);
|
|
return ( _wire->endTransmission() == 0);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// Core functions
|
|
//
|
|
float INA226::getShuntVoltage()
|
|
{
|
|
uint16_t val = _readRegister(INA226_SHUNT_VOLTAGE);
|
|
if (val & 0x8000)
|
|
{
|
|
val = val & 0x7FFF;
|
|
val = val ^ 0x7FFF;
|
|
val++;
|
|
return val * -2.5e-6;
|
|
}
|
|
return val * 2.5e-6; // fixed 2.50 uV
|
|
}
|
|
|
|
|
|
float INA226::getBusVoltage()
|
|
{
|
|
uint16_t val = _readRegister(INA226_BUS_VOLTAGE);
|
|
return val * 1.25e-3; // fixed 1.25 mV
|
|
}
|
|
|
|
|
|
float INA226::getPower()
|
|
{
|
|
uint16_t val = _readRegister(INA226_POWER);
|
|
return val * 25 * _current_LSB;
|
|
}
|
|
|
|
|
|
float INA226::getCurrent()
|
|
{
|
|
uint16_t val = _readRegister(INA226_CURRENT);
|
|
if (val & 0x8000)
|
|
{
|
|
val = val & 0x7FFF;
|
|
val = val ^ 0x7FFF;
|
|
val++;
|
|
return val * -_current_LSB;
|
|
}
|
|
return val * _current_LSB;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// Configuration
|
|
//
|
|
void INA226::reset()
|
|
{
|
|
uint16_t mask = _readRegister(INA226_CONFIGURATION);
|
|
mask |= 0x800;
|
|
_writeRegister(INA226_CONFIGURATION, mask);
|
|
// reset calibration?
|
|
}
|
|
|
|
|
|
bool INA226::setAverage(uint8_t avg)
|
|
{
|
|
if (avg > 7) return false;
|
|
uint16_t mask = _readRegister(INA226_CONFIGURATION);
|
|
mask &= 0xF1FF;
|
|
mask |= (avg << 9);
|
|
_writeRegister(INA226_CONFIGURATION, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
uint8_t INA226::getAverage()
|
|
{
|
|
uint16_t mask = _readRegister(INA226_CONFIGURATION);
|
|
mask >>= 9;
|
|
mask &= 7;
|
|
return mask;
|
|
}
|
|
|
|
|
|
bool INA226::setBusVoltageConversionTime(uint8_t bvct)
|
|
{
|
|
if (bvct > 7) return false;
|
|
uint16_t mask = _readRegister(INA226_CONFIGURATION);
|
|
mask &= 0xFE3F;
|
|
mask |= (bvct << 6);
|
|
_writeRegister(INA226_CONFIGURATION, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
uint8_t INA226::getBusVoltageConversionTime()
|
|
{
|
|
uint16_t mask = _readRegister(INA226_CONFIGURATION);
|
|
mask >>= 6;
|
|
mask &= 7;
|
|
return mask;
|
|
}
|
|
|
|
|
|
bool INA226::setShuntVoltageConversionTime(uint8_t svct)
|
|
{
|
|
if (svct > 7) return false;
|
|
uint16_t mask = _readRegister(INA226_CONFIGURATION);
|
|
mask &= 0xFFC7;
|
|
mask |= (svct << 3);
|
|
_writeRegister(INA226_CONFIGURATION, mask);
|
|
return true;
|
|
}
|
|
|
|
|
|
uint8_t INA226::getShuntVoltageConversionTime()
|
|
{
|
|
uint16_t mask = _readRegister(INA226_CONFIGURATION);
|
|
mask >>= 3;
|
|
mask &= 7;
|
|
return mask;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// Calibration
|
|
//
|
|
bool INA226::setMaxCurrentShunt(float maxCurrent, float shunt, bool normalize)
|
|
{
|
|
if (maxCurrent > 20 || maxCurrent < 0.001) return false;
|
|
if (shunt < 0.001) return false;
|
|
|
|
_current_LSB = maxCurrent * 3.0517578125e-5; // maxCurrent / 32768;
|
|
|
|
// normalize the LSB to a round number
|
|
// LSB will increase
|
|
if (normalize)
|
|
{
|
|
// Serial.print("current_LSB:\t");
|
|
// Serial.println(_current_LSB, 10);
|
|
uint32_t factor = 1;
|
|
while (_current_LSB < 1)
|
|
{
|
|
_current_LSB *= 10;
|
|
factor *= 10;
|
|
}
|
|
_current_LSB = 10.0 / factor;
|
|
// Serial.print("current_LSB:\t");
|
|
// Serial.println(_current_LSB, 10);
|
|
}
|
|
|
|
// auto-scale
|
|
uint32_t calib = round(0.00512 / (_current_LSB * shunt));
|
|
while (calib > 65535)
|
|
{
|
|
_current_LSB *= 10;
|
|
calib /= 10;
|
|
}
|
|
_writeRegister(INA226_CALIBRATION, calib);
|
|
|
|
// Serial.print("Calibration:\t");
|
|
// Serial.println(calib);
|
|
|
|
_maxCurrent = _current_LSB * 32768.0;
|
|
_shunt = shunt;
|
|
return true;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// operating mode
|
|
//
|
|
bool INA226::setMode(uint8_t mode)
|
|
{
|
|
if (mode > 7) return false;
|
|
uint16_t config = _readRegister(INA226_CONFIGURATION);
|
|
config &= 0xFFF8;
|
|
config |= mode;
|
|
_writeRegister(INA226_CONFIGURATION, config);
|
|
return true;
|
|
}
|
|
|
|
|
|
uint8_t INA226::getMode()
|
|
{
|
|
return _readRegister(INA226_CONFIGURATION) & 0x0007;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// alert
|
|
//
|
|
void INA226::setAlertRegister(uint16_t mask)
|
|
{
|
|
_writeRegister(INA226_MASK_ENABLE, (mask & 0xFC00));
|
|
}
|
|
|
|
|
|
uint16_t INA226::getAlertFlag()
|
|
{
|
|
return _readRegister(INA226_MASK_ENABLE) & 0x001F;
|
|
}
|
|
|
|
|
|
void INA226::setAlertLimit(uint16_t limit)
|
|
{
|
|
_writeRegister(INA226_ALERT_LIMIT, limit);
|
|
}
|
|
|
|
|
|
uint16_t INA226::getAlertLimit()
|
|
{
|
|
return _readRegister(INA226_ALERT_LIMIT);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// meta information
|
|
//
|
|
uint16_t INA226::getManufacturerID()
|
|
{
|
|
return _readRegister(INA226_MANUFACTURER);
|
|
}
|
|
|
|
uint16_t INA226::getDieID()
|
|
{
|
|
return _readRegister(INA226_DIE_ID);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
//
|
|
// PRIVATE
|
|
//
|
|
uint16_t INA226::_readRegister(uint8_t reg)
|
|
{
|
|
_wire->beginTransmission(_address);
|
|
_wire->write(reg);
|
|
_wire->endTransmission();
|
|
|
|
_wire->requestFrom(_address, (uint8_t)2);
|
|
uint16_t value = _wire->read();
|
|
value <<= 8;
|
|
value |= _wire->read();
|
|
return value;
|
|
}
|
|
|
|
|
|
uint16_t INA226::_writeRegister(uint8_t reg, uint16_t value)
|
|
{
|
|
_wire->beginTransmission(_address);
|
|
_wire->write(reg);
|
|
_wire->write(value >> 8);
|
|
_wire->write(value & 0xFF);
|
|
return _wire->endTransmission();
|
|
}
|
|
|
|
|
|
// -- END OF FILE --
|
|
|