" for a, b, c, d, e, g, h, i in pins)
bom = [
("Arduino Uno (or Nano) + USB cable", "1", "Controller and serial logging"),
("ADS1115 16-bit ADC breakout", "3", "Addresses 0x48, 0x49, 0x4A"),
("LM317 (TO-220)", "12", "2 per channel: CC + CV"),
("Rcc 32.4 Ω 1% ¼ W", "6", "Sets 38.4 mA"),
("R1 120 Ω 1%", "6", "CV divider top"),
("R2 100 Ω multi-turn trimmer", "6", "Sets CV 1.50 / 1.80 V"),
("C1 10 µF 25 V", "6", "LM317 output stability"),
("F1 100 mA resettable PTC fuse", "6", "Per-channel protection"),
("K1 5 V SPST-NO reed relay (e.g. SIP reed)", "6", "Low-current dry switching"),
("K2 5 V SPDT signal relay, gold contacts", "6", "Charge / discharge select"),
("ULN2803 Darlington driver", "2", "Drives 12 relay coils (has flyback diodes)"),
("Q1 2N7000 N-MOSFET", "6", "Discharge sink pass device"),
("U3 MCP6002 dual rail-to-rail op-amp", "3", "One half per channel"),
("Rs 10 Ω 0.1% ¼ W", "6", "Sink current sense"),
("Rg 100 Ω", "6", "Gate resistor"),
("Rsh 1 Ω 0.1% ¼ W", "6", "Cell current shunt"),
("LM4040-2.5 + 2.2 kΩ, 7.87 kΩ 0.1%, 1.00 kΩ 0.1%", "1 set", "Shared Vref"),
("12 V 1 A DC adapter", "1", "Charger supply"),
("Small alligator / tab clips + silicone wire", "18", "3 per coupon (2 Zn joined, 1 Ti)"),
("Perfboard or 2 × half-size breadboards, terminal blocks", "—", ""),
]
bom_rows = "".join(f"
{a}
{b}
{c}
" for a, b, c in bom)
HTML = f"""Coupon Test Rig Wiring
Drawing ZM-RIG-01 · Rev A · for build plan phase 2E
Coupon Test Rig Wiring
Six independent channels that charge, discharge and log six coupon cells at 28 mA. Each channel has a constant-current charger with a voltage limit, a constant-current discharge load, and a 1 Ω shunt read by a 16-bit ADC. An Arduino switches the relays and streams readings to a PC.
System overview
{OV}
TitleSix-channel rig · block wiring
Sheet1 of 3
Supply12 V + USB 5 V
RevA
One channel (build 6)
K1 open = rest. K1 closed with K2 off = discharge through the sink. K1 closed with K2 on = charge. Because K2 is a changeover contact, the charger and the sink can never be connected at the same time.
{CH}
Shared reference (build 1)
{VR}
TitleChannel schematic · Vref
Sheet2 of 3
Current28 mA each way
RevA
Pin map, parts and setup
Channel
Coupon
K1 pin
K2 pin
ADS1115
P input
B input
CV limit
{pin_rows}
Parts list (rig)
Part
Qty
Note
{bom_rows}
Setup and calibration
Power the board with no coupons. Check Vref reads 0.282–0.286 V.
Per channel, with K1 off, close K2 by hand (or from the sketch) and measure U2 output. Turn R2 to 1.500 V or 1.800 V as the pin map says.
Put a 10 Ω resistor in place of the coupon. Charge mode: current should read about 28 mA, falling as the voltage limit is reached. Discharge mode: 28.4 mA.
Shunt offset: the sketch measures and subtracts it automatically during every rest (no current flows then). Check it with STATUS after the first hour: it should be under 0.1 mA.
Connect a coupon: red clip to the Ti tab (+), black clip to the joined zinc tabs (−). The sense wires to P/B are on the board side of the clips.
Sketch logic (per channel, every 1 s)
Implemented in coupon_rig/coupon_rig.ino; log it with coupon_rig/coupon_logger.py.
Rest 24 h: K1 off. Log the resting voltage.
Discharge: K1 on, K2 off. Stop at 0.900 V. Integrate mAh.
Charge: K1 on, K2 on. Constant current until the CV limit, then hold until I < 3.0 mA. Integrate mAh.
Rest 10 min between steps. Repeat for 10 cycles.
CSV over USB every 60 s: D,time_s,ch,state,cycle,V,mA,mAh,mWh. One S summary row per cycle (capacity, CE, average voltage) and E rows for events.
Fail-safes: any cell above 1.90 V or below 0.80 V, current during a rest, or no current 2 min into a step → K1 off and flag the channel.
Shunt offset auto-zeroes during rests; state is saved to EEPROM, so a reset resumes the test.
Notes
Self-discharge loading: while resting, the only load is the ADC input (well under 1 µA), so the 7-day rest test is not affected.
CV point: U2 holds node P at its set voltage, so the cell sees about 28 mV less until the current tapers. That is why the end-of-charge current check is at 3 mA, where the error is only 3 mV.
Relays: use reed or gold-contact signal relays. Large 10 A relay boards can give unreliable contact at 28 mA.
Hydrogen: coupons vent through the lid hole. Keep the rig in a ventilated spot, and the electronics above and away from the cups.
A commercial multi-channel battery analyzer can replace this whole rig if it supports custom voltage limits down to 0.9 V and currents of about 30 mA.