Intelligent Charger for 9V NiMH Rechargeable Batteries

About: Analog engineer

I looked for smart charger chat can charge 9V NiMH battery in couple of hours and didn't found one. Moreover all chargers I found was really "dumb". Charging current unknown and no function to terminate charging after battery fully charged. Problem with such chargers that they can overcharge battery and significantly reduce lifespan.So I decided to create "smart" charger using Arduino.

First version I intend to keep simple, so it allows basic things like charging with constant current, automatic charging termination after battery fully charged, trickle charge, measurement of charge transferred to battery.

In next version I will add couple of additional useful features like discharge, capacity measurement and cycling.

Warning: Charging battery with high current may cause battery explosion or fire. Please don't leave charger unattended. Also please don't try to charge battery don't intended to be charged as Alkaline. This charger tested only with NiMH batteries (and still you are using it at your own risk and I am absolutely have no any responsibility if any damage caused because of bugs in desigh or code). Chagrin of other types of batteries will require code modification.

Step 1: Parts List

You will need following parts:

Arduino UNO

SparkFun I2C DAC Breakout - MCP4725LM317

Linear Regulator with Adjustable Output

LM358 opamp

Resistor 6.8k ohm x2

Resistor 3.3k ohm

Resistor 5.1k ohm

Resistor 20k ohm

Resistor 1k ohm

Resistor 10 ohm

Capacitor 47uF

RelaySparkFun Breadboard Power Supply 5V/3.3V


Power supply 17V

Step 2: Theory

Some useful facts to remember that will help to understand needed parameters of charger.
C - current equal to nominal capacity of battery

When charged at the C rate single cell voltage may reach 1.6V. This voltage may be higher for old batteries.

Nominal voltage of single cell is 1.2V, but fully charged cell has an open-circuit voltage up to 1.5 volt.

Trickle charge rate of less than 0.025 C (C/40) is recommended after battery fully charged.

It is generally two options to charge NiMH battery:

1. Fast charging. Charging current 0.5C-1C. Charge state must be monitored and terminated by dV/dt (voltage change rate) or dT/dt (temperature change rate)

2. Slow charging. Charging current 0.1C. Charging time 14-16 hours. Charge termination by timer. dT/dt charge termination impossible for low currents. dV/dt termination may be not reliable for currents below 0.5C according to literature.

Step 3: Basic Parameters of Charging Circuit

9V battery usually has 7 serially connected sells, but in some cases it may have 6 or 8 cell.

Voltage regulator should be able to provide charging voltage at least up to 8*1.6=12.8V. Dropout voltage of LM317 regulator up to 2V, so supply voltage need to be ~15V (this not takin to account voltage drop on current sensing resistor)
For maximum charging current of 200mA and current sensing resistor 10 Ohm additional drop on current sensing resistor is 2V, so 17V supply voltage needed.

Fully discharged cell may have very low, even negative voltage. Minimum voltage of regulator ideally should be 0, but using LM317 it may be as low as 1.2V.

Step 4: Circuit

The basic idea is to measure charging current and adjust voltage of regulator until desired current reached. Current measured by measuring voltage drop on current sensing resistor R5. I=V/R

SparkFun I2C DAC Breakout - MCP4725 - 12 bit digital to analog converter used to control voltage. Output voltage cam be configured via I2C between 0 and 5V.

Because we need to be able to adjust voltage in wider range, from 0 to 15V operational amplifier LM358 used to amplify output voltage of DAC. Amplification of operational amplifier set by resistors R4 and R3. Gain=1+R4/R3=1+6800/3300=3.06 so output voltage of operational amplifier approximately 0 to 15V

Maximum output current of LM358 is 50mA, so LM317 adjustable voltage regulator used to control higher current. Output of operational amplifier connected to ADJ terminal of LM317. LM317 will maintain 1.2V between ADJ and OUT terminals, so actual voltage on battery can be configured between 1.2 and 16.2V.

LM317 need minimum 3.5mA current to maintain regulation. So 1kOhm resistor R6 used to ensure regulation if battery not connected.

Capacitor C1 used to filter output voltage and improve stability of LM317.

Voltage measured at two different points.

1. Resistor R5 connected to pin A2 of Arduino. Voltage on resistor measured and than charging current calculated as Icharging=V/R

2. Voltage on battery can be up to 16.2V, so resistive divider R1,R2 used to bring voltage below 5V, allowed by Arduino. Output of divider connected to pin A0 of arduino. For R1=5.1k Ohm and R2=20kOhm Vout=Vin/(20000+5100)*5100=0.2 So battery voltage divided by 5.

Step 5: Relay

Relay used to disconnect battery from charging circuit. You can see on photo relay I used, but generally any relay with 5V control can be used. It is more safe to connected battery to normally open contacts of relay.

Step 6: LCD

