Fluctuating voltage value in print console

I have made myself an Car battery monitoring circuit with Wemos D1 Mini and i have used 1x 1M resistor and 1x 220K resistor in series before the A0 pin.

The voltage as showing is correct, but it fluctuates. The readings on the picture have an one second delay.

Here is my code:

int voltPin = A0;
float voltValue;

void setup() {
  Serial.begin(9600);
  pinMode(voltPin, INPUT);

}

void loop() {
  voltValue = analogRead(voltPin);

  float voltage = voltValue * (15.0 / 1023.0);


  Serial.print("Battery Voltage: ");
  Serial.print(voltage);
  Serial.println("V");
  delay(1000);
}

How can i make the readings more stable?

Floating point math is not 100% accurate on small MCU's, so try to convert you math to integers and see if it stabilizes. You could also use an average of the last 5-10 measurements in order to even out any electrical fluctuations.

well if its a 12V lead acid car battery you should be reading around 13V - so your readings are wrong.

To get decent readings in a noisy environment you need to average the adc reading as explained here

your potential divider scales 18V down to 3.3V so you need

 float voltage = voltValue * (18.0 / 1023.0);

but I still dont see why your readings are so far out.

I'd hope its MUCH better than the ADC resolution

I just test with a bench power supply so no battery is connected. All voltage readings is correct and when i give Wemos D1 Mini 15V to A0, the value is 1023, so 15V is max. If i give A0 18V i kill the D1.

So i think i have to avarage the readings some how...

That is quite simple:

#define NUM_READINGS 5
uint16_t readings[NUM_READINGS];
uint8_t readings_idx = 0;

store_reading(value) {
  readings[reading_idx++] = value;
  if (reading_idx >= NUM_READINGS) reading_idx = 0;
}

get_average {
  uint32_t result = 0;
  for (uint8_t i = 0; i < NUM_READINGS; i++) result += readings[i];
  return result / NUM_READINGS;
}

Hi,
Try a 0.1uF capacitor from A0 to gnd.
Also try lower values of your potential divider.
1M and 440K will be susceptible to noise.

Tom... :smiley: :+1: :coffee: :australia:

https://www.esp8266.com/viewtopic.php?p=61322#p61759

many boards like NodeMCU or WemoS D1 have input resistor diver chains to allow 0-5 inputs and effectively divide that input range down to 0-1volt for the ESP, in which case the input impedance of these boards would be much lower. The Wemos D1 mini for example has a 220K and 100K series divider giving you an input impedance of < 100Kohm.

I think that means you should be using resistors well below 100k in your voltage divider. Try 10k and 2.2k.

Or, if you want a lower passive current draw when your Arduino is turned off, add an op-amp voltage follower. That will turn a high impedance voltage source into a low impedance voltage source.

Is it possible to explain and or make an simplier code than that?
I think i just don't understand it...

I have tried for a while now, and i just understand how i can smooth out the voltage readings. I have tried different codes with no luck.

Here is an screenshot of readings:

And here is a code i found on Youtube. What am i doing wrong here?

int voltPin = A0;

void setup() {
  Serial.begin(9600);
  pinMode(voltPin, INPUT);

}

void loop() {

  int numReads = 100;
  int senseSum = 0;

  for (int k = 0; k < numReads; k++) {
    senseSum += analogRead(voltPin);
  }

  int senseAve = senseSum / numReads;
  float voltage = senseAve * (17.0 / 1023.0);
  Serial.print("Battery Voltage: ");
  Serial.print(voltage);
  Serial.println("V");
  delay(2000);
}

Taking 100 readings with no delay in between is not a good solution. Also, if "int" is 16 bit it will overflow. You could lower the number of readings to 10 and put in a small delay of 100ms in the for loop. Or you could use the better solution I posted in #6 above.

Hi,
Is there a reason you want 0.01V precision.
Mechanics and autoelecs are usually happy with 0.1V

Have you tried 10uF between A0 and gnd?
Have you tried lower resistor values for you pot divider?

Can you please post some images of your project please?

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

Here is a dead simple method of smoothing the readings:

template<uint8_t pin> uint16_t analogReadAvg()
{
	const uint8_t ANALOG_BUFFER_SIZE = 10;
	static uint8_t buffer_idx = 0, buffer_size = 0;
	static uint16_t buffer[ANALOG_BUFFER_SIZE] = {0};
	buffer[buffer_idx++] = analogRead(pin);
	if (buffer_idx > ANALOG_BUFFER_SIZE) buffer_idx = 0;
	if (buffer_size < ANALOG_BUFFER_SIZE) buffer_size++;
	uint32_t result = 0;
	for (uint8_t i = 0; i < buffer_size; i++) result += buffer[i];
	return result / buffer_size;
}

void loop()
{
  uint16_t avg = analogReadAvg<voltPin>();
  float voltage = avg * (17.0 / 1023.0);
  Serial.println(voltage);
  delay(1000);
}

I just want to make my own code work and understand that before i try other codes.

When i start the serial monitor the voltage shows correct smooth and fine the first seconds. But after some seconds, its begin to fluctuate by approx 0.1V.

I hvae mounted an 10uF electrolytic capacitor between ground and analog input, but that does not smooth out the readings. But when i adjust the input voltage i can se the values change more slowly. But it does not fix the voltage readings.

But why does the voltage sows nice and smooth for some seconds when i start the serial monitor and resets the board?

This is my last code:

int voltPin = A0;


void setup() {
  Serial.begin(9600);
  pinMode(voltPin, INPUT);

}

void loop() {

  int numReads = 5;
  int senseSum = 0;

  for (int k = 0; k < numReads; k++) {
    senseSum += analogRead(voltPin);
    delay(1);
  }

  int senseAve = senseSum / numReads;
  float voltage = senseAve * (17.1 / 1023.0);
  Serial.print("Battery Voltage: ");
  Serial.print(voltage);
  Serial.println("V");
  delay(100);
}

Your delay is too short to have any real effect, try to up it to 100ms. Would you try the method I posted in #14? It uses a cyclic buffer to even out any fluctuations and that is more robust in the long term.

I have tried with 100ms delay. I did not work.

I get error when i tries your code...

Sorry, try to replace "int voltPin = A0;" with "#define voltPin A0".

Hi,
I sounds like the fluctuations in the 5V supply, which is your ADC reference is fluctuating.
The UART and USB IC may be producing noise on the 5V supply when they are transmitting data.

Try a 10uF or 100uF across the 5V pin and gnd of the D1.

Does the D1 have an internal reference you can use instead of the supply reference?

Tom... :smiley: :+1: :coffee: :australia:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.