Measure 5v from 3.3v, using arduino as switch

Would the above circuit work to measure the battery voltage?

The idea here is to connect the voltage divider to ground only when we want to measure, when we don't want to measure D0 high or tri state.

I think this is the best treatise on measuring battery voltage. Note that it goes on for several pages.

https://jeelabs.org/2013/05/16/measuring-the-battery-without-draining-it/index.html

1 Like

thanks, that makes sense.

What happens to the output of the MOSFET when it is turned off, how does it stop the 3V-5V connecting directly to a 3V3 GPIO via R1?

1 Like

You are right, I didn't think that one out

1 Like

@turbogrill
I was wrong, putting a MOSFET from R2 to ground will not work

You put the N-channel mosfet between the two resistors, and tap A0 below the mosfet. Then when the mosfet is off, A0 is grounded through the lower resistor. And when it's on, you get the divided voltage. So no exposure to 5V. So jim-p, you were wrong in thinking you were wrong. :slight_smile:

But note that you have to divide down pretty low so the mosfet will still turn on with 3.3V at its gate. So probably 1V or below, depending of course on the mosfet's threshold voltage.

But my favorite puts a P-channel mosfet at the top, with a capacitor in the line to the gate to protect the GPIO:

https://jeelabs.org/2013/05/18/zero-power-measurement-part-2/index.html

That lets you divide down to 3.3V max.

I think it would as long as D0 was an output, and LOW.
However with D0 high or perhaps configured as input - pullup Vbat would be applied to A0 and D0 - not good.
So the trick from the above post is likely best.

I don't see how that could be the case. The N-channel circuit I'm referring to is here:

https://jeelabs.org/2013/05/17/zero-powe-battery-measurement/index.html

Neither the D* or A* pin is ever exposed to Vbat.

My reply was to post 1, so I was referring to the original suggestion.

I agree with you that circuit seems the optimal solution. However depending on the interval between measurements the voltage divider + capacitor with high value resistors provides a simple solution and the drain current may well be less than the battery's self discharge - depending on chemistry.

I've always thought the capacitor version was very clever. But it might require some experimentation to get to the right capacitor value. You can't take too long to take the reading because the cap will recharge and turn off the mosfet. So you might have to try out different values.

But in either case, you can use cheap TO-92 mosfets so long as they have reasonable threshold voltage. But they don't have to have reasonable RDSon. If it's 10 ohms, that's just 10 ohms in series with divider resistors of many K, so it really doesn't matter.

@ShermanP I've little experience with mosfets.
I'm looking to get a couple to try this idea, as I'd like to see the voltage on the gate.

Can you tell if these would be suitable please?
https://www.mouser.co.uk/datasheet/2/268/VP2106_P_Channel_Enhancement_Mode_Vertical_DMOS_FE-2887725.pdf

or these?

Neither will work.

The OP wanted to measure a voltage of 3V-5V, so the minimum Vgs on the MOSFET would be 3V.

However, the max Vgs for the VP2106 is 3.5V so it will never turn on. The Vgs of the other MOSFET is even higher.

I agree. See if you can find a TP2104. Maximum threshold voltage is 2V, so it should work ok for this purpose at 3.3V.

Thenks @jim-p, @ShermanP
I'll have a look for a better mosfet - thanks for your suggestion Sherman

However

A voltage divider of up to 22M - 22M or 27M - 27M would give a continuous current of only 5V/50M = 100nA. You can use a small capacitor to ground to hold the voltage for the adc to read.

much less than an esp32 in ANY sleep mode.

and apparently using timer wakeup to wake the device is tricksy (not impossible) for periods of more than 3 hours.

I don't think ADC would work with those resistors. I think ADC needs a lower impedance input than that.

I've not tried it, (yet) but providing the input leakage current is low I think it should be possible.


The data sheet says the input is "optimised" for measuring from an output resistance of 10k or less. But that is to provide a very fast response time, which measuring battery voltage should not need.

Your right. For measuring battery voltage your idea is perfect.

I finally tested it Jim: here is the code

/*
  Analog input, serial output on NANO V3 to test effect of high resistance on analog input

  The circuit:
 A0 connected to 3V3 via 680 ohm 
 A1 connected to 3V3 via 680 ohm initially, then via 10M with 0.1uF to gnd at A1

  

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/AnalogInOutSerial
*/

const int analogIn0 = A0;
const int analogIn1 = A1;
const int ledPin = 3;

unsigned long A0agg, A1agg;  //aggregate readings to get more precision
float A0val, A1val;
int count = 64;  //number of readings to aggreagate
// note the actual value is not important to no calibration is needed,
// just a check that the analog input readings are unaffected by the high Z.
int i, j;  //loop counts

void setup() {

  Serial.begin(57600);
  pinMode(ledPin, OUTPUT);
  analogReference(DEFAULT);
}

void loop() {
  // read and aggregate the reading on A0:
  A0agg = 0;
  for (i = count; i > 0; i--) {
    A0agg += analogRead(analogIn0);
    delay(7);
  }
  //Serial.print("I= ");
  //Serial.print(i);
  Serial.print("A0 result ");
  Serial.print(A0agg);
  A0val = float(A0agg) / count;
  Serial.print(":  A0 reading ");
  Serial.print(A0val);
  // toggle LED state
  digitalWrite(ledPin, !digitalRead(ledPin));

  Serial.print("  ::  ");  //spacer between A0 & A1 readings

  // read and aggregate the reading on A1:
  A1agg = 0;
  for (j = count; j > 0; j--) {
    A1agg += analogRead(analogIn1);
    delay(7);
  }
  //Serial.print("J= ");
  //Serial.print(j);
  Serial.print("A1 result ");
  Serial.print(A1agg);
  A1val = float(A1agg) / count;
  Serial.print(":  A1 reading ");
  Serial.println(A1val);

  // toggle LED state
  digitalWrite(ledPin, !digitalRead(ledPin));
  delay(1000);
}

Initially on a NANO, with the 3v3 connected to A0 & A1 via 680 ohm the readings as expected corresponded within 1 lsb.
eg A0 result 47394: A0 reading 740.53 :: A1 result 47384: A1 reading 740.38

With A1 connected via 10M and 0.1uF ceramic to ground I'm getting these results:
A0 result 47403: A0 reading 740.67 :: A1 result 47456: A1 reading 741.50
A0 result 47396: A0 reading 740.56 :: A1 result 47441: A1 reading 741.27
A0 result 47408: A0 reading 740.75 :: A1 result 47421: A1 reading 740.95
A0 result 47365: A0 reading 740.08 :: A1 result 47365: A1 reading 740.08
A0 result 47400: A0 reading 740.63 :: A1 result 47392: A1 reading 740.50

A1 is possibly picking up a little noise, but I'd say the test shows the Analog input is not prejudiced by a high Z input, and the leakage current is less than 1nA

see below, @ShermanP