METEO LAB · PROJECT

Charger v1

An experimental four-channel smart charger based on Arduino Mega 2560. Full firmware description: pinout, control loop, charge profiles, protections.

Charger v1 experimental prototype
🔋

Overview

Charger v1 was created as an engineering test platform for developing charging algorithms, measuring battery parameters and testing different battery chemistries.

Each channel has separate battery voltage, current and temperature measurement. Control is based on PWM regulation of a buck module through its feedback path, with pre-charge, constant-current and constant-voltage stages. It includes profiles for Li-Ion, LiFePO4 and NiMH/NiCd cells.

The device uses two ST7920 displays, four INA219 measurement modules, NTC temperature sensors, LED indication, a buzzer and automatic brightness control.

4 channels Li-Ion LiFePO4 NiMH CC/CV Arduino Mega 2560

The project archive includes source code, a wiring diagram, a block diagram and a buck-module feedback injection diagram.

Experimental development.
Check the wiring, calibrate measurements and test every channel before connecting batteries.

1Single-channel hardware

The same set is repeated for each of the 4 channels.

BlockComponentPurpose
Step-down converterbuck LM2596 / XL4015 (with FB exposed)adjustable voltage source
SwitchMOSFET IRLZ44N / AO3400 (logic-level)breaks battery “+” — for OCV/-dV sensing and safety
V/I measurementINA219 (0.1 Ω shunt)battery voltage and charge current
TemperatureNTC 10k β=3950 + 10k divider to +5Vcell over-temperature protection
Holder18650 cradle / terminalsthe battery itself

2Control principle — FB injection

Current and voltage are regulated not by a “smart” buck controller, but by injecting a potential into the feedback (FB) input of an ordinary buck module:

PWM (Mega)→ RC filter 1kΩ + 100nF→ injection resistor 10kΩ→ buck FB

Raising the FB voltage makes the buck lower its output. The relationship is inverted: ↑PWM → ↓Vout. The inversion sign is handled in the PI controller (subtraction). PWM_MAX = 255 corresponds to minimum output voltage — the default safe state.

Assembly tuning: choose the injection resistor so that the PWM range 30…220 gives a buck output of 3.0…4.3 V (for an 18650) — this provides regulation headroom.

3Arduino Mega 2560 pinout

Charge channels — 4 lines per channel

ChannelPWM→FBMOSFET ENNTC (ADC)INA219 addr
Ch1D5 OC3AD32A00x40
Ch2D2 OC3BD33A10x41
Ch3D3 OC3CD34A20x44
Ch4D6 OC4AD35A30x45

INA219 addresses are set by the A0/A1 jumpers on the modules. MOSFET EN = HIGH → current flows into the battery.

ST7920 128×64 displays (software SPI)

On the ST7920 the signals have different names, and the U8g2 constructor order is (clock, data, cs, reset): E=SCLK, RW=MOSI, RS=CS.
DisplaySCK (E)MOSI (RW)CS (RS)RESETChannels
Display 0D48D47D46D8Ch1, Ch2
Display 1D52D51D53D7Ch3, Ch4

PSB = GND (SPI mode). Backlight BLA of both displays → D9 (PWM, through a transistor, not directly).

I²C bus · 100 kHz

SDA = D20   SCL = D21

Shared by 4× INA219 + VEML7700 (0x10).

Power

  • +5V rail ≥ 1 A — Mega + all modules
  • +6…12V — buck VIN input (≈1.5 A/channel)
  • Common ground for Mega / buck / batteries — required

UI and indication

FunctionPinNote
MODE buttonD30INPUT_PULLUP, button to GND
START buttonD31INPUT_PULLUP, button to GND
BuzzerD12moved from D9
ST7920 backlightD9analogWrite (PWM)
LED READY (green)D10→ 330Ω → LED → GND
LED FAULT (red)D11→ 330Ω → LED → GND

LED panel — 8 LEDs, port PA

D22–D29 = G G B B Y Y R R, each through 330Ω to GND. The pairs R2 R1 Y2 Y1 B2 B1 G2 G1 form the “SoC bar” of the selected channel, filled right-to-left (red → green).

PWM (Timer3/4) ADC (NTC) I²C SW SPI +5V / power

4PWM setup (fast PWM)

  • Timer3 (D2/D3/D5) and Timer4 (D6): Fast PWM 8-bit, non-inverting, prescaler /1 → ≈62.5 kHz.
  • Timer0 is left untouched — millis()/delay() keep working.
  • Values are written directly to the OCR3AL/BL/CL, OCR4AL registers via setPwmFast().
  • The high frequency gives ≈1 mV ripple after the RC filter.

