FVR and battery voltage

nbw

Senior Member
#1
Hi everyone. It's been about 5 years since I've been on here. I need a bit of guidance with FVRSETUP etc.

Here's the project: a simple clap switch (works fine) based on an 08m2. It's run off a 4.2V Li-ion battery, and I'd like to keep an eye on the battery voltage, so I can alert if the battery drops too low, say to 3.0V.

I've searched a few threads here on FVRSETUP but to be honest I'm still confused! I have an 18K / 18K (1%) resistor voltage divider from the battery positive to ground, with pin c.1 reading the voltage halfway.

I understand that if I simply read that voltage, I'll get a value about 512 steps (halfway to 1024). Even as the battery voltage drops, the ADC will quite happily report that it's getting 512 steps (thank you very much :) )

So, using FVRSETUP and triggering a 2.048V reference, I should be able to compare it somehow to say at battery voltage = 4.2V, I'm reading 512 steps (say) at c.1, which I can do some maths to convert to 2.1V. If the battery drops to 3.5V, I guess I should be able to trigger the FVR somehow and compare, then some maths to actually give me the 3.5V.

It might be because I'm nearly 50 and my mind isn't as sharp as it usually to be, but I just seem to have a real mental block with this one.

Can someone please help?
Barney
 

hippy

Technical Support
Staff member
#2
Use a 15K/10K divider. That will reduce 4.8V (Vbat) to 1.9V (Vadc), maximum charged battery to below the 2.048V you can measure.

Vadc = Vbat * ( Rbot / ( Rtop + Rbot ) )

Vadc = 4.8 * ( 10 / ( 15 + 10 ) ) = 1.9

Say you want to detect a battery voltage of 3.5V (Vbat). That would be 1.4V (Vadc) on the ADC pin -

Vadc = Vbat * ( Rbot / ( Rtop + Rbot ) )

Vadc = 3.5 * ( 10 / ( 15 + 10 ) ) = 1.4

The Nadc value you get from READADC10 is -

Nadc = ( Vadc / Vref ) * 1023

Nadc = ( 1.4 / 2.048 ) * 1023 = 699.31 = 699

So -

ReadAdc10 pin, w0
If w0 >= 699 Then BatteryOkay

If you want to convert Nadc to Vbat in mV ...

Vbat = Nadc * Vref * (25/10) * 1000 / 1023

Vbat = 699 * 2.048 * 2500 / 1023 = 3498 ~= 3.5V

Of course, you have to make that PICAXE friendly

Vbat = Nadc * 5

Vbat = 699 * 5 = 3495 ~= 3.5V

So -

ReadAdc10 pin, w0
w0 = w0 * 5
If w0 >= 3500 Then BatteryOkay

Or if determined to eke every last drop out down to 3.5V -

If w0 >= 3495 Then BatteryOkay
 
Last edited:

premelec

Senior Member
#3
@nbw if you want even longer battery life consider doubling or tripling each R divider value to get lower drain current into the resistor... accuracy should be OK with these higher R values.
 

nbw

Senior Member
#4
Use a 15K/10K divider. That will reduce 4.8V (Vbat) to 1.9V (Vadc), maximum charged battery to below the 2.048V you can measure.

Vadc = Vbat * ( Rbot / ( Rtop + Rbot ) )

Vadc = 4.8 * ( 10 / ( 15 + 10 ) ) = 1.9

Say you want to detect a battery voltage of 3.5V (Vbat). That would be 1.4V (Vadc) on the ADC pin -

Vadc = Vbat * ( Rbot / ( Rtop + Rbot ) )

Vadc = 3.5 * ( 10 / ( 15 + 10 ) ) = 1.4

The Nadc value you get from READADC10 is -

Nadc = ( Vadc / Vref ) * 1023

Nadc = ( 1.4 / 2.048 ) * 1023 = 699.31 = 699

So -

ReadAdc10 pin, w0
If w0 >= 699 Then BatteryOkay

If you want to convert Nadc to Vbat in mV ...

Vbat = Nadc * Vref * (25/10) * 1000 / 1023

Vbat = 699 * 2.048 * 2500 / 1023 = 3498 ~= 3.5V

Of course, you have to make that PICAXE friendly

Vbat = Nadc * 5

Vbat = 699 * 5 = 3495 ~= 3.5V

So -

ReadAdc10 pin, w0
w0 = w0 * 5
If w0 >= 3500 Then BatteryOkay

Or if determined to eke every last drop out down to 3.5V -

