Voltage divider resistor value

I’m designing a circuit that works with 18650 lithium batteries so my ATtiny13 uC is constantly checking the voltage of the battery cells. There are 3 batteries in series and I’m using this circuit to check the voltage of each one:

Now because the device is battery powered, and more importantly because lithium batteries shouldn’t be drained too much I would like to use larger resistors for the voltage divider. I’m thinking 1M ohms. (i.e. replacing each 100k in the pic with a 1M).

But I was wondering if using big values for resistors could cause noise or inaccurate readings. Same as a 1M ohm pullup resistor would be too “weak”.

Well that i don’t know, but i would be using PB5 for measurement, since it is also the reset pin, if that goes to low your ATTiny resets and doesn’t take appropriate action. (probably wont happen, but still…)
Problem regardless of all this is that you are not really measuring each battery individually, but rather get there through calculation. There are hardware solutions to monitor your battery available like a FS312-F

Yes, the readings will be inaccurate unless you add some 100nF capacitors to ground on each analog input - then you can up the resistor values quite a lot - the ADC needs to see low impedance when switching between different inputs, capacitance provides that low impedance without increasing current consumption. Better make sure your resistors are reasonably good tolerance like 1% or so, otherwise there’s little point improving the ADC accuracy in the first place (!)

The battery voltage is never gonna reach 0 so (hopefully) there won’t be a problem.
Yes I get each battery’s voltage with calculations by subtracting the previous voltage from the combined voltage.
Regarding the IC, yes I wish an IC like that was available here. All that is available here are crappy ICs and “protection” boards that have 10A max current and 2.5v min voltage.
Min voltage should be 2.7 at least, and the current should be 2-3A max because most 18650 batteries can’t really put out more than that.

I have actually been going through extreme difficulty trying to find a solution for the lithium battery problems. I still don’t know what I’m gonna do. It’s extremely difficult without a good protection board/IC.

Thanks Mark.
I don’t need very accurate readings. Even up to 50mV inaccuracy is acceptable. Do I still need the caps?
I don’t mind adding them, just curious.

You may or may not need the capacitors, it depends on how you use the analogRead function.

Without the capacitor, it is likely to be inaccurate when you read a different input to the previous one as the internal capacitor has not had enough time to stabilise. You need to read each input twice, preferably with a significant delay (perhaps 1 ms) between.

Now I certainly would put another 100k (or 1M, whatever) resistor in series with the connection to the lowest battery because connecting it directly to a chip input sounds like a really bad idea.

This is how I’m reading the input:
(ADLAR is set because like I said 8bit resolution is enough for me)

	ADMUX = (0b00100000 | bat1MUX);
	uint8_t cel1Val = readADC();
	ADMUX = (0b00100000 | bat2MUX);
	uint8_t cel1_2Val = readADC();
	uint8_t cel2Val = (cel1_2Val * cel2DivRatio) - cel1Val;
	ADMUX = (0b00100000 | bat3MUX);
	uint8_t cel1_2_3Val = readADC();
	uint8_t cel3Val = (cel1_2_3Val * cel3DivRatio) - cel2Val - cel1Val;

and the readADC() function:

uint8_t readADC()
	//start the conversion
	ADCSRA |= (1 << ADSC);
	//wait until read is complete
	while (ADCSRA & (1 << ADSC));
	return ADCH;

I guess I have to add the capacitors, there’s no delay at all.

Regarding the 100k resistor you mentioned, I was actually going to ask about this.
As you can see from the schematic I have the batteries connected to the uC. I have a switch too, which is connected to the VCC pin of the uC. I was wondering if it is okay for the batteries to be connected to the input pins when the switch is off.

Also, I thought input pins have very high impedance by themselves, why should connecting a battery be a problem? They receive 5v all the time. For example when you connect a potentiometer you go from shorted to ground to shorted to VCC.

But you are already measuring only over 10% of the full range (4.2v - 3.7v over a full 5v range of the ADC)

I only need to detect if the voltage goes below 3 volts.
3 volts converted by the ADC would be: (3/5) * 255 = 153.
So what I’m doing in the code is check whether the ADC value is below 153.
Another reason for that is because float operations don’t fit in the 1kb space of the tiny13, so I’m just comparing the ADC values.

Is there something I’m missing?


I would not drain it that far.

That is true, or at least, it does fit, but doesn’t really leave any space for anything else.
But 16-bit computations are probably going to work ok, 16-bit comparisons do take up extra flash though.
Still if you start with a 10-bit ADC, you know that actually you the 10th bit always needs to be high, so i would do something like

uint8_t adc = (analogRead(pin) >> 1) & 0xFF;

That should give you at least double the resolution, though maybe it isn’t all that tight. The most accurate is to use OP-amps as voltage comparators.

Hmm… smart move.
My code isn’t final yet. If I ended up having spare room I’ll use this approach for more resolution.
I’ll keep this in mind for the future.

Maybe you missed the issue with Vref. The ADC can use Vcc or an internal 1.1V source as a reference. If you are using an internal source, the input voltage to be measured should be 0-1.1V and you need another resistor dividers.
If you are using Vcc, the input voltage should be 0-Vcc. However, Vcc as Vref should be stable. You cannot use Vbat as Vref because it changes.
What is your ATtiny13 Vcc?

ATtiny13A datasheet says:
The ADC is optimized for analog signals with an output impedance of approximately 10 kOhm or less. If such a source is used, the sampling time will be negligible. If a source with higher impedance is used, the sampling time will depend on how long time the source needs to charge the S/H capacitor, with can vary widely. The user is recommended to only use low impedant sources with slowly varying signals, since this minimizes the required charge transfer to the S/Hcapacitor.

1 Like

Vcc is 5v coming from an ams1117.
I did a test run with an arduino (changed some registers) and everything seemed to work fine. I don’t currently have any issues with the code. I asked “Is there something I’m missing” because Deva_Rishi was suggesting I might need higher ADC resolutions.

I think it is not a good idea to read all 3 cell voltages: You are only interested in the total battery voltage and the ground connected cell will have to provide current for all 3 voltage dividers. That will unbalance the charging of each cell.

True ! hence also my suggestion of Op-amps, Though actually what you want ideally is the charge of every individual battery, but measured across the poles of each battery individually, not through calculus.

No you have to monitor each cell individually because sometimes one of them fails. You might have 3.5 + 3.5 + 2 which gives you 9 volts. If you don’t have the voltage on each cell you might think you have 3x 3v cells, but in reality one of your cells is being damaged. I didn’t take this seriously and this actually happened to me. One cell was quite hot and the voltage was below 2. Got lucky it didn’t explode and catch fire.

But if each op-amp is measuring one cell they will not have common ground with the rest of the circuit. How are they supposed to signal the rest of the circuit if the voltage got too low?

Creating a Voltage Substrator.
Personally i’ve never done it, but i think i’ll get it to work. An old LM724 quad OP-amp would do the trick (i know they are obsolete, but i have a few…) I would probably even play with resistor values to extend the range, so that a near empty battery would signal around 1 Volt, but first a basic setup of course.

+/-50mV across a 3.7V cell is +/-1.4%, which is why I said 1% resistors are appropriate - you can alternatively measure each resistor and add a calibration factor into the code, but
that’s fiddly and 1% resistors are cheap these days.

If you want resistor values around 1M, definitely. You’re only going to see proper readings
for source impedances of 10k or less, and 1M is 100x larger than 10k

@pourduino I see your worry now. What about sensing the battery pack temperature compared to room temperature? Will that warn of a battery fault?