I made a quick hack to measure the battery for a project where I'm using the Espruino Pico running off of 3 AA batteries. It's an epaper display that updates once a day, so it will run off of the batteries for a very long time, but I had no idea how long. It turns out measuring the battery charge isn't too difficult. Here is how I implemented it.
I can't connect the battery directly to the ADC, since the three AA batteries start off at about 4.5 volts, much higher than the 3.3v that is the maximum the ADC can measure. The ADC will report 1.0 for 3.3v and 0.0 for 0v, with 12 bits of resolution, so I needed to move the battery voltage into that range. A voltage divider is a simple circuit that can do that. The simplest voltage divider is just two equally large resistors in series, where the point between them will be half the voltage across both of them. 4.5 / 2 = 2.25 which the ADC will report as 2.25 / 3.3 = 0.6818 is the highest battery measurement, while 0.5 is the lowest (3.3 / 2 / 3.3 = 0.5). This gives a range of 0.1818, which is about 8 bits of ADC resolution. But instead of using two identical resistors I used one of 560k and one of 270k:
o BAT_IN

[ ] 270k

o ADC (pin A5)

[ ] 560k

o GND
This puts the ADC at roughly 2/3 the battery voltage. Given that the max the ADC can measure is 3.3v then the maximum battery voltage that can be measured is 4.95v, but it's unlikely to go that high. I measured a fresh battery at 1.6v, so it might go as high as 4.8v, but that was under no load. 4.5v will give an ADC measurement of 0.9090 and 3.3v will give 0.666, so we have a range of 0.2424, a bit more than before but still about 8 bits of ADC resolution.
This setup drains about 6uA, so it does affect the battery life quite a bit given that the sleeping Espruino pulls 25uA. Higher resistor values could reduce the current drain.
The code for measuring the battery is very simple and not at all accurate. It assumes a linear discharge curve between 1.65v and 1.1v, which isn't correct for AA batteries. I'm planning to log the recorded values and plot them to produce a more accurate discharge curve, then I can make a better estimation function from that. But since this is a project that is designed to run for as long as possible on battery power it will take a few months to log this data.
// returns a number between 0 and 100
function getBattery(){
let avg = 0;
for(let i=0; i<10; i++){
avg += analogRead(A5)*30  20;
}
return Math.round(avg);
}
The code above makes 10 measurements and takes the average of them. I multiply out the value right away to delay a bit between measurements. This code does not clamp the values, so it might return values higher than 100% and if no battery is connected it will return 200.
Espruino is a JavaScript interpreter for lowpower Microcontrollers. This site is both a support community for Espruino and a place to share what you are working on.
I made a quick hack to measure the battery for a project where I'm using the Espruino Pico running off of 3 AA batteries. It's an epaper display that updates once a day, so it will run off of the batteries for a very long time, but I had no idea how long. It turns out measuring the battery charge isn't too difficult. Here is how I implemented it.
I can't connect the battery directly to the ADC, since the three AA batteries start off at about 4.5 volts, much higher than the 3.3v that is the maximum the ADC can measure. The ADC will report 1.0 for 3.3v and 0.0 for 0v, with 12 bits of resolution, so I needed to move the battery voltage into that range. A voltage divider is a simple circuit that can do that. The simplest voltage divider is just two equally large resistors in series, where the point between them will be half the voltage across both of them.
4.5 / 2 = 2.25
which the ADC will report as2.25 / 3.3 = 0.6818
is the highest battery measurement, while0.5
is the lowest (3.3 / 2 / 3.3 = 0.5
). This gives a range of 0.1818, which is about 8 bits of ADC resolution. But instead of using two identical resistors I used one of 560k and one of 270k:This puts the ADC at roughly 2/3 the battery voltage. Given that the max the ADC can measure is 3.3v then the maximum battery voltage that can be measured is 4.95v, but it's unlikely to go that high. I measured a fresh battery at 1.6v, so it might go as high as 4.8v, but that was under no load. 4.5v will give an ADC measurement of 0.9090 and 3.3v will give 0.666, so we have a range of 0.2424, a bit more than before but still about 8 bits of ADC resolution.
This setup drains about 6uA, so it does affect the battery life quite a bit given that the sleeping Espruino pulls 25uA. Higher resistor values could reduce the current drain.
The code for measuring the battery is very simple and not at all accurate. It assumes a linear discharge curve between 1.65v and 1.1v, which isn't correct for AA batteries. I'm planning to log the recorded values and plot them to produce a more accurate discharge curve, then I can make a better estimation function from that. But since this is a project that is designed to run for as long as possible on battery power it will take a few months to log this data.
The code above makes 10 measurements and takes the average of them. I multiply out the value right away to delay a bit between measurements. This code does not clamp the values, so it might return values higher than 100% and if no battery is connected it will return 200.