5Charge state machine (per channel)

Lithium:

IDLE→CHECK→ PRECHARGE→CC→ CV→DONE

NiMH:

IDLE→CHECK→ NIMH_CC⇄TERM_CHECK→ DONE
StateWhat it does
IDLEwaits for START, MOSFET open
CHECKopens the switch, reads OCV, checks presence/reverse polarity, estimates starting SoC
PRECHARGEtrickle 10% current while V < v_precharge (deep-discharge recovery)
CCconstant current = setpoint (PI on current) up to V_max
CVconstant voltage V_max until current drops below i_term_pct
NIMH_CCCC only + -dV / dT/dt monitoring
TERM_CHECKonce a minute opens the switch, reads OCV for -dV detection
DONEcharge complete, capacity is computed
FAULTfault; no auto-reset — the operator presses START

PI controller

Shared for current and voltage. Integral anti-windup, ±1000 clamp, rate-limit of 5 PWM steps per iteration (protects against current spikes on entering CC).

Capacity estimate

From mAh and starting SoC (OCV table): Cap ≈ mAh·100/(100−SoC). If SoC>30% — rough (“~”), if ≥90% not computed.

6Chemistry profiles

Values per single cell (1S).

ParameterLi-IonLiFePO4NiMH
V_max (CV)4.20 V3.55 V1.55 V (limit)
V_precharge3.00 V2.50 V0.90 V
Precharge current10%10%20%
CV termination current5%7%— (no CV)
-dV——10 mV
dT/dt——1 °C/min
Timeout240 min240 min300 min
Reverse<100 mV<100 mV<100 mV

The charge current is selected by button from a list: 500 / 1000 mA (I_TARGET_LIST_MA).

7Protections

Checked on every state-machine step.

  • WDT 4 s — wdt_enable(WDTO_4S)
  • Over-voltage: V > V_max + 100 mV → F_OVERVOLT
  • Hard current cutoff: I > 1500 mA → F_OVERCURRENT
  • Temperature: T > 45 °C → F_TEMP_HIGH
  • Temperature: T < 0 °C → F_TEMP_LOW (3° hysteresis)
  • NTC open (ADC <20 or >1000) → F_NTC_OPEN
  • Reverse polarity (OCV < v_reverse) → F_REVERSE
  • Battery removed (V < 500 mV) → F_NO_BATTERY
  • Profile timeout → F_TIMEOUT
  • INA219 lost → F_INA_LOST
  • PWM stuck at a limit >5 s with large error → F_LOOP_STUCK
  • MOSFET open in all states except PRECHARGE/CC/CV/NIMH_CC

8Measurement

  • INA219: 32V/2A calibration (100 µA/bit), IIR EMA filter y += (x−y)/4 for V and I.
  • NTC → °C: β-equation, R_ntc = 10k·ADC/(1023−ADC), result in °C×10, extra smoothing (old·3+new)/4.
  • OCV: opens the MOSFET, 200 ms relaxation, reads VBUS. Does not re-close the switch — the state machine does that.

9Interface

Screens: Display 0 — channels 1/2 (top/bottom), Display 1 — channels 3/4. Per channel: name+chemistry+current, large V/A, state/T/accumulated mAh, progress bar.

MODE button (D30)

  • short — switch channel 1→2→3→4
  • long — enter/exit edit (in IDLE/DONE/FAULT)
  • in edit, short — next field (chemistry → current → exit)

START button (D31)

  • short — START/STOP the channel
  • in edit — change the field value

Sound: short beep — switch; beep — START/STOP; long — DONE; short — FAULT.

Auto-brightness: the VEML7700 is read once per second; the backlight smoothly ramps to a target based on ambient light (in the dark — minimum 20/255, in room light — maximum).

10Assembly notes

  1. The MOSFET must be logic-level (Vgs(th) < 3 V), otherwise it won’t turn on from 5 V.
  2. Tune the injection resistor: PWM 30…220 → buck output 3.0…4.3 V (for an 18650) — regulation headroom.
  3. First-run check over Serial (115200): 4× INA[x] OK + VEML OK.
  4. At PWM=255 the buck output is ≤ 3 V, at PWM=0 — maximum (~4.3–4.5 V).
  5. Display PSB to GND, common ground is mandatory.
← Back to METEO Lab