I have recently gotten into arduino, i put together a code wich converts the voltages from my two batterys into readings with max/min values on an lcd. My problem is that these readings are VERY inaccurate. If i do an crontroll with an multimeter my voltage is constant 14.3 volt with an slight differ of 0.05 volts over the time. But with ardu i got insane inaccurate readings whenever i got my car on or off.
I messure my voltages with the help of an 10kohm and an 100kohm resistor.
Firstly, this has nothing to do with the Arduino, it has something to do with your project. (Although I understand you suspect the Arduino).
Electrical signals in a car are very "noisy", very short spikes of different voltages on all wires. Your Multimeter does an "averaging" reading; your Arduino code takes a much smaller snapshot of time, and thus sees more of these fluctuations. Also depending on your wiring the very eads from the battery to the arduino will act as tiny arials picking up the electrical noise.
The simplest way is to make a for-loop and add 5 readings together, then divide by 5 and thus you have an average. That will probably give you more stable readings.
The second is to add a simple RC filter (a small capacitor between your input pin and ground, and a low value resistor in series).
Also make sure no high voltage spikes get into your Arduino, for example by using a Zener diode to clamp the input voltage on your input wires. Maybe usinga shielded wire and earth the shield at both ends will reduce pickup, too.
I have not studied your code, apart from seeing that it is straightforward and you are not (yet) doing an averaging of your input values.
From the ATmega328p datasheet: "The ADC is optimized for analog signals with an output impedance of approximately 10 k or less." I suspect your 100k resistor is too high a value.
Also, dividing by 11 gets you a nominal input of 1.3V which is a waste of a large portion of your input rage (0-5V). Let's figure a maximum expected voltage of 15.0V. To read that on a 5V input we would require a "divide by three" where the signal side resistance is twice the ground side resistance. Use three 10k resistors. Put two in parallel to get 5k and use that for the ground side of the divider. Then you can calculate the battery voltage with: float voltage = (analogRead(voltagePin) / (1024.0/5.0)) * 3.0;
" potValue1 = analogRead(potPin) / 10;"
That is reducing your precision right off the bat. I suggest using the full reading, and running it through the map() function.
I suspect you need more caps. On the analog pin to ground, on the power rails, etc.
How are you powering the arduino?
Thanks for the good answers. im powering the arduino right from battery no1. will look more into these answers tomorrow since its realy late here.
And no, i am not doing any averaging yet. so an average of 5 readings is the optimal?
From my simple view what stops me from doing an sample of 500 / second and averaging 100 each and printing it 5 times a second?
Arduino’s 5volt supply is by default used as reference for the A/D converter.
That default Aref makes A/D readings potentially unstable.
Better to use the stable internal 1.1volt Aref.
Here is a sketch to try.
It uses pre-reading, averaging and 1.1volt Aref.
Leo…
/*
0 - ~17volt voltmeter
displays the voltage on the serial monitor and/or LCD shield
works with 3.3volt and 5volt Arduinos
uses the internal 1.1volt reference
10k resistor from A1 to ground, and 150k resistor from A1 to +batt
(1k8:27k or 2k2:33k are also valid 1:15 ratios)
100n capacitor from A1 to ground for stable readings
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // your LCD pins could be different
//int ledPin = 10; // backlight pin
float Aref = 1.075; // change this to the actual Aref voltage of ---YOUR--- Arduino (1.000 - 1.200), or adjust to get accurate voltage reading
unsigned int total; // A/D output
float voltage; // converted to volt
void setup() {
analogReference(INTERNAL); // use the internal ~1.1volt reference, change (INTERNAL) to (INTERNAL1V1) for a Mega
Serial.begin(9600); // ---set serial monitor to this value---
//analogWrite(ledPin, 255); // optional dimming
lcd.begin(16, 2); // shield with 2x16 characters
lcd.setCursor(0, 0); // first line
lcd.print("Voltmeter"); //info text
lcd.setCursor(0, 1); // second line
lcd.print("0-16 volt");
delay(2000); // info display time
lcd.clear(); // clear
lcd.setCursor(0, 0); // first line
lcd.print("Battery is"); // print this once
}
void loop() {
analogRead(A1); // one unused reading to clear old sh#t
for (int x = 0; x < 16; x++) { // 16 analogue readings and 1/16 voltage divider = no additional maths
total = total + analogRead(A1); // add each value
}
voltage = total * Aref / 1023; // convert readings to volt
// print to LCD
lcd.setCursor(0, 1); // second line
lcd.print(voltage);
lcd.print("volt ");
// print to serial monitor
Serial.print("The battery is ");
Serial.print(voltage);
Serial.println(" volt");
total = 0; // reset
delay(1000); // readout delay
}
Msquare:
The second is to add a simple RC filter (a small capacitor between your input pin and ground, and a low value resistor in series).
Also make sure no high voltage spikes get into your Arduino, for example by using a Zener diode to clamp the input voltage on your input wires.
A voltage divider plus a 100n cap from analogue-in to ground is a filter.
A zener adds non-linearity and temp dependency. Bad advice.
A 10k:150k divider protects to ~200volt (<1mA pin protection diode current). No zener needed.
johnwasser:
“The ADC is optimized for analog signals with an output impedance of approximately 10 k or less.” I suspect your 100k resistor is too high a value.
Also, dividing by 11 gets you a nominal input of 1.3V which is a waste of a large portion of your input rage (0-5V).
A 100n cap from analogue input to ground is a very low impedance to ground compared to the ~12pf sampling cap.
A 10Megohm resistor would still work.