Persistent Power UPS

Arduino-based High Capacity 12V UPS

Geoff Cohen

Issue 36, July 2020

This article includes additional downloadable resources.
Please log in to access.

Log in

Build this 12V uninterruptible power supply to keep your broadband and other important tech running during a blackout.


With broadband replacing fixed-line phones, keeping the power on during blackouts is essential, as the horrific bushfire season in Australia showed us recently. This UPS is designed to power your modem/WiFi router, providing essential phone and Internet service for several hours.

Impressively, it is able to supply up to 5A for over an hour, and can also supply high short-term peak currents to run devices such as a 12V compressor fridge.


Our 12V UPS is designed to go in series with the 12V power supply that powers the device you want to keep running during a blackout, such as a broadband router.

The UPS uses the newest LiPoFE4 lithium battery technology (they don’t catch on fire as Li-ion can), which is charged thanks to the onboard Boost module.

We use an Arduino Pro Mini running in a low power mode and with its power LED removed to conserve power, a colour OLED display, and solid-state MOSFET switches.

A custom-designed 3D printed enclosure rounds out the project.


Charger / Boost module

With a (nominal) 12V input to the UPS and the Boost Module set to 13.6V output, the Boost module powers the load and also charges the LiFePO4 battery. The boost module works with any input voltage between 10.5V and 13V. You can also power the UPS from 24V (or vehicle use at 14.2V) by replacing the 6A Boost module with a 6A Buck module (we use one of our UPS’s this way to power a 12V Car Compressor fridge when parked for a while).

The Boost module is isolated from the output and battery by MOSFET Q4 (refer to the schematic) acting as a very low loss pseudo-diode. We initially used a Schottky diode to isolate the battery from the input, but with over 500mV loss at 5A, it ran too hot to touch, and, as we had quite a few spare NDP6020 MOSFET’s, we modified our design to use one as a pseudo-diode. When checked, we measured a very small 54mV drop and only a 2°C increase in temperature at 5A. We even tested it at 10A for 30 seconds with no ill effects, although this is outside the continuous ratings for the Boost module - using a higher capacity boost module and a bigger battery (or two in parallel) leaves the way open for a higher current UPS version with minimal changes needed.

BUCK MODULE: A switching regulator with output voltage LOWER than its input

BOOST MODULE: A switching regulator with output voltage HIGHER than its input

Using an Arduino to control a UPS

