Introduction: DIY Wattmeter Using Arduino Uno

About: Learn something new everyday

This instructable demonstrates how an Arduino can be used to control an analog panel meter. The analog meter can be used to display any sort of metric you like it to do.Voltage, Current, Resistance, Speed, Distance , Magnetic field density....anything that you would want an analog meter to display. However you have to also use your intuition to trick the meter into displaying the value you want it to display.

This can be done because Arduino Uno can output voltages between 0-5V in analog output pins. This if properly used in a voltmeter with a range of 0-5V, can be used as a very reliable meter that responds to sudden changes and can also give you very smooth transitions between values, depending upon how you program it.

Step 1: Controlling the Voltmeter

Caution: Analog meters are quite sensitive and unlike digital meters, where if you plug in the wrong way around, there is a chance you will break the needle. Operating the meters requires a basic knowledge of analog meters.

Analog meters basically operate like a motor with a spring at the arm. Applying current through the contacts generates a force proportional to the current. The spring constantly pulls the opposite direction of the force of the moment. This means that if you apply full voltage and immediate turn the power off, the needle will hit the 0V at a high force causing damage to the needle. The voltmeter I purchased did not have polarity written on the contacts so I had to assume one contact was positive and slowly added voltage to see where the needle moved.

Its important that you find a Voltmeter with 0-5V. The Arduino Uno can output maximum of 5V. Arduino achieves different voltages by a process called Pulse Width Modulation using the analogWrite method.

.

Since the voltage range is 0-5 and the range of values for analogWrite is 0-255, we can write an equation where x axis is desired voltage and y axis is desired analogWrite value,

slope m= (y2 -y1)/(x2 - x1)

m=(255 - 0) / (5 - 0)

m= 255 /5= 51

So substituting back into the equation with x1=0, y1=0 we get

51=(y2 - 0) / (x2 -0 )

y2= x2 * 51

In other words,

Analog Write value= 51* Desired Voltage.

For a more in-depth explanation, watch the lecture by Paul McWhorter here:

https://www.youtube.com/watch?v=9FBMVt-iFrM

Step 2: Movement - Calibration Code

I will go through the code in parts and post the final code at the end. Here I have created a method called void start() which runs once at setup. This could be seen as a calibration procedure for the meter. It will cycle through 1 through 5 volts and at 5V slowly reduced the value to 0V.

void start()
{

int x=0; int y=255;

//////////

This creates jumps in sequence to 5V. Note the values are from the graph. The delay is 1.5 seconds between intervals. 1 second interval is too quick because when the needle jumps, it generates oscillations before it settles down.

///////////

analogWrite(ledPin, x);

analogWrite(ledPin, 51); delay(1500);

analogWrite(ledPin, 102); delay(1500);

analogWrite(ledPin, 153); delay(1500);

analogWrite(ledPin, 204); delay(1500);

analogWrite(ledPin, 255);

////////////////

In the next part, y=255 or the voltage starts at 5V since the previous code ends in 5V and this code picks up the movement and slowly decreases the voltage values to 0V. The analogWrite value is reduced once every 40 milliseconds which I find to be a good rate for smooth motion as shown in video.

/////////

while (y>=0) { analogWrite(ledPin, y); delay(40);

y--; }

}

////////////////////////

and in setup call the method start();


Step 3: Ammeter

For measuring current, you can use any type of current sensing module. I used the ACS712 Current Sensor Module (30A). It gives out precise value of current readings (3% error) and can be read using Analog input pin. The current sensor can take very high voltages ( I used 48V DC in my setup) and the sensor is relatively easy to set up. For the ACS712 , knowing the offset value is important. It can be obtained from the datasheet

int ACSoffset = 2500;

///////loop code///////

RawValue = analogRead(analogIn);
Voltage = (RawValue / 1024.0) * 5000; // Gets you mV

Amps = abs( ((Voltage - ACSoffset) / mVperAmp));

///////////

The builtin voltage function here was not very useful to me. I used the current values instead.

Watts is a measurement of energy. In electrical terms,

Watts = Voltage x Current ,

where Voltage is in Volts and Current in Amperes.

My power supply used 48V DC and could supply up to 400W, so I want the meter to show up to 500W,

where 1V in the meter can be interpreted as 100W, 2V as 200W and so on. Therefore I converted current and known voltage into watts,

watts=Amps*48;

finally the equation shows

Analog Value= 51 * Desired Voltage

and 500W is 5V, 400W is 4V and so on,

therefore,

Desired Voltage= Watts /100

So Rewriting the equation we get,

Analog Value = 51 * (Watts/100)

Analog Value= 0.51*Watts

As the code shows,

int finalstep = int(watts*0.51);

analogWrite(ledPin,finalstep );

Step 4: Final Code

const int analogIn = A0;
int mVperAmp = 66; // use 100 for 20A Module and 66 for 30A Module

int RawValue= 0; int ACSoffset = 2500;

double Voltage = 0.0;

double Amps = 0.0; double watts=0.0;

int ledPin = 9; // LED connected to digital pin 9

int analogPin = 3; // potentiometer connected to analog pin 3

int val = 0; // variable to store the read value

void start()

{

int x=0;

int y=255;

analogWrite(ledPin, x);

analogWrite(ledPin, 51);

delay(1500);

analogWrite(ledPin, 102);

delay(1500);

analogWrite(ledPin, 154);

delay(1500);

analogWrite(ledPin, 205);

delay(1500);

analogWrite(ledPin, 255);

while (y>=0) {

analogWrite(ledPin, y);

delay(40);

y--; }

}

void setup()

{

Serial.begin(9600);

pinMode(ledPin, OUTPUT); // sets the pin as output

start();

}

void loop()

{

RawValue = analogRead(analogIn);

Voltage = (RawValue / 1024.0) * 5000; // Gets you mV

Amps = abs( ((Voltage - ACSoffset) / mVperAmp));

Serial.print("Raw Value = " ); // shows pre-scaled value

Serial.print(RawValue);

Serial.print("\t mV = "); // shows the voltage measured

Serial.print(Voltage,3); // the '3' after voltage allows you to display 3 digits after decimal point

Serial.print("\t Amps = "); // shows the voltage measured

Serial.println(Amps,3); // the '3' after voltage allows you to display 3 digits after decimal point

watts=Amps*48;

int finalstep = int(watts*0.51);

analogWrite(ledPin,finalstep );

}