If w0 >= 3495 Then BatteryOkay
Thanks Hippy, I shall make a cup of coffee and digest your thoughts there - thanks! Straightaway I can amend the voltage divider as you suggest, and increase the resistors proportionally to reduce current drain. I'll let you know how I get on. I'm not sure still exactly how fvrsetup comes into it (switching it on etc)
 

nbw

Senior Member
#5
@nbw if you want even longer battery life consider doubling or tripling each R divider value to get lower drain current into the resistor... accuracy should be OK with these higher R values.
I'm going to use hippy's suggested ratio, then double it as you suggest to lower current draw... thanks
 

nbw

Senior Member
#6
OK, I went for Rtop of 27.7K, Rbott of 18.04K (1% resistors). Gives a very close ratio to Hippy's suggestion, with reduced current draw.
So say 4.5V will be reduced to 1.755V at my ADC pin. That's fine.

Is it then simply a matter of initiating the FVR to the 2.048V reference, quickly reading the required ADC port, then multiplying it by 5 to give a mV value?

Something like:

#picaxe 08m2

' code to check the ADC C.1 pin voltage and compare it to a 2.048V fixed reference

fvrsetup fvr2048 ' select the 2 volt reference
adcconfig %011 ' set ADC to FVR
readadc10 c.1, w0 ' read the voltage from the divider into w0

' picaxe will automatically switch off the FVR after a readadc is issued...

w0 = w0 * 5 ' multiply by 5 to give mV (divider voltage)

' use mV to act on varying battery voltages......
 

hippy

Technical Support
Staff member
#7
Is it then simply a matter of initiating the FVR to the 2.048V reference, quickly reading the required ADC port, then multiplying it by 5 to give a mV value?
Pretty much, and as your code shows it. The only thing is the multiplier will be different because your resistor divider ratio has changed.

Rather than calculate it, a better approach is to measure the battery voltage with a meter and SERTXD out the raw READADC10 reading. Then you can determine what the multiplier should be for greatest accuracy.

I calculate that a 3.5V (3500mV) battery voltage would give a READADC10 reading of 886.

The multiplier is then : 3500 / 886 = 3.95

A multiplier of 4 is possibly good enough ( 3.5V -> 3544mV ) but a closer multiplication can be calculated through -

Vbat = Nadc * 3.95

Vbat = ( Nadc * 3 ) + ( Nadc * 0.95 )

And that * 0.95 is the same as -

* ( 0.95 * 65536 / 65536 )

** ( 0.95 * 65536 )

** 62281

So -

Vbat = ( Nadc * 3 ) + ( Nadc ** 62281 )

Code:
FvrSetup FVR2048
AdcConfig %011
ReadAdc10 pin, w0
w1 = w0 * 3
w1 = w0 ** 62281 + w1
SerTxd( "Vbat = ", #w1, "mV" )
Test that under simulation by putting a 'w0=886' after the READADC10 and the result is "Vbat=3499mV". Bingo! w1 contains, near enough, 3500, so "If w1 >= 3500..."

The mV result is slightly low but you can bump that up by increasing the ** multiplier. 62282 works perfectly, 3.5V -> 3500mV.
 

AllyCat

Senior Member
#8
Hi,

Sorry, rather late to the party, I've been asleep for a few hours. :)

You don't need a resistor divider, or even a pin, to read the PICaxe's supply rail (i.e. the battery voltage in this case), just use the CALIBADC command. There are various examples in the "Code Snippets" section of the forum, and I've made a "speciality" of achieving (very) high resolution by various methods (which you probably don't need here).

' picaxe will automatically switch off the FVR after a readadc is issued...
The FVR doesn't actually use much current (your external resistor divider will use more) but I don't think that statement is true. It became very much "lost in the noise" (literally) in a long recent thread when I discussed the issue around post #12. There are various examples of programs in the Code Snippets section which rely on the FVR not being switched off by the READADC command.

Cheers, Alan.
 

AllyCat

Senior Member
#10
Hi Julian,,

Probably not. I don't use X2s myself, but a few members who tried have reported problems (@BESQUEUT in particular). Although it looks as if the SFR commands should work, it appears that the internal PICaxe Interpreter (Operating System) does something to block or cancel the FVR module commands in X2s. :(

But perhaps the comment about the READADC command turning off the FVR does apply to the X2s ? EDIT: It appears that the FVR in M2s uses about 20 uA nominally, whilst it's about 70 uA for the X2s, so there might be more justifictaion in "Automatically" turning off the FVR module. I don't recall exactly what was tested with the X2s, so it might be worth trying my code with the FVR commands moved to immediately before any READADC commands.

ADDENDUM: The first report that the code doesn't work with an X2 was in post #20 here. I think there might have been another thread at a similar time, but I can't find it.

