Hi All,
I'm trying to make a high-precision digital multimeter and watt-meter. (Going for 100uA and 1~2mV resolution.)
I am using the ACS712ELCTR-05B-T for current measurement, and the Adafruit ADS1115 16-bit ADC to read the voltage and current values.
My test board is an Uno R3 @ 16MHz (when built I will transfer to a 5v 16MHz Pro Mini).
My problems are twofold:
- The output from the ACS712 is massively unstable.
- My code for reading the values is too slow!
I'm mainly after help with point 2 here - I'm pretty sure the instability will be solved with a replacement 712, or better grounding when I make it off the breadboard.
Here's my code (so far):
#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <LiquidCrystal_I2C.h>
Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
#define ADS1115_REG_CONFIG_DR_860SPS;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
int i;
float avVolt = 0;
float avAmp = 0;
float lastVolt = 0;
float lastAmp = 0;
float numLoops = 50.00;
long previousMillis = 0;
void setup(void)
{
Serial.begin(115200);
Serial.println("Hello!");
lcd.begin(20,4);
lcd.backlight();
lcd.setCursor(1,0);
lcd.print("Digital Multimeter");
lcd.setCursor(7,1);
lcd.print("V1.0.0");
delay(3000);
lcd.clear();
lcd.setCursor(1,0);
lcd.print("V = ");
lcd.setCursor(1,1);
lcd.print("A = ");
lcd.setCursor(1,3);
lcd.print("Loop Millis = ");
Serial.println("Getting differential reading from AIN0 (P) and AIN1 (N)");
Serial.println("ADC Range: +/- 4.096V (1 bit = 0.125mV)");
// 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.begin();
}
void loop(void)
{
unsigned long currentMillis = millis();
for (i = 0; i < numLoops; i++) {
int16_t Vresults;
int16_t Aresults;
Vresults = ads.readADC_Differential_0_1();
Aresults = ads.readADC_Differential_2_3();
avVolt = lastVolt + Vresults;
avAmp = lastAmp + Aresults;
lastVolt = avVolt;
lastAmp = avAmp;
//Serial.print(i);
//Serial.print(" ");
//delay(1);
}
float Vmultiplier = 0.000125F; /* ADS1115 @ +/- 4.096V gain_1 (16-bit results) */
float Amultiplier = 0.000125F * (1 / 0.185);
float Vval = ((avVolt * Vmultiplier) / numLoops);
float Aval = ((avAmp * Amultiplier) / numLoops) - (2.5339 * (1 / 0.185));
//Serial.println();
//Serial.print("V = ");
//Serial.println(Vval, 3);
//Serial.print("I = ");
//Serial.println(Aval, 4);
lcd.setCursor(5,0);
lcd.print(Vval, 3);
lcd.setCursor(5,1);
lcd.print(Aval, 4);
lastVolt = 0;
lastAmp = 0;
avVolt = 0;
avAmp = 0;
//delay(1);
previousMillis = millis() - currentMillis;
lcd.setCursor(15,3);
lcd.print(previousMillis);
//Serial.print("Previous Millis = ");
//Serial.println(previousMillis);
}
The ADS1115 should be able to take 860 samples / second. I know I'm doing maths in the smoothing loop, but it's hardly rocket science!
At numLoops = 50, the LCD updates at 915 millis. If I remove the LCD, it still only updates at 904 millis.
At numLoops = 100, the LCD updates at 1815 millis, and 1804 millis with serial.
This leads me to believe its the "ads.readADC_Differential_x_x()" commands which are taking all the time.
Far from 860SPS, I'm only achieving ~55SPS!!
My ultimate aim (obviously there are more calculations to be added later when Watts, Wh and Ah are being calculated) is for a 3-4Hz LCD update, with 100+ samples being averaged.
Can anyone point me to why this is running so slowly?!
Thank you,
Tom.