Skip to main content

Very simple Li-Ion battery charger


Always remember, that a fully charged 18650 Li-Ion battery has about 48000 Joules of stored energy. Wonder what that means ? It means, that you can melt 46g of copper with it. You don’t want to melt copper at home. Or on your bench. So don’t do anything stupid and read my legal disclaimer at the bottom of the page.


Lately there has been a lot of instances when I had to use batteries for powering all kind of devices and prototypes. This is largely do to the fact, that for some really low noise work it’s the only approach possible, and for other occasions it was just a very convenient way to break the ground loops. Naturally the “charging” question arose quite soon after. First I just used current limited lab power supply, but I quickly ran out of channels as I needed to also power other stuff on the bench. As this was happening during Christmas holidays, I started wondering what to do. Good luck with buying something reasonable during this time of year, so I decided to mock up something quickly.

The concept

As always, you start with something simple, something reasonable, like “I just want to charge these batteries”. And then you get in that rabbit hole vortex of “other functions that would be nice”. Everybody who designed anything in their life knows what I’m talking about here.  So the wish-list was born:

  • Charging and discharging functions
  • Selection of currents and voltages for both functions
  • Indication of current state
  • Ability to measure and indicate capacity
  • Ability to export logs to PC
  • Operate on 5V supply voltage
  • Minimum 4 channels

From this list it was evident, that some embedded MCU with a couple of transistor will just not cut it. Or it will need much more development time then I would be willing to spend on it. So I started to look for alternatives and stumbled upon LINX  MakerHub project for LabView. I was blown away right there and then by the implications it provided. Controlling embedded platform devices like Arduino and ChipKit directly from LabView opens a whole new world of possibilities! I really don’t know why there is so little buzz around this. Sure, it won’t change automation industry or anything like that. Because, well, let’s say that controlling a nuclear reactor (or even a boiler for that matter) with some 4$ Arduino board running on “very RTC” windows might not be the greatest idea out there. But for DIY purposes (and much more really) it’s really just wonderful!

The hardware

Project “brains” are running on Arduino Nano board. This puppy can be bought for 3.8$ (shipping included if you were wondering), so yeah. Doesn’t get cheaper then that. This board is based on ATmega328P, which has 8 analog inputs and 4 PWM outputs.

We have to measure charge current, voltage and control a charging device. That means 2 analog inputs and 1 PWM output per channel minimum. So this board just meets a theoretical minimum requirements for controlling a 4 channel charger.

Control circuit

Next, as the name of the project suggests, we need some simple charging circuit. Most of the professional  commercial battery chargers use 2 mosfets.

P-channel for charging, and N-channel for discharging. Also there should be reverse polarity protection diode. In case battery is connected in reverse, N-MOS build in diode will conduct and produce a lot of magic smoke. You definitely don’t want this. Also this protection diode should NOT be in a feedback circuit, as it is highly nonlinear device.

Actual Circuit

In our case the above circuit poses a couple of problems. First – two mosfets is already not so simple and second – we don’t have enough PWM channels to drive them. Sure, we could make some muxing circuit and select which mosfet to drive, but again – not a very simplistic approach. So let’s go with a bare-bone single mosfet solution.

Here is a complete circuit for one channel. Arduino digital output D2 controls a relay which, depending on whether we are charging or discharging the battery, connects it to ground or charger power supply Vs. D3 is a PWM output, which drives the mosfet. Gate drive circuit, consisting from 5.6kΩ resistor and 10uF capacitor, is smoothing pwm signal and slowing down the PID loop (100kΩ is just a pull-down). Arduino analog inputs A0 and A1 monitors battery voltage and current (using 0.47Ω sensing resistor) and 2.7kΩ resistors are there just for protection (22kΩ pull-down keeps A0 from floating when not connected). And that’s basically it. Doesn’t get any simpler then that.

There is just one problem though. Well, maybe a couple of them. First, there is no reverse polarity diode. No matter where you put it, it will always be in a feedback (current or voltage) loop.  Second, you have to manually reverse battery polarity when discharging.  That’s a price to pay for such a simple approach. But what’s a worse that can happen? Well, if you forget to change battery polarity – there will be -4V present on current sensing resistor and a current of 8.5A will flow through it. Hence the FUSE to ground in the schematics. And that’s it – you pop the fuse. Below is a complete schematic for all 4 channels.

Control firmware

