Arduino power meter based on the ACS 712 and the ADS1115

In this video I show you how to wire up a 128x32 OLED display, an ADS1115 AD converter and an ACS 712 Hall sensor-based current sensor with an Arduino Nano and use it as a power meter. These circuits are very simple to use, but I will show you a few trick that can make them even better. For example, by building a proper voltage divider, you can extend the original 0-5 V voltage range to 20 V like I did. Or, by calibrating the current sensor with another, reliable current meter, you can get accurate current readings. The main motivation of the circuit is my Peltier experiments. I wanted to have a continuous log for my current and voltage values too. So, I will add some extra features to the demonstrated circuit and use it as a logger.



Wiring diagram

The wiring diagram looks a bit messy, I know, but bear with me. The OLED display and the ADS1115 AD-converter uses the same i2C protocol for communication. Therefore, both of them are connected to the same pins: A4 (SDA) and A5 (SCK). Both of them uā€¦

The wiring diagram looks a bit messy, I know, but bear with me. The OLED display and the ADS1115 AD-converter uses the same i2C protocol for communication. Therefore, both of them are connected to the same pins: A4 (SDA) and A5 (SCK). Both of them use the VCC (+5 V) and GND connections. One half of the differential inputs of the ADS1115 is directly connected to the output of the ACS712 current meter (A0: OUT, A1 GND), and the other half is connected to a voltage divider to increase the range of measurement from 0-5 V to 0-20 V. This requires some calculations, so check the video for it. The load is represented by a Peltier unit and the power source for the Peltier is represented by a 9 V battery.



Arduino source code

#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
#define I2C_ADDRESS 0x3C //Address
#define RST_PIN -1 //For OLED with no reset pin
SSD1306AsciiAvrI2c display;

#include <Adafruit_ADS1015.h>

Adafruit_ADS1115 ads;

unsigned long startTime;
unsigned long elapsedTime;

float Voltage;
float Current;
float Power;

void setup(void)
{   
  Serial.begin(9600);  //start serial connection
  Serial.println("Power Tester"); //print a message on the serial terminal
  
  // The ADC input range (or gain) can be changed via the following
  // functions, but be careful never to exceed VDD +0.3V max, or to
  // exceed the upper and lower limits if you adjust the input range!
  // Setting these values incorrectly may destroy your ADC!
  //                                                                ADS1015  ADS1115
  //                                                                -------  -------
  // ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
  // ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
  // ads.setGain(GAIN_TWO);        // 2x gain   +/- 2.048V  1 bit = 1mV      0.0625mV
  // ads.setGain(GAIN_FOUR);       // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
  // ads.setGain(GAIN_EIGHT);      // 8x gain   +/- 0.512V  1 bit = 0.25mV   0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.125mV  0.0078125mV

  //ADS SETUP PART
  //----Set default------
  //ads.setSPS(DR_128SPS); //Sampling speed -some libraries don't support this. check it for yourself.
  
  ads.setGain(GAIN_TWOTHIRDS);
  ads.begin();

  //--------------------------------------------------------------------------------------------
  //OLED part-----------------------------------------------------------------------------------
  #if RST_PIN >= 0
  display.begin(&Adafruit128x32, I2C_ADDRESS, RST_PIN);
  #else // RST_PIN >= 0
  display.begin(&Adafruit128x32, I2C_ADDRESS);
  #endif // RST_PIN >= 0
  //Call oled.setI2cClock(frequency) to change from the default frequency.

  display.setFont(System5x7);
  display.set1X(); //set2x() is too large for the 128*32 oled
  display.clear();
  //--endofOLED----
  
  startTime = millis(); //"start" timer
  
}

void loop(void)
{
  
  MeasurePower(); 
  PrintSerial();
  PrintOLED();  
  delay(500); 
  
}

void MeasurePower()
{  
 elapsedTime = millis() - startTime; //"note down" the elapsed time
 
 //Converts the raw data to mV (* 0.1875), then to V (/1000) 
 // 4.3985 is the division factor that I got for the voltage divider. 
 Voltage = 4.3985 * ads.readADC_Differential_0_1() * 0.1875 / 1000;  //This should give the output in VOLTS

 //You have to calibrate the sensor!
 //My function: I (in Amps) = ([Measured voltage in mV] - 2309.098) / 92.10048
 Current = ((ads.readADC_Differential_2_3()* 0.1875) - 2309.098 ) / 92.10048; //This should give the output in AMPS

 //Watt = U * I
 Power = Voltage * Current;
  
}
void PrintSerial()
{    
  Serial.print(elapsedTime/1000); //print time in seconds
  Serial.print(" "); //space as delimiter
  Serial.print(Voltage,3);
  Serial.print(" ");
  Serial.print(Current,3); 
  Serial.print(" ");
  Serial.println(Power,3);   //we do a linebreak together with the last print   
}

//If you found my video helpful, please SUBSCRIBE:  https://www.youtube.com/c/CuriousScientist?sub_confirmation=1
//The code belongs to the following tutorial video: https://youtu.be/wqADfB0Y4ts

void PrintOLED()
{  
  //128x32 OLED
  //1st line of the OLED
  display.clear();  //we have to clear the previous data before printing the new one
  display.setCursor(0, 0); //The cursor's unit is in pixels and not in blocks as in the case of the 16x2 LCD
  display.print("U: ");
  display.print(Voltage,3); //we print with 3 decimal places
  display.print("  I: "); 
  display.println(Current,3);
  //2nd line
  display.setCursor(0, 1); 
  display.print("t: ");
  display.print(elapsedTime/1000);   //time in seconds
  display.print(" s  P: "); 
  display.print(Power,1);
 
}

Previous
Previous

Testing different Peltier coolers by cooling/freezing water - Part 4 - TEC12708

Next
Next

4 channel temperature logger based on the DS18B20 sensors