The output of the module is a voltage that is proportional to the current flowing through the device. The module measures both AC and DC current, and for DC will report the current as positive or negative. Therefore the voltage output is centred around half of the module supply voltage. The measured voltage represents amps per millivolt – for the 5-Amp device the measurement is 0.185v per Amp. In order to convert this voltage to a current reading the Arduino needs to know the supply voltage of the module, in order to calculate the centre value and therefore the variance from this centre value.
Arduino Pro Mini. I chose the Pro over the Nano because
I do not expect to be re-programming it and the USB interface could not be
justified. I have positioned it so that I can access the serial input pins
if required.
ACS712 current sensor module. Any
of the available variations of maximum rated amperage will do, but note
that the resolution is less at higher rated amps. The code provided
assumes the 5A version.
128x64 OLED display with I2C interface.
On/Off button. Salvaged from an old PC.
Momentary push button. Salvaged from an old PC.
Hookup wire and a scrap of perfboard.
9v Battery with clip and leads.
3D printed case with 3 3mm screws and knurled inserts.
Note that a prototyping board was not used for this project because the
components sit at different heights relative to the top surface, so it
would have been difficult to get everything at the correct level if they
were soldered to a single board.
The cover for the OLED was sourced from Thingiverse and scaled to
suit. There are many different sizes of OLED, so some experimenting
will probably be required to get just the right size. When adjusted
correctly the frame clamps the mounting surfaces between the front and
rear sections, without imposing any pressure against either the OLED
surface or the module substrate.
With the layout confirmed I designed a case to suit. Only the ACS module and the perfboard strip have mounting holes, so everything else sits on an offset on the bottom of the case, and is positioned by dividing pieces or by the cutout in the lid.
There is a cutout for the Pro programming pins
connections at the back, with a cover plate that can be pressed into place
to conceal them.
The code for the ammeter is not complex, but it does include a calculation to allow for calibration. This calculation occurs at startup, so there is an assumption that no current source is attached the the ACS terminals when the Arduino initialises.
The calibration code also executes whenever the user presses the calibration button. This should only be done when there is no load across the ACS terminals. This is not really required, as it is almost as easy to turn the unit off and turn it on again, but it is available as a quick check that the battery voltage has not changed significantly.
The code uses the Ascii and AsciiWire versions of the SSD1306 OLED libraries. These libraries provide all the functionality that the application needs with much less overhead than the standard libraries. The standard libraries could be substituted with a few simple and obvious changes to the code (although some juggling might be required to get the display laid out just right).
Confirm that the I2C address for your OLED is correct. Adjust the number of samples if required (above about 100 it makes very little difference).
#include <Wire.h>
#include <SSD1306Ascii.h>
#include <SSD1306AsciiWire.h>
// OLED I2C address
#define I2C_ADDRESS 0x3C
SSD1306AsciiWire display;
boolean startup = true; // Flag to indicate auto calibrate
const int acsIn = A0; // Analog input for ACS reading
const int btnIn = 9; // Digital input for button press (active low).
void setup() {
Wire.begin();
Wire.setClock(400000L); // Adjust to suit OLED, if required.
pinMode(btnIn, INPUT_PULLUP);
pinMode(acsIn, INPUT);
//1 Serial.begin(9600); //Start Serial Monitor to display current read value on Serial monitor
display.begin(&Adafruit128x64, I2C_ADDRESS);
display.setFont(fixed_bold10x15);
display.clear();
display.println();
display.setLetterSpacing(2);
display.println(F("DIGITAL"));
display.print(F(" AMMETER"));
display.setFont(Adafruit5x7);
delay(1000); // Pause for 2 seconds
}
float cNominal = 1024.0; // ADC count max
float cCentre = 512.0; // ADC count centre (zero amps)
float vpc = 0; // Volts per count
void loop() {
unsigned int x = 0;
float vInput = 0.0, nSamples = 0.0, vAverage = 0.0, vAdjusted = 0.0, aCalculated;
for (int x = 0; x < 150; x++) { //Get 150 samples.
vInput = analogRead(acsIn); //Read current sensor values.
nSamples = nSamples + vInput; //Accumulate sample values.
delay (5); // Required ADC settling time.
}
vAverage = nSamples / 150.0; // Calculate average value.
//vpc is the assumed supply Vcc. The ADC value is referenced to this voltage.
//You must change the offset according to the input voltage
//0.185 (185mV) is output voltage change for 1A current ACS712-05 ( 5 Amp).
//0.100 (100mV) is output voltage change for 1A current ACS712-20 (20 Amp).
//0.066 (66mV) is output voltage change for 1A current ACS712-30 (30 Amp).
vpc = 5.00 / cNominal; // millivolts per ADC count. Adjust if Vcc is not 5v.
vAdjusted = (vAverage - cCentre) * +vpc; // Volts = Count * Volts per count.
aCalculated = vAdjusted / 0.185; // Amps = Volts / Volts per Amp.
// Re-calculate zero amps reading and max count at startup and at button press.
if ((digitalRead(btnIn) == LOW) || startup) {
cCentre = vAverage;
cNominal = cCentre * 2.0;
startup = false;
}
display.clear();
display.setFont(System5x7);
display.println(String(cNominal, 3) + ' ' + String(vAverage, 2));
//display.println();
display.setRow(2);
display.setFont(ZevvPeep8x16);
display.set2X(); // Double-size font
if (aCalculated >= 0.0) {
display.print(" " + String(aCalculated, 3));
}
else {
display.print(" " + String(aCalculated, 3));
}
display.set1X(); // Standard-size font.
display.setCursor(98,6);
display.println("Amps");
delay(50);
}
This site was last updated 18th August 2024.