First you have to upload LYNX firmware to your Arduino NANO board. If you have LabView already installed, then this a simple procedure using Firmware deployment wizard. And I would recommend this approach if you are new to Arduino devices.  After installing LINX add-on using VIPM, start LabView and go to Tools>>Makerhub>>LYNX>>LYNX Firmware Wizard and follow simple instructions. LabView student edition is free for 6 months evaluation. If you don’t want to download almost 2GB from hamster powered NI’s servers (it’s slooooow at the moment of writing this) then download LYNX firmware and upload it using Arduino IDE.  Just Open Arduino IDE, Click File>>Examples>>LINX>>LINX Arduino Nano Serial, Build and deploy.

After successful firmware deployment, connect Arduino to your PC and make sure that you have a USB-SERIAL device in your device manager. Actual device name may vary depending on what USB chip your particular board is using. What is important is COM port number (COM9 in example above). Remember it and that’s it, you are ready to go!

Charging software

Obviously it was written in LabView. That’s the only visual programing language that really works for today as far as I’m concerned. Sure, it has this tendency to make things that would be very simple in other text based languages somehow complicated. But then it makes a lot of others things, that would takes ages to write, a breeze! I love it. You can download compiled executable here. If you don’t have LabView installed, just download LabView run-time engine and you can run this executable just fine.

It’s a “one window” approach user interface (couldn’t be bothered for more).  Adjust section splitters for your screen size. On first run, enter program settings that fits your needs. Select COM port number from device manager. Supply voltage – enter your charging power supply voltage (Vs in schematics). Also you can manually adjust current coefficients. Basically it’s a number that you multiply by to get a current from voltage measurement. So for a 0.47Ω current sensing resistor it’s 1/0.47=2.127. You can latter calibrate current by adjusting this value to match an actual resistance.  Then there is a possibility to change Arduino voltage reference.

Read warning and make sure you understand what you are doing. If you are powering Arduino from USB and using default AVCC mode, measure actual voltage on +5V pin and enter that value in REF OVERRIDE. Hit save when you are done. This will create .ini file in your user directory to keep all these settings for the next time.

Now press CONNECT for a moment of truth. If stars did lined up correctly – you should see green Link led active and Loop rate indicating refresh rate. All the rest is pretty self explanatory I guess.

Quick program overview

Select function by pressing on CHARGE or DISCHARGE buttons, enter parameters and hit start.

Relay actuates and if you didn’t connected battery, status displays WAIT. When battery is connected – charging begins.

Charging starts in constant current mode and status displays CHARGE. Then, when a set voltage is reached, TOPPING begins in constant voltage mode. Graph displays actual voltage (yellow trace), current (blue trace)  and capacity (red trace) values versus time.

When a set cut-off current is reached – charging stops and READY status  is displayed. You can save this graph now by pressing SAVE button. It’s in .cvs format so you can easily import it to excel for future reference. Graph file also contains all parameters for current session.

DISCHARGE functions in a same manner. Press DISCHARGE function button, enter parameters and hit start.

Only major difference being a graph format. It’s battery voltage versus capacity now. Graph update rate is 1 second, so it actually has a time stamp also.

As can be seen by version number 0.9, it’s quite a mature revision that I’m not afraid to publish. What this means is, all really obvious bugs are gone and there is some minimal error handlers. Like for example if a battery is disconnected, cycle can be restarted from where you left. But I’m sure there are a lot of other things you can do to break it (or make a small fire) and I’m not planning on developing it any further. So use it at your own risk and don’t hold your breath for updates.

Some other considerations

I’m using fixed 5V 5A channel from my laboratory power supply to power this charger (hence the 5V initial requirement). Other options will depend on your particular current needs. I would suggest to use separate voltage regulators for each channel. That way you will not get any fluctuations from other channels when starting/stopping cycles (very important in CV mode, as controller is trying to hold voltage in mV range by adjusting current). Simple 7805 will do its job if 1A charging current is enough.

It should be, as this is almost 0.5C charging current for most 18650 cells. Also, as presented in above schematics,  using IRF540N and 0.47Ω Rsense, 1A is about max current possible. If you need more – decrease Rsense. Then for power supply use 7805 with external regulating transistor or even better – buy a cheap 5V impulse power supply.

Something like that (5V 10A) could be bought for 10$ (yep, shipping included) on a numerous china online markets. That’s actually less than 4×7805 and some good smoothing caps.  And finally here is my actual mockery.

Not bad for a couple hours of work. You don’t need this massive heat sink. For 1A operation from 5V supply there will be only 1.5W worse case dissipation per mosfet. I used it just as a base for everything. As can be seen further, I also used simple mosfets from my junk box (IRFP044N actually) so max current is only 0.8A. That’s why I recommend using logic level IRF540N. I also omitted relays (only simple jumpers) and fuses (I like to live dangerously) which is not recommended by any means.

So stay safe and happy tinkering!