Normally, an Arduino uses too much power for use in a UPS, but the Low Power Library by Rocketscream ( has some extremely low power sleep modes. With one simple modification, the sleep current of your Arduino drops from 3mA to 25μA.

As an example of how useful this is, when your UPS battery is nearly flat (approximately 1.5% capacity left in our 7AH battery). 3mA would exhaust a nearly flat battery in just one day, however, by just removing the Arduino Pro Mini’s power LED, the same, nearly flat, battery would last over 2 months (hopefully mains power won’t be out that long).

In our UPS, when it’s battery powered, if the battery is nearly flat and the voltage drops below 12V, the Arduino Pro Mini first isolates the battery (by turning off MOSFET Q1) then the Arduino switches to low-power SLEEP mode, consuming only 25μA, preventing the battery going completely flat for months. The Arduino code then periodically (once a second) wakes up for approximately 200 microseconds, checks to see if the input power is back on and resumes normal operation if it is. Using this simple method of operation only increases the average SLEEP power used by 0.02% percent.

We selected an Arduino Pro Mini for this project. Having no USB Port that would be drawing several mA, it is one of a few Arduinos that can run in very low power mode, drawing only 25µA in sleep mode. The only change needed is to remove the Arduino board’s power LED.

Arduino Pro Mini Low Power Details

We also encountered problems on some Arduino compatible boards with their internal voltage regulator dying when more than 12V was applied to the RAW input, so we used seven series-connected 1N914 diodes to drop the RAW voltage from 13.6V down to (approximately) 9V and have had no more problems. We didn’t use a Zener as they tend to not work at very low currents, in this case, 25μA in SLEEP mode.


MOSFET (Q1) needs a small heatsink because, when charging a very flat LiFePO4 battery, the internal diode in MOSFET Q1 forward conducts and produces some heat. Only a small heatsink is required. We used a couple of Raspberry Pi adhesive heatsinks, but any similar sized one will work, even a 12mm x 12mm piece of Aluminium screwed to Q1 would work.

Once the battery is moderately charged, this diode stops conducting, then the battery charging current is limited to 3A, using PWM (Pulse Width Modulation) control from Arduino output D3. Q2 acts as a level converter with resistors R5 and R6 limiting the gate voltage (VGSS) to Q1, as it’s rather low at only 8V. This method is also used with R19, R20, Q3, and Q4.

Measuring Voltage and Current

As the Arduino can't measure negative voltages, we used three different earth (or more accurately, 0V reference) points: the 12V and Boost GND input, battery GND, and output GND. Of course, at full current there is only 0.025x5 or 125mV difference between each one. The battery current is not measured directly, but calculated from the difference between input and output current. You can examine the code in function readAllAnalogInputs() (in file DIYODE-12V-UPS-Mk2.ino - near line 470). The voltages are measured via the 15:1 voltage dividers (R3/R4, R8/R9, R11/R12) into the Arduino board’s analog inputs, with some maths being performed to allow for the slight difference between the three ground reference points.

LiFePO4 Battery

We were pleased when we noticed Jaycar had added a 12V/7AH LiFePO4 battery to their products. LiFePO4 batteries are much safer, they don’t catch fire (unlike Li-ion), and having an internal BMS (Battery Management System) makes charging much simpler, with each internal cell receiving a balanced charge. LiFePO4 cells are also relatively forgiving and can be fully charged by any voltage between 3.4V and 4.2V per cell, although 3.4 - 3.6 are considered optimal. The BMS should also prevent damage to the LiFePO4 battery if it ever goes completely flat, but minimising that risk is always a better option.


Although we haven’t needed one yet, we have allocated space for a 40mm cooling fan that you can add if you are running high loads (eg. 6A) 24/7 or live in hot climates, such as the NT or FNQ.


A 0.96” I2C OLED display module is used to show exactly how the UPS is performing, displaying voltage and current for the input, battery and output.

Note: We are currently adding code to show the battery charge %, which should be available by the time we go to print.

The Build:

Parts Required:Jaycar
1 x Arduino Pro Mini or Compatible-
1 x FTDI- USB Serial 3.3V/5VXC4464
2 x P-Ch Power MOSFETZT2467
2 x 2N7000 N-Channel FETZT2400
1 x 40 Pin Socket Header StripHM3230
1 x 40 Pin Pin Header StripHM3212
1 x Solder-able Breadboard-
1 x DC-DC-Boost Converter (150W)-
1 x 12V/7AH LiFEePO4 BatterySB2210
1 x OLED Screen 128x64-
1 x Mini Heatsink*HH8584
1 x Insulated Female Spade - Red*PT4525
1 x Insulated Female Spade - Blue*PT4625
2 x M3 Countersunk Bolt or Small Self-tapping Screws (Over 15mm Long)*HP0626
8 x M3 Bolts or Small Self Tapping Screws (8-12mm length - not countersunk)*HP0403
1 x Heatshrink Tubing PackWH5520
4 x 50mΩ SMD Current Sense Resistors^Element 14: 3285931

* Quantity shown, may be sold in packs.

^ The current sense resistors are available from various online electronics retailers. Search for PCS2512DR0500ET.

Building the UPS is relatively straightforward; the LiFePO4 battery rests on the baseplate, and is held In place by both the 3D printed battery clip screws and two baseplate battery end support walls. The Boost module and protoboard (with Arduino Pro Mini, OLED display, and all other components) are screwed to this battery clip, with the two input and two output wires clamped to their strain relief mounts with small wire ties.

As there are so many different connectors that could be used, we left the inputs/outputs as flying leads, rather than mounting connectors on the 3D case that would only be the correct connectors in a very small percentage of cases. With flying leads, you just need to solder on an input and an output connector to suit your application. The UPS is simply plugged in between your original 12V source and the device being protected/powered by your UPS. Plus, if there is ever a problem with your UPS, merely unplug it and use your 12V device as originally setup, without any UPS protection.


The first thing to decide is, do you want to remove the Arduino board’s power LED for the best low power performance. Locating the power LED is really easy - just connect the Pro Mini to your FTDI-USB Serial board (don’t forget to plug your FTDI into your computer), and you will see the Arduino board’s power LED turn on. Just mark it with a Texta, turn everything off and unsolder the LED. It’s possible to unsolder it with a regular single soldering iron, but a SMD de-soldering tool makes it much easier. Commercial units around $200 are available, or you could consider making Geoff’s SMD Desoldering Tool that uses two cheap USB soldering irons ( We recommend a pair of stainless tweezers to make removing the SMD LED from the tips much easier too.

Except for the Boost module, the Arduino board, MOSFETs, and all the other electronic components are soldered to a protoboard.

As there are several versions of the Arduino Pro Mini, with slightly different pinouts for A4, A5, and A6 (some not even on a 0.1” grid), to fix this problem we’ve used flying leads to connect A4, A5, and A6, simply making our own 1 and 2 pin connectors from sections of 40-pin socket header strip (the images show you how we did this). The heatshrink tubing isn’t essential, but is good practice and will prevent any future problems with broken wires.

Note: Just remember that using proto-links on a working power supply may result in 'unfavourable' faults if one becomes loose or disconnected!

As the voltages across the 25mΩ current sense resistors (R1/R2 and R14/R15) are quite low (125mv @ 5Amps) we used heavy gauge 1mm tinned copper wire for all earth bus connections to maximise accuracy (we stripped the wire from a length of old 1mm Twin and Earth cable). This heavy wiring also acts as a heatsink, further reducing any heating of the SMD current sense resistors.

We could have used 0.025Ω (25mΩ) resistors for the current sense resistors, as they are 2W rated and the maximum power dissipation is estimated as 0.625W (625mW). However we chose to use two 50mΩ in parallel for better heat dissipation and lower temperature.

Before installing the Boost module, we connected it to our 12V source and adjusted the Boost modules output to exactly 13.6V. This provides around 97% capacity compared to charging at 14.6V, and is much less likely to hurt any 12V electronics on the output side.

Note: You will need to bend the leads on your 2N7000's to match the protoboards 0.1" grid.

Note: We incorrectly used BS170 FETs for Q2/Q4 on the photographed build. The Source and Drain pins are reversed compared to the correct 2N7000 FETs. Unfortunately, we didn't notice as we always check component pinouts with our TC1 Multi-Function Tester before soldering. Both types will work, just remember the pins are reversed.


Firstly, if not in your Arduino Library, you will need to install these libraries by selecting Sketch > Include Library > Add .ZIP Library:,

The code for this project can be downloaded from our website.

Note: If you have both an FTDI USB-Serial board and Arduino Pro Mini with the same polarity FTDI programming connectors don’t despair, just do what we did, cut two 6-way lengths from your 40-way socket strip and solder them together to make an adapter.

We originally tried using the Arduino with interrupt driven code, but it just couldn’t switch fast enough. Our 300MHz Tektronix CRO showed BIG switching spikes, so we finally settled on a design with the battery always connected.

Now, when the 12V input goes off, there is not the slightest sign of a switching spike. You can only tell the input 12V went off by looking at the display.

If you are really keen, you can even calibrate the voltage and current exactly by measuring it with an accurate meter and then adjusting vRefMultIn, vRefMultOut, vRefMultBat and aRefMultOut (In file DIYODE-12V-UPS-Mk2.ino, near line 121) so the values displayed on the UPS’s OLED display match your measured values. For extra accuracy, you can even display these values with 2 decimal point accuracy (at the cost of a smaller font) by changing the decimalPoints variable (around line 81) from 1 to 2. Just remember to change it back if you prefer the bigger fonts as we do. We used some existing sense resistors (of unknown accuracy), but using more accurate resistors (0.5% or 1%) makes extra calibration of current with aRefMultOut unnecessary.


We have put in a lot of explanatory comments, so you should have minimal problems modifying our code.


Initially, leave the battery (Brown & Blue wires) and output (Yellow & Green wires) unconnected, then supply between 10.5V and 13V to the input leads (Red & Black wires). You will see the OLED display turn on with three separate sections - the top section displays the output voltage and current, which should be close to 13.6V. The centre section shows the input voltage and current, and the lower section displaying the battery voltage and current. With only an input and no battery or output load, all currents should be close to zero. You can now connect the LiFePO4 battery, and unless the battery is fully charged, both input and battery will display some current flow, and if you disconnect the input power, the display will change to "On Battery".

With these tests completed, you can now reconnect the input power and also connect a load to the output e.g. NBN Modem. All three sections will display their respective voltage and current details, and the output will be powered with or without any input power. All that remains is to clip the top cover to the baseplate (sometimes a firm tap is needed to press the top cover's 20 recesses in place around the baseplate's 20 edge retaining clips.

Note: If the UPS is not needed for several months, remove the case top and unplug the battery to turn the UPS off.


We used PETG, but PLA would be OK for indoor use. We used support for the cover but it may be unnecessary, and it’s a real pain to clean out all the holes.

We’ve also provided two alignment clips that align the OLED display in the viewing window. If your Arduino has a male programming connector you may only be able to use the bigger alignment clip.

In our early designs, there wasn’t quite enough pressure to hold the top in place. We just warmed the top cover edges with a hot air gun, pressed inwards, and let it cool (for our build, the cover is so tight we need to push a spudger in quite hard to separate the lid and baseplate). We have modified the design to minimise this problem with some extra reinforcing, both inside the top cover, battery clip, and around the baseplate edges.

Assembly is easy! First, place the battery on the baseplate, put the battery clip in place and use two countersunk M3 (or self-tapping screws) to hold everything together. Then use four screws to hold the Boost module in place, after removing the four spacers on the Boost module (only if it has some, of course). Then screw the proto-board in place and clamp the input and output wires to their strain reliefs. We recommend looking carefully at the pictures we have provided, which are the best way to check the correct orientation of all parts.


If you are handy with circuit board design, you could make a PCB for the project, which would make it much quicker to build and reduce assembly errors.

A few other ideas include:

  • Modify the source code to show battery power/time/% left to run.
  • Run two (or more) batteries in parallel so your UPS runs longer under battery power.
  • Put in a bigger Boost (or Buck) module for higher power.
  • Add an ESP-01 for telemetry and send UPS status to phone/PC etc.
  • Experiment with higher output currents (10-15 Amps) by adding a heatsink for both NDP6020 MOSFETS and changing the current sense resistors.