diff --git a/Examples/DisplayReadings/DisplayReadings.ino b/Examples/DisplayReadings/DisplayReadings.ino index d6b42c0..c9e8178 100644 --- a/Examples/DisplayReadings/DisplayReadings.ino +++ b/Examples/DisplayReadings/DisplayReadings.ino @@ -11,6 +11,13 @@ ** only to convert and display the data conveniently. The INA226 uses 15 bits of precision, and even though the ** ** current and watt information is returned using 32-bit integers the precision remains the same. ** ** ** +** As of version 1.0.3 the library supports multiple INA226 devices. The Atmel's EEPROM is used to store the 96 ** +** bytes of static information per device using https://www.arduino.cc/en/Reference/EEPROM function calls. ** +** Although up to 16 devices could theoretically be present on the I2C bus the actual limit is determined by the ** +** available EEPROM - ATmega328 UNO has 1024k so can support up to 10 devices but the ATmega168 only has 512 bytes** +** which limits it to supporting at most 5 INA226s. The library has been modified to be backwards compatible and ** +** the device number (from 0 to number of devices found) is passed as the last parameter. ** +** ** ** The datasheet for the INA226 can be found at http://www.ti.com/lit/ds/symlink/ina226.pdf and it contains the ** ** information required in order to hook up the device. Unfortunately it comes as a VSSOP package but it can be ** ** soldered onto a breakout board for breadboard use. The INA226 is quite similar to the INA219 mentioned above, ** @@ -27,9 +34,10 @@ ** ** ** Vers. Date Developer Comments ** ** ====== ========== ============================= ============================================================== ** -** 1.0.2 2017-08-09 https://github.com/SV-Zanshin Cosmetic changes ** -** 1.0.1 2017-01-12 https://github.com/SV-Zanshin Minor code cleanup and added more comments ** -** 1.0.0 2017-01-09 https://github.com/SV-Zanshin Cloned example from test program suite ** +** 1.0.3 2017-09-18 https://github.com/SV-Zanshin https://github.com/SV-Zanshin/INA226/issues/6 Multiple INA226s ** +** 1.0.2 2017-08-09 https://github.com/SV-Zanshin Cosmetic changes ** +** 1.0.1 2017-01-12 https://github.com/SV-Zanshin Minor code cleanup and added more comments ** +** 1.0.0 2017-01-09 https://github.com/SV-Zanshin Cloned example from test program suite ** ** ** *******************************************************************************************************************/ #include // INA226 Library // @@ -41,6 +49,7 @@ const uint32_t SERIAL_SPEED = 115200; // ** Declare global variables and instantiate classes ** *******************************************************************************************************************/ INA226_Class INA226; // INA class instantiation // +uint8_t devicesFound = 0; // Number of INA226s found // /******************************************************************************************************************* ** Declare prototypes for all functions used ** *******************************************************************************************************************/ @@ -56,12 +65,16 @@ void setup() { // #ifdef __AVR_ATmega32U4__ // If we are a 32U4 processor, then // delay(2000); // wait 2 seconds for the serial // #endif // interface to initialize // - Serial.print(F("\n\nDisplay INA226 Readings V1.0.1\n")); // Display program information // - // The begin initialized the calibration for an expected ±1 Amps maximum current and for a 0.1Ohm resistor // - INA226.begin(1,100000); // // + Serial.print(F("\n\nDisplay INA226 Readings V1.0.3\n")); // Display program information // + // The begin initializes the calibration for an expected ±1 Amps maximum current and for a 0.1Ohm resistor, and // + // since no specific device is given as the 3rd parameter all devices are initially set to these values // + devicesFound = INA226.begin(1,100000); // Set expected Amps and resistor // + Serial.print(F("Detected ")); // // + Serial.print(devicesFound); // // + Serial.println(F(" INA226 devices on I2C bus")); // // INA226.setAveraging(4); // Average each reading n-times // - INA226.setBusConversion(); // Maximum conversion time 8.244ms // - INA226.setShuntConversion(); // Maximum conversion time 8.244ms // + INA226.setBusConversion(7); // Maximum conversion time 8.244ms // + INA226.setShuntConversion(7); // Maximum conversion time 8.244ms // INA226.setMode(INA_MODE_CONTINUOUS_BOTH); // Bus/shunt measured continuously // } // of method setup() // // /******************************************************************************************************************* @@ -69,18 +82,25 @@ void setup() { // ** run in a simple infinite loop ** *******************************************************************************************************************/ void loop() { // Main program loop // - Serial.print(F("Bus voltage: ")); // // - Serial.print((float)INA226.getBusMilliVolts()/1000.0,4); // Convert to millivolts // - Serial.println(F("V")); // // - Serial.print(F("Shunt voltage: ")); // // - Serial.print((float)INA226.getShuntMicroVolts()/1000.0,3); // Convert to millivolts // - Serial.println(F("mV")); // // - Serial.print(F("Bus amperage: ")); // // - Serial.print((float)INA226.getBusMicroAmps()/1000.0,3); // Convert to milliamps // - Serial.println(F("mA")); // // - Serial.print(F("Bus wattage: ")); // // - Serial.print((float)INA226.getBusMicroWatts()/1000.0,3); // Convert to milliwatts // - Serial.println(F("mW")); // // - Serial.println(); // // + for (uint8_t i=0;i // I2C Library definition // -INA226_Class::INA226_Class() {} // Unused class constructor // +#include // Include the EEPROM library // +INA226_Class::INA226_Class() {} // Class constructor // INA226_Class::~INA226_Class() {} // Unused class destructor // /******************************************************************************************************************* -** Method begin() does all of the initialization work ** -*******************************************************************************************************************/ -void INA226_Class::begin(const uint8_t maxBusAmps, const uint32_t microOhmR){ // Class initializer // - Wire.begin(); // Start the I2C wire subsystem // - for(_DeviceAddress = 1;_DeviceAddress<127;_DeviceAddress++) { // Loop for each possible address // - Wire.beginTransmission(_DeviceAddress); // See if something is at address // - if (Wire.endTransmission() == 0) { // by checking the return error // - writeWord(INA_CONFIGURATION_REGISTER,INA_RESET_DEVICE); // Force INAs to reset // - delay(I2C_DELAY); // Wait for INA to finish resetting // - if (readWord(INA_CONFIGURATION_REGISTER)==INA_DEFAULT_CONFIGURATION) { // Yes, we've found an INA226! // - _Current_LSB = (uint64_t)maxBusAmps*1000000000/32767; // Get the best possible LSB in nA // - _Calibration = (uint64_t)51200000 / ((uint64_t)_Current_LSB * // Compute calibration register // - (uint64_t)microOhmR / (uint64_t)100000); // using 64 bit numbers throughout // - _Power_LSB = (uint32_t)25*_Current_LSB; // Fixed multiplier for INA219 // - writeWord(INA_CALIBRATION_REGISTER,_Calibration); // Write the calibration value // - break; // Stop searching // - } // of if-then we've found an INA226 // // - } // of if-then we have found a live device // // - } // for-next each possible I2C address // // +** Method begin() sets the INA226 Configuration details, without which meaningful readings cannot be made. If it ** +** is called without the option deviceNumber parameter then the settings are applied to all devices, otherwise ** +** just that specific device is targeted. ** +*******************************************************************************************************************/ +uint8_t INA226_Class::begin(const uint8_t maxBusAmps, // Class initializer // + const uint32_t microOhmR, // // + const uint8_t deviceNumber ) { // // + inaDet ina; // Hold device details in structure // + if (_DeviceCount==0) { // Enumerate devices in first call // + Wire.begin(); // Start the I2C wire subsystem // + for(uint8_t deviceAddress = 1;deviceAddress<127;deviceAddress++) { // Loop for each possible address // + Wire.beginTransmission(deviceAddress); // See if something is at address // + if (Wire.endTransmission() == 0) { // by checking the return error // + writeWord(INA_CONFIGURATION_REGISTER,INA_RESET_DEVICE,deviceAddress); // Force INAs to reset // + delay(I2C_DELAY); // Wait for INA to finish resetting // + if (readWord(INA_CONFIGURATION_REGISTER,deviceAddress) // Yes, we've found an INA226! // + ==INA_DEFAULT_CONFIGURATION) { // // + ina.address = deviceAddress; // Store device address // + ina.operatingMode = B111; // Default to continuous mode // + if ((_DeviceCount*sizeof(ina))>8)); // Write the first byte // Wire.write((uint8_t)data); // and then the second // @@ -85,118 +111,177 @@ void INA226_Class::writeWord(const uint8_t addr, const uint16_t data) { // /******************************************************************************************************************* ** Method getBusMilliVolts retrieves the bus voltage measurement ** *******************************************************************************************************************/ -uint16_t INA226_Class::getBusMilliVolts(const bool waitSwitch) { // // +uint16_t INA226_Class::getBusMilliVolts(const bool waitSwitch, // // + const uint8_t deviceNumber) { // // + inaDet ina; // Hold device details in structure // + EEPROM.get((deviceNumber%_DeviceCount)*sizeof(ina),ina); // Read EEPROM values // if (waitSwitch) waitForConversion(); // wait for conversion to complete // - uint16_t busVoltage = readWord(INA_BUS_VOLTAGE_REGISTER); // Get the raw value and apply // + uint16_t busVoltage = readWord(INA_BUS_VOLTAGE_REGISTER,ina.address); // Get the raw value and apply // busVoltage = (uint32_t)busVoltage*INA_BUS_VOLTAGE_LSB/100; // conversion to get milliVolts // - if (!bitRead(_OperatingMode,2) && bitRead(_OperatingMode,1)) { // If triggered mode and bus active // - int16_t configRegister = readWord(INA_CONFIGURATION_REGISTER); // Get the current register // - writeWord(INA_CONFIGURATION_REGISTER,configRegister); // Write back to trigger next // + if (!bitRead(ina.operatingMode,2) && bitRead(ina.operatingMode,1)) { // If triggered mode and bus active // + int16_t configRegister = readWord(INA_CONFIGURATION_REGISTER,ina.address);// Get the current register // + writeWord(INA_CONFIGURATION_REGISTER,configRegister,ina.address); // Write back to trigger next // } // of if-then triggered mode enabled // // return(busVoltage); // return computed milliVolts // } // of method getBusMilliVolts() // // /******************************************************************************************************************* ** Method getShuntMicroVolts retrieves the shunt voltage measurement ** *******************************************************************************************************************/ -int16_t INA226_Class::getShuntMicroVolts(const bool waitSwitch) { // // +int16_t INA226_Class::getShuntMicroVolts(const bool waitSwitch, // // + const uint8_t deviceNumber) { // // + inaDet ina; // Hold device details in structure // + EEPROM.get((deviceNumber%_DeviceCount)*sizeof(ina),ina); // Read EEPROM values // if (waitSwitch) waitForConversion(); // wait for conversion to complete // - int32_t shuntVoltage = readWord(INA_SHUNT_VOLTAGE_REGISTER); // Get the raw value // + int32_t shuntVoltage = readWord(INA_SHUNT_VOLTAGE_REGISTER,ina.address); // Get the raw value // shuntVoltage = shuntVoltage*INA_SHUNT_VOLTAGE_LSB/10; // Convert to microvolts // - if (!bitRead(_OperatingMode,2) && bitRead(_OperatingMode,0)) { // If triggered and shunt active // - int16_t configRegister = readWord(INA_CONFIGURATION_REGISTER); // Get the current register // - writeWord(INA_CONFIGURATION_REGISTER,configRegister); // Write back to trigger next // + if (!bitRead(ina.operatingMode,2) && bitRead(ina.operatingMode,0)) { // If triggered and shunt active // + int16_t configRegister = readWord(INA_CONFIGURATION_REGISTER,ina.address);// Get the current register // + writeWord(INA_CONFIGURATION_REGISTER,configRegister,ina.address); // Write back to trigger next // } // of if-then triggered mode enabled // // return((int16_t)shuntVoltage); // return computed microvolts // } // of method getShuntMicroVolts() // // /******************************************************************************************************************* ** Method getBusMicroAmps retrieves the computed current in microamps. ** *******************************************************************************************************************/ -int32_t INA226_Class::getBusMicroAmps() { // // - int32_t microAmps = readWord(INA_CURRENT_REGISTER); // Get the raw value // - microAmps = (int64_t)microAmps*_Current_LSB/1000; // Convert to microamps // +int32_t INA226_Class::getBusMicroAmps(const uint8_t deviceNumber) { // // + inaDet ina; // Hold device details in structure // + EEPROM.get((deviceNumber%_DeviceCount)*sizeof(ina),ina); // Read EEPROM values // + int32_t microAmps = readWord(INA_CURRENT_REGISTER,ina.address); // Get the raw value // + microAmps = (int64_t)microAmps*ina.current_LSB/1000; // Convert to microamps // return(microAmps); // return computed microamps // } // of method getBusMicroAmps() // // /******************************************************************************************************************* ** Method getBusMicroWatts retrieves the computed power in milliwatts ** *******************************************************************************************************************/ -int32_t INA226_Class::getBusMicroWatts() { // // - int32_t microWatts = readWord(INA_POWER_REGISTER); // Get the raw value // - microWatts = (int64_t)microWatts*_Power_LSB/1000; // Convert to milliwatts // +int32_t INA226_Class::getBusMicroWatts(const uint8_t deviceNumber) { // // + inaDet ina; // Hold device details in structure // + EEPROM.get((deviceNumber%_DeviceCount)*sizeof(ina),ina); // Read EEPROM values // + int32_t microWatts = readWord(INA_POWER_REGISTER,ina.address); // Get the raw value // + microWatts = (int64_t)microWatts*ina.power_LSB/1000; // Convert to milliwatts // return(microWatts); // return computed milliwatts // } // of method getBusMicroWatts() // // /******************************************************************************************************************* +** Method reset resets the INA226 using the first bit in the configuration register ** +*******************************************************************************************************************/ +void INA226_Class::reset(const uint8_t deviceNumber) { // Reset the INA226 // + inaDet ina; // Hold device details in structure // + int16_t configRegister; // Hold configuration register // + for(uint8_t i=0;i<_DeviceCount;i++) { // Loop for each device found // + if(deviceNumber==UINT8_MAX || deviceNumber%_DeviceCount==i ) { // If this device needs setting // + EEPROM.get(i*sizeof(ina),ina); // Read EEPROM values // + writeWord(INA_CONFIGURATION_REGISTER,0x8000,ina.address); // Set most significant bit // + delay(I2C_DELAY); // Let the INA226 reboot // + } // of if this device needs to be set // // + } // for-next each device loop // // +} // of method reset // // +/******************************************************************************************************************* +** Method setMode allows the various mode combinations to be set. If no parameter is given the system goes back ** +** to the default startup mode. ** +*******************************************************************************************************************/ +void INA226_Class::setMode(const uint8_t mode,const uint8_t deviceNumber ) { // Set the monitoring mode // + inaDet ina; // Hold device details in structure // + int16_t configRegister; // Hold configuration register // + for(uint8_t i=0;i<_DeviceCount;i++) { // Loop for each device found // + if(deviceNumber==UINT8_MAX || deviceNumber%_DeviceCount==i ) { // If this device needs setting // + EEPROM.get(i*sizeof(ina),ina); // Read EEPROM values // + configRegister = readWord(INA_CONFIGURATION_REGISTER,ina.address); // Get the current register // + configRegister &= ~INA_CONFIG_MODE_MASK; // zero out the mode bits // + ina.operatingMode = B00001111 & mode; // Mask off unused bits // + EEPROM.put((deviceNumber%_DeviceCount)*sizeof(ina),ina); // Write new EEPROM values // + configRegister |= ina.operatingMode; // shift in the mode settings // + writeWord(INA_CONFIGURATION_REGISTER,configRegister,ina.address); // Save new value // + } // of if this device needs to be set // // + } // for-next each device loop // // +} // of method setMode() // // +/******************************************************************************************************************* ** Method setAveraging sets the hardware averaging for the different devices ** *******************************************************************************************************************/ -void INA226_Class::setAveraging(const uint16_t averages ) { // Set the number of averages taken // +void INA226_Class::setAveraging(const uint16_t averages, // Set the number of averages taken // + const uint8_t deviceNumber ) { // // uint8_t averageIndex; // Store indexed value for register // - int16_t configRegister = readWord(INA_CONFIGURATION_REGISTER); // Get the current register // - if (averages>=1024) averageIndex = 7; // setting depending upon range // - else if (averages>= 512) averageIndex = 6; // // - else if (averages>= 256) averageIndex = 5; // // - else if (averages>= 128) averageIndex = 4; // // - else if (averages>= 64) averageIndex = 3; // // - else if (averages>= 16) averageIndex = 2; // // - else if (averages>= 4) averageIndex = 1; // // - else averageIndex = 0; // // - configRegister &= ~INA_CONFIG_AVG_MASK; // zero out the averages part // - configRegister |= (uint16_t)averageIndex << 9; // shift in the averages to register// - writeWord(INA_CONFIGURATION_REGISTER,configRegister); // Save new value // + int16_t configRegister; // Configuration register contents // + inaDet ina; // Hold device details in structure // + for(uint8_t i=0;i<_DeviceCount;i++) { // Loop for each device found // + if(deviceNumber==UINT8_MAX || deviceNumber%_DeviceCount==i ) { // If this device needs setting // + configRegister = readWord(INA_CONFIGURATION_REGISTER,ina.address); // Get the current register // + if (averages>=1024) averageIndex = 7; // setting depending upon range // + else if (averages>= 512) averageIndex = 6; // // + else if (averages>= 256) averageIndex = 5; // // + else if (averages>= 128) averageIndex = 4; // // + else if (averages>= 64) averageIndex = 3; // // + else if (averages>= 16) averageIndex = 2; // // + else if (averages>= 4) averageIndex = 1; // // + else averageIndex = 0; // // + configRegister &= ~INA_CONFIG_AVG_MASK; // zero out the averages part // + configRegister |= (uint16_t)averageIndex << 9; // shift in the averages to register// + writeWord(INA_CONFIGURATION_REGISTER,configRegister,ina.address); // Save new value // + } // of if this device needs to be set // // + } // for-next each device loop // // } // of method setAveraging() // // /******************************************************************************************************************* ** Method setBusConversion specifies the conversion rate (see datasheet for 8 distinct values) for the bus ** *******************************************************************************************************************/ -void INA226_Class::setBusConversion(uint8_t convTime ) { // Set timing for Bus conversions // - if (convTime>7) convTime=7; // Use maximum value allowed // - int16_t configRegister = readWord(INA_CONFIGURATION_REGISTER); // Get the current register // - configRegister &= ~INA_CONFIG_BUS_TIME_MASK; // zero out the Bus conversion part // - configRegister |= (uint16_t)convTime << 6; // shift in the averages to register// - writeWord(INA_CONFIGURATION_REGISTER,configRegister); // Save new value // +void INA226_Class::setBusConversion(uint8_t convTime, // Set timing for Bus conversions // + const uint8_t deviceNumber ) { // // + inaDet ina; // Hold device details in structure // + int16_t configRegister; // Store configuration register // + for(uint8_t i=0;i<_DeviceCount;i++) { // Loop for each device found // + if(deviceNumber==UINT8_MAX || deviceNumber%_DeviceCount==i ) { // If this device needs setting // + if (convTime>7) convTime=7; // Use maximum value allowed // + configRegister = readWord(INA_CONFIGURATION_REGISTER,ina.address); // Get the current register // + configRegister &= ~INA_CONFIG_BUS_TIME_MASK; // zero out the Bus conversion part // + configRegister |= (uint16_t)convTime << 6; // shift in the averages to register// + writeWord(INA_CONFIGURATION_REGISTER,configRegister,ina.address); // Save new value // + } // of if this device needs to be set // // + } // for-next each device loop // // } // of method setBusConversion() // // /******************************************************************************************************************* ** Method setShuntConversion specifies the conversion rate (see datasheet for 8 distinct values) for the shunt ** *******************************************************************************************************************/ -void INA226_Class::setShuntConversion(uint8_t convTime ) { // Set timing for Bus conversions // - if (convTime>7) convTime=7; // Use maximum value allowed // - int16_t configRegister = readWord(INA_CONFIGURATION_REGISTER); // Get the current register // - configRegister &= ~INA_CONFIG_SHUNT_TIME_MASK; // zero out the Bus conversion part // - configRegister |= (uint16_t)convTime << 3; // shift in the averages to register// - writeWord(INA_CONFIGURATION_REGISTER,configRegister); // Save new value // +void INA226_Class::setShuntConversion(uint8_t convTime, // Set timing for Bus conversions // + const uint8_t deviceNumber ) { // // + inaDet ina; // Hold device details in structure // + int16_t configRegister; // Store configuration register // + for(uint8_t i=0;i<_DeviceCount;i++) { // Loop for each device found // + if(deviceNumber==UINT8_MAX || deviceNumber%_DeviceCount==i ) { // If this device needs setting // + if (convTime>7) convTime=7; // Use maximum value allowed // + configRegister = readWord(INA_CONFIGURATION_REGISTER,ina.address); // Get the current register // + configRegister &= ~INA_CONFIG_SHUNT_TIME_MASK; // zero out the Bus conversion part // + configRegister |= (uint16_t)convTime << 3; // shift in the averages to register// + writeWord(INA_CONFIGURATION_REGISTER,configRegister,ina.address); // Save new value // + } // of if this device needs to be set // // + } // for-next each device loop // // } // of method setShuntConversion() // // /******************************************************************************************************************* ** Method waitForConversion loops until the current conversion is marked as finished. If the conversion has ** ** completed already then the flag (and interrupt pin, if activated) is also reset. ** *******************************************************************************************************************/ -void INA226_Class::waitForConversion() { // Wait for current conversion // +void INA226_Class::waitForConversion(const uint8_t deviceNumber) { // Wait for current conversion // uint16_t conversionBits = 0; // // - while(conversionBits==0) { // // - conversionBits = readWord(INA_MASK_ENABLE_REGISTER)&(uint16_t)8; // // - } // of while the conversion hasn't finished // // + inaDet ina; // Hold device details in structure // + for(uint8_t i=0;i<_DeviceCount;i++) { // Loop for each device found // + if(deviceNumber==UINT8_MAX || deviceNumber%_DeviceCount==i ) { // If this device needs setting // + conversionBits = 0; // // + while(conversionBits==0) { // // + conversionBits = readWord(INA_MASK_ENABLE_REGISTER,ina.address) // // + &(uint16_t)8; // // + } // of while the conversion hasn't finished // // + } // of if this device needs to be set // // + } // for-next each device loop // // } // of method waitForConversion() // // /******************************************************************************************************************* ** Method setAlertPinOnConversion configure the INA226 to pull the ALERT pin low when a conversion is complete ** *******************************************************************************************************************/ -void INA226_Class::setAlertPinOnConversion(const bool alertState) { // Enable pin change on conversion // - uint16_t alertRegister = readWord(INA_MASK_ENABLE_REGISTER); // Get the current register // - if (!alertState) alertRegister &= ~((uint16_t)1<<10); // zero out the alert bit // - else alertRegister |= (uint16_t)(1<<10); // turn on the alert bit // - writeWord(INA_MASK_ENABLE_REGISTER,alertRegister); // Write register back to device // +void INA226_Class::setAlertPinOnConversion(const bool alertState, // Enable pin change on conversion // + const uint8_t deviceNumber ) { // // + inaDet ina; // Hold device details in structure // + uint16_t alertRegister; // Hold the alert register // + for(uint8_t i=0;i<_DeviceCount;i++) { // Loop for each device found // + if(deviceNumber==UINT8_MAX || deviceNumber%_DeviceCount==i ) { // If this device needs setting // + alertRegister = readWord(INA_MASK_ENABLE_REGISTER,ina.address); // Get the current register // + if (!alertState) alertRegister &= ~((uint16_t)1<<10); // zero out the alert bit // + else alertRegister |= (uint16_t)(1<<10); // turn on the alert bit // + writeWord(INA_MASK_ENABLE_REGISTER,alertRegister,ina.address); // Write register back to device // + } // of if this device needs to be set // // + } // for-next each device loop // // } // of method setAlertPinOnConversion // // -/******************************************************************************************************************* -** Method reset resets the INA226 using the first bit in the configuration register ** -*******************************************************************************************************************/ -void INA226_Class::reset() { // Reset the INA226 // - writeWord(INA_CONFIGURATION_REGISTER,0x8000); // Set most significant bit // - delay(I2C_DELAY); // Let the INA226 reboot // -} // of method reset // // -/******************************************************************************************************************* -** Method setMode allows the various mode combinations to be set. If no parameter is given the system goes back ** -** to the default startup mode. ** -*******************************************************************************************************************/ -void INA226_Class::setMode(uint8_t mode ) { // Set the monitoring mode // - int16_t configRegister = readWord(INA_CONFIGURATION_REGISTER); // Get the current register // - configRegister &= ~INA_CONFIG_MODE_MASK; // zero out the mode bits // - mode = B00001111 & mode; // Mask off unused bits // - configRegister |= mode; // shift in the mode settings // - writeWord(INA_CONFIGURATION_REGISTER,configRegister); // Save new value // - _OperatingMode = mode; // Save the operating mode // -} // of method setMode() // // \ No newline at end of file diff --git a/INA226.h b/INA226.h index 52db66e..34ed0c3 100644 --- a/INA226.h +++ b/INA226.h @@ -33,6 +33,8 @@ ** ** ** Vers. Date Developer Comments ** ** ====== ========== ============================= ============================================================== ** +** 1.0.5b 2017-09-23 https://github.com/SV-Zanshin https://github.com/SV-Zanshin/INA226/issues/6. Multiple INA226 ** +** 1.0.5a 2017-09-18 https://github.com/SV-Zanshin https://github.com/SV-Zanshin/INA226/issues/6. Multiple INA226 ** ** 1.0.4 2017-08-13 https://github.com/SV-Zanshin Enhancement #5, removed while() loop after Wire.requestFrom() ** ** 1.0.3 2017-08-09 https://github.com/SV-Zanshin Fix https://github.com/SV-Zanshin/INA226/issues/4. Overflows ** ** in computations of begin() and getShuntMicroVolts() functions. ** @@ -48,6 +50,16 @@ #ifndef INA226_Class_h // Guard code definition // #define INA226__Class_h // Define the name inside guard code// /***************************************************************************************************************** + ** Declare structures used in the class ** + *****************************************************************************************************************/ + typedef struct { // Structure of values per device // + uint8_t address; // I2C Address of device // + uint16_t calibration; // Calibration register value // + uint32_t current_LSB; // Amperage LSB // + uint32_t power_LSB; // Wattage LSB // + uint8_t operatingMode; // Default continuous mode operation// + } inaDet; // of structure // // + /***************************************************************************************************************** ** Declare constants used in the class ** *****************************************************************************************************************/ const uint8_t I2C_DELAY = 10; // Microsecond delay on write // @@ -81,29 +93,34 @@ public: // Publicly visible methods // INA226_Class(); // Class constructor // ~INA226_Class(); // Class destructor // - void begin(const uint8_t maxBusAmps, const uint32_t micoOhmR); // Class initializer // - uint16_t getBusMilliVolts(const bool waitSwitch=false); // Retrieve Bus voltage in mV // - int16_t getShuntMicroVolts(const bool waitSwitch=false); // Retrieve Shunt voltage in uV // - int32_t getBusMicroAmps(); // Retrieve micro-amps // - int32_t getBusMicroWatts(); // Retrieve micro-watts // - void reset(); // Reset the device // - void setMode(uint8_t mode = 7); // Set the monitoring mode // - void setAveraging(const uint16_t averages = UINT16_MAX); // Set the number of averages taken // - void setBusConversion(uint8_t convTime = UINT8_MAX); // Set timing for Bus conversions // - void setShuntConversion(uint8_t convTime = UINT8_MAX); // Set timing for Shunt conversions // - void setAlertPinOnConversion(const bool alertState); // Enable pin change on conversion // - void waitForConversion(); // wait for conversion to complete // + uint8_t begin(const uint8_t maxBusAmps, // Class initializer // + const uint32_t microOhmR, // // + const uint8_t deviceNumber = UINT8_MAX ); // // + uint16_t getBusMilliVolts(const bool waitSwitch=false, // Retrieve Bus voltage in mV // + const uint8_t deviceNumber=0); // // + int16_t getShuntMicroVolts(const bool waitSwitch=false, // Retrieve Shunt voltage in uV // + const uint8_t deviceNumber=0); // // + int32_t getBusMicroAmps(const uint8_t deviceNumber=0); // Retrieve micro-amps // + int32_t getBusMicroWatts(const uint8_t deviceNumber=0); // Retrieve micro-watts // + void reset(const uint8_t deviceNumber=0); // Reset the device // + void setMode(const uint8_t mode,const uint8_t devNumber=UINT8_MAX); // Set the monitoring mode // + void setAveraging(const uint16_t averages, // Set the number of averages taken // + const uint8_t deviceNumber=UINT8_MAX); // // + void setBusConversion(uint8_t convTime, // Set timing for Bus conversions // + const uint8_t deviceNumber=UINT8_MAX); // // + void setShuntConversion(uint8_t convTime, // Set timing for Shunt conversions // + const uint8_t deviceNumber=UINT8_MAX); // // + void waitForConversion(const uint8_t deviceNumber=UINT8_MAX); // wait for conversion to complete // + void setAlertPinOnConversion(const bool alertState, // Enable pin change on conversion // + const uint8_t deviceNumber=UINT8_MAX); // // private: // Private variables and methods // - uint8_t readByte(const uint8_t addr); // Read a byte from an I2C address // - int16_t readWord(const uint8_t addr); // Read a word from an I2C address // - void writeByte(const uint8_t addr, const uint8_t data); // Write a byte to an I2C address // - void writeWord(const uint8_t addr, const uint16_t data); // Write two bytes to an I2C address// - uint8_t _DeviceAddress = 0; // First I2C address found // + uint8_t readByte(const uint8_t addr, const uint8_t deviceAddress); // Read a byte from an I2C address // + int16_t readWord(const uint8_t addr, const uint8_t deviceAddress); // Read a word from an I2C address // + void writeByte(const uint8_t addr, const uint8_t data, // Write a byte to an I2C address // + const uint8_t deviceAddress); // // + void writeWord(const uint8_t addr, const uint16_t data, // Write two bytes to an I2C address// + const uint8_t deviceAddress); // // uint8_t _TransmissionStatus = 0; // Return code for I2C transmission // - uint16_t _Calibration = 0; // Calibration register value // - uint16_t _Configuration = 0; // Configuration register value // - uint32_t _Current_LSB = 0; // Amperage LSB // - uint32_t _Power_LSB = 0; // Wattage LSB // - uint8_t _OperatingMode = B111; // Default continuous mode operation// - }; // of MicrochipSRAM class definition // // + uint8_t _DeviceCount = 0; // Number of INA226s detected // + }; // of INA226_Class definition // // #endif //----------------------------------// diff --git a/README.md b/README.md index 5bf853b..c2ca661 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ different and require the functions and methods in this library to access. ## Hardware layout The [datasheet](http://www.ti.com/lit/ds/symlink/ina226.pdf) has examples of how to hook up INA226. The package is a small VSSOP and I used a blank breakout board, some solder paste, a frying pan, desoldering braid, a magnifying glass and quite a bit of time to set up the first breadboard example. I've since seen breakout boards available on the web but since only a few external components are necessary apart from connecting the 10 pins of the INA226 I'll remain with self-build. ## Library description -The library will locate the INA226 on the I2C chain and with 4 setup parameters describing the expected voltage, shunt / resistor values the internal configuration registers will be set and the library is ready to begin very accurate measurements. The details of how to setup the library along with all of the publicly available methods can be found on the [INA226 wiki pages](https://github.com/SV-Zanshin/INA226/wiki). -Great lengths have been taken to avoid the use of floating point variables in the library. The results are returned as 32-bit integers to keep the original level of precision without loss of significant digits but to allow the full range of voltages and amperes to be returned. +The library locates all INA226 devices on the I2C chain. Each unit can be individually configured with 4 setup parameters describing the expected voltage, shunt / resistor values which then set the internal configuration registers is ready to begin accurate measurements. The details of how to setup the library along with all of the publicly available methods can be found on the [INA226 wiki pages](https://github.com/SV-Zanshin/INA226/wiki). +Great lengths have been taken to avoid the use of floating point in the library. To keep the original level of precision without loss but to allow the full range of voltages and amperes to be returned the amperage results are returned as 32-bit integers. The INA226 has a dedicated interrupt pin which can be used to trigger pin-change interrupts on the Arduino and the examples contain a program that measures readings using this output pin so that the Arduino can perform other concurrent tasks while still retrieving measurements.