Cheers, Alan.
 
Last edited:

julianE

Senior Member
#11
Thanks Alan. I have a stockpile of both 20X2 and 20M2 reason for 20X2 is that it can be a slave I2C to a raspberry pi. Which isn't that big a deal since now I program the picaxe remotely using Pi UART so I always have the serial connection to the picaxe. I'm working on a solar powered picaxe raspberry pi zero W so i can have everything outside and do all sort of data collecting. I'm using your snippet to check on my battery voltage and know how much time i have to use the Pi. I had the box outside for the first time today and the battery charges better than expected, I used your snippet to montor the battery every minute and in full sun the battery was being charged while also powering all the electronics. I can remotely shut off the Pi completely to substantially reduce the current draw. Plan is to have the Picaxe collecting data and storing in external EEPROM and when I want to download data, power up the Raspberry Pi. I'm sure I'll have many questions to the forum and I'm always grateful for all the help.

all the best.
 

AllyCat

Senior Member
#14
Hi Julian,

I don't want to hijack this thread, but I've been refreshing my memory of this code snippet which might be the one you used. Fortunately, the program doesn't use any SFR commands (which are implemented differently in X2s), but the ADCCONFIG command uses different flag positions between M2 and X2 devices. More seriously, it appears that the ADCCONFIG and DACSETUP commands are not supported at all by the 20X2 (only the 28 and 40 pin devices). :(

I don't recall what improvements I made for the "Updated" version in that thread, but another disappointment is that the listing is now plastered with PE6's "color" commands. I don't believe I would have posted it in that form, so is it a result of converting to the "new" forum software? And more to the point, is there a way to "recover" the raw PICaxe .BAS program without any manual editing (hippy) ? [ If there is an answer, it would probably be more appropriate to add it to that Snippets thread. ]

Cheers, Alan..
 

julianE

Senior Member
#15
Hi Julian,

I don't want to hijack this thread, but I've been refreshing my memory of this code snippet which might be the one you used.

Cheers, Alan..


here is the code snippet I've been using

Code:
#picaxe 20m2        ; Or any other M2
#no_data
#terminal 4800

symbol CALVDD10 = 41942        ; "Fractional" multiplier to calibrate Vdd in 10s of mV (nominally 41942)
main:
do
    sertxd(cr,lf,"Vdd= ")
    call ReadVdd10        ; Measure the PICaxe supply rail to a resolution of 10mV into w1
    call show2dp        ; Report the value. (Or use BINTOASCII w1,units,tenths,hundredths )
    sertxd(" Volts")
    pause 3000
loop

ReadVdd10:            ; Read the supply rail in hundredths of a volt into w1
    fvrsetup fvr1024        ; Select the 1 volt Fixed Voltage Reference
    dacsetup $80        ; Enable the DAC referenced to Vdd (NOT connected to output pin)
    daclevel 5        ; = Vdd * 5 / 32 , must be less than the FVR2048 reference (Vdd < 6v)
    adcconfig 3        ; Use the FVR as reference voltage for READADC (and READDAC)
    readdac10 w1        ; Read the DAC voltage (nominally Vdd * 5 / 32)
    w1 = w1 ** CALVDD10    ; Calibrate to 10 mV units
    return
show2dp:            ; Display the value in w1 with two decimal places
    b1 = w1 / 100         ; Integer part
    b2 = w1 // 100        ; Fractional part ( 0 - 99)
    b3 = b2 // 10        ; Hundredths
    b2 = b2 / 10        ; Tenths
    sertxd(#b1,".",#b2,#b3)    ; Show as a decimal value
    return
 

hippy

Technical Support
Staff member
#16
the listing is now plastered with PE6's "color" commands ... is there a way to "recover" the raw PICaxe .BAS program without any manual editing (hippy) ?
Just change the opening [code] tag to [code=rich] and it will magically fix itself.

I updated that for you in the thread linked to.
 

AllyCat

Senior Member
#17
Hi,

Thanks hippy. It proves I'm not yet a Power User of PE6 . ;)

@Julian: Ah yes, as in the title of the original Code Snippet, I think that code is probably suitable only for M2 chips.

However, if you need only 2 decimal digits of voltage resolution then post #2 in my other code snippet which uses only CALIBADC10 should be good enough and fully compatible with X2 PICaxes. [And pulls this thread back on topic.] :)

Cheers, Alan.
 

nbw

Senior Member
#18
Right, got it working now! Larger resistor voltage divider, and wrapped my head around the FVR concept. I'm going to take a look at AllyCat's "divider-free" approach as it won't kill me to learn a second thing this week.

Thanks all above :) ^^^^
 
Top