I used YwRobot I2C SERIAL LCD 1602 MODULE to display status of charger, but any other I2C controlled LCD module can be used.

It seems like YwRobot LCD module not supported by standard LiquidCrystal_I2C library, so I used New LiquidCrystal library

If you are using different LCD module you will need to change this line:

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); in charger.ino file

Step 7: Power

To power Digital to analog converter and LCD I used SparkFun Breadboard Power Supply 5V/3.3V. It is probably will be ok to use 5V from Arduino board.

You also will need to supply 17V to charging circuit. If you don't have power supply, you can use adjustable DC/DC converter like this

Step 8: Functionality

I don't wanted a lot of wires, so there are no buttons to configure charging. Chagrin current configured only in code. You need to set desired charging current in charger.ino

float target_current_mA=30; //Charging current mA

float battery_nominal_capacity_mA=170; //Nominal capacity of battery mA

float max_time_for_trickle_charge=6; //Maximum trickle charge time in minutes

target_current_mA - constant charging current
max_time_for_trickle_charge - maximum number of minutes for trickle charging, can be set up to 600 (10h) battery_nominal_capacity_mA - battery capacity used to calculate trickle current

Generally charging current can be up to nominal capacity. For battery with nominal capacity of 170mAh maximum charging current is 170mA. Minimum charging current usually C/10 - 17mA for 170mAh battery.

After power is up charger will check if battery connected. If battery connected battery will be charged with configured constant current until fully charged. Charging terminated by detecting negative dV/dt during 5 minutes.

After charging completed charger will switch to trickle charging with current C/40. Charger will disconnect itself from battery after maximum trickle charging time elapsed.

Step 9: Arduino Sketch

Step 10: Additional Information About NiMH Batteries





    • Trash to Treasure

      Trash to Treasure
    • Epilog X Contest

      Epilog X Contest
    • Weaving Challenge

      Weaving Challenge

    12 Discussions


    Question 3 months ago on Step 9

    Hello Alexander,

    I really like your project and I want to build it, but I have struggled on compiling the code:
    All libraries are installed, but still, have some compilation issues, any help will be appreciated:

    calculations:16:1: error: 'mytime' does not name a type
    mytime mills2time(unsigned long int time_mills){
    lcd:67:30: error: 'mytime' was not declared in this scope
    String construct_time_string(mytime timeinfo){
    C:\Users\Astrall\Documents\Arduino\charger\lcd.ino: In function 'String construct_time_string(mytime)':
    lcd:67:45: error: 'String construct_time_string(mytime)' redeclared as different kind of symbol
    String construct_time_string(mytime timeinfo){
    C:\Users\Astrall\Documents\Arduino\charger\lcd.ino:67:8: note: previous declaration 'String construct_time_string'
    String construct_time_string(mytime timeinfo){
    C:\Users\Astrall\Documents\Arduino\charger\main.ino: In function 'void loop()':
    main:186:84: error: no match for call to '(String) (mytime&)'
    msg =String(M2S(msg_completed)+M2S(msg_space)+construct_time_string(elapsed_time));
    Using library Wire at version 1.0 in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire
    Using library Newliquidcrystal_1.3.5 in folder: C:\Users\Astrall\Documents\Arduino\libraries\Newliquidcrystal_1.3.5 (legacy)
    Using library Time-master at version 1.5 in folder: C:\Users\Astrall\Documents\Arduino\libraries\Time-master
    Using library TimerOne-master at version 1.1 in folder: C:\Users\Astrall\Documents\Arduino\libraries\TimerOne-master
    Using library elapsedMillis-master at version 1.0.4 in folder: C:\Users\Astrall\Documents\Arduino\libraries\elapsedMillis-master
    exit status 1
    'mytime' does not name a type

    Screenshot - 6.12.2018 г. , 11_29_23.pngScreenshot - 6.12.2018 г. , 11_29_50.png

    1 year ago

    can i use dac0800 instead of dac mcp4725?????

    1 reply

    2 years ago

    Can you write what condenser you use? because I can't find or you doesen't write. Thanks.

    3 replies

    Reply 2 years ago

    Actually, you can see on schematic capacitor was 47uF


    Reply 2 years ago

    But on photo i see that you use 3 capacitor, or I'm not right?


    Reply 2 years ago

    You are right. The other two is 10uF in parallel with R5(current sense) and 0.1uF in parallel with R1, i think. But i don't think you really need them.


    2 years ago

    Do i have to find the code here? Although I searched the page in detail, I could not find a link.

    Sorry, but i'm new to this kind of source. Thx

    3 replies

    Reply 2 years ago

    I want to build it when i have the time... I'll give you a review of my experiences if you want.

    Originally i wanted to built a tester... but i hope to integrate in your schematic :)


    2 years ago

    Good tips!