I’ve received my Photons today and started a new project. A LiPo battery is connected to a Photon and and also a charging circuit. It expects 5V which I am supplying with a QI Charging receiver. That’s all great and works - I can run the photon off the lipo and also charge the lipo when the qi receiver is on the qi transmitter for charging.
To detect that the system is in charging mode, I put the 5V qi receiver input to the lipo charger through a 10K resistor and then connected it to D0, where I can simply check digitalRead(D0) for charging detection.
I am currently “breathing” - turning slowly on and off a neopixel ring to signal the charging. I know this is not exactly power-saving, so probably charging slower, but that’s OK.
I would like to detect the charge level of the LiPo to let the LEDs breathe faster or slower. Does anyone have a recommendation on how to do that? I assume that I can take the input voltage, connect to a resistor and then read the analog in value. But is there maybe an internal function already that let’s me check the input voltage on VIN?
I suggest you do some research on battery fuel gauges since the voltage level of the battery does not give the full story for LiPo’s. Maxim and TI and several others make parts specifically for this application.
I second @bko’s advice. The key search term is “battery fuel gauge”.
You may have to think beyond simply bolting a fuel gauge onto the side of an existing charging solution.
As @bko and @AndyW suggest, a fuel gauge is the way to go, it will give you an actual "level of charge".
If like me you want something super quick just to give a Low Battery alarm you could use a voltage divider and read the voltage using a analog input. I wanted to measure the voltage of a 3S lipo pack and make sure its above 10.5v before running the motors. Have a read of this post
Its probably worth having a read to see how the resistors work to reduce the voltage to a safe level before connecting to an input, as your 10k resistor wont reduce the voltage but will just limit the current. although the pins on the photon are 5v tolerant there are some rules to prevent damage. [1] FT = 5.0V tolerant pins. All pins except A3 and DAC are 5V tolerant (when not in analog mode). If used as a 5V input the pull-up/pull-down resistor must be disabled.
And a handy site for calculating resistor values for the divider.. here
Thx all for the replies. The battery level does not need to be very accurate, so I decided to go with what I roughly understand: a voltage divider.
rigth now I am using two 10k resistors across VIN/GND and read the input on A0. I am currently sending out events with the raw A0 readings and will later map the upper/lower levels to 0/100 using the map function.
So when I measure the voltage with a multimeter across the VIN/GND pins of the lipo, I get around 3.7+ for a fully charged one and it will go down to about 3.4 or less. Then the lipo circuit will shut off automatically to not damage the battery.
When I read the A0 I got values from around 2370 for fully charged to about 2100 for almost empty. I simply convert that:
uint8_t batteryLevel()
{
int raw = analogRead(A0);
int lower = 2100; //raw A0 voltage reading
int upper = 2370; //raw A0 voltage reading
uint8_t percent = map(raw, lower, upper, 0, 100);
return percent;
}
I will run a few more cycles and adapt the lower/upper accordingly.
Many thx for the links to maxim fuel gauges, too. I am using a single cell lipo battert, 400maH. Even with a 12led neopixel that turns off and on in a 1s inerval, constant connection of the photon and events every minute or so it runs > 1 hour.
That looks good. But more than one way to skin a cat.
uint8_t percent = constrain(map(raw, lower, upper, 0, 100), 0, 100);
They should both do the trick. One with less lines of code, the other easier to read.
Thanks, Jack
Yeah sure we can whittle it down to one line for the ultimate in unreadability I would also prefer to constrain my inputs than the outputs to prevent wrapping. You also have to now be really careful in how all of these functions play with each other as far as input and output types go. More explicitly set types will be easier to debug if you have unexpected results down the road.
I think you meant to say signed here. And unless you are testing for values below or above 0 percent, it won't matter much. If you go to the extreme to test for errors post function call, then I believe this particular function is implemented incorrectly. You should trap your errors in the called function and keep the user from having to post process the output. If those errors were very specific though, like -1 for a battery value out of range low, or -2 for a battery value out of range high, then that would be more appropriate and a good use of a signed return value. You can code it however your heart pleases you but that's my 2 cents.
We could, and someone probably will (and we are actually in progress of...), write a book about all of the different ways we could implement this batteryLevel() function
That's great. Is this book just for LiPo, or other types of batteries ?
Will it cover how to charge/maintain the LiPo (3.8V vs 4.2V) ?
I may have misunderstood you. I thought you were writing a book, but looking back, I can see how I may have been confused on that point.
I guess I/we really don't know how the OP intends to use the result of this function. I would generally use a "if less than", or "if greater than", but that's just my thoughts. Maybe they just want to display the percentage. We don't know.
True, and if not unsigned... then for those who know what's correct it's implied you should code it as signed... but better to explicitly say signed so those who are learning by reading our posts can learn
I am! We are!! I'm trying to be subtle in saying we are kind of going on and on about this and are off topic now.
I’m currently using an INA3221 board in my project. It provides 3 inputs and can monitor both current and voltage. I’m using it to measure the LIPO, solar panel and the load (in this case a Moteino w/several sensors) in an outdoor weather unit. Before that I used a INA219 board with only one input. Easy to code and very accurate.