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
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); }