Led Balancer

I have a lot of different leds in my drawer, some are new high efficiency devices, other are pretty old and despite a high amount of current (say 10 mA) are less brighter than the new ones (at 1 mA). I still have some leds from the 80-90s but their max brightness is incredibly low: practically unusable.
I sometimes need to put together leds having different colors and to get uniform brightness I need to test the leds together and experimentally find acceptable R values.
Similar problems with analog (4 pins) RGB leds.


The easier way to have the work done is to get 1 potentiometer x led, a multimeter, and a calculator.

I then decided to build a ‘Led Balancer’ device using materials I already have.

That’s why I went to this project, giving Arduino the task of reading current, voltage and proposing the correct E12 standard R value depending on supply voltage.
Too easy: that’s why I ended up adding pwm to set the brightness by up/down buttons.

The pcb hosts an arduino nano, a 20×4 characters lcd display (HD44780 compatible), some buttons, a connector for the leds and a few other components (including a voltage reference).

Leds can both be powered by DC (and current limited by multi-turn trimmers) or by arduino pwm generated signal.
AtMega ADC takes care of reading both voltage and current.
With pwm enabled, the adc reading requires some sw work, because U and I can only be read-in during the ‘active’ (led on) phase. The I value is then sw scaled by the pwm ratio.
This required tweaking the AtMega registers (details in source code pwmadc1ch.cpp).
The pwm out pin from arduino is buffered and inverted (BC327). The pwm pins have been chosen to leave Timer0 free (it is required for millis() and other time-keeping functions). Interrupts have been enabled, and at the correct transition (high to low) adc is started.
Adc sampling rate has been increased, minimum pwm duty cycle has been limited to 5%, that means a few more than 100 us, required by the Adc to have the sample done.
Adc alternatively reads voltage and current, and stores readings in 2 buffers.
See the oscilloscope sampled timings.
The pwm code is not directly portable to other Arduinos, it is AtMega328 specific, all the rest is standard architecture-independent C++.

Schematic diagram pdf

Sources (github)

* When driving leds with pwm, the voltage across the led is different from when the led is powered by static dc voltage.
* The pwm ratio (number passed to AnalogWrite()) is not exactly proportional to the effective duty cycle. But the difference is really small, see https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM

* I added a Precision Voltage Reference because I had one. This, along with 1% resistors, simplifies the project (no settings required). The overall error is small for the task of giving a 10% tolerance value for the resistor.

I have written 2 Arduino libraries:
ManyButtons: a single static class (thus a single instance) to handle any number of buttons; debounce and events (button pressed, released and long-pressed) handled.
IEC60003: computes the nearest E-series standard value. Can return both the standard value as a C float or a string in the form “12K”, “22u”, “R33”, “31K6”, … Can be used for R, L and C components.


Pcb has been printed by AllPcb, they do manufacture their pcbs and this means really short production times. As an example, time from file upload to pcbs on my desk has been 5 days. At the moment of writing the total cost (10x10cm, 5 pcs, dhl) is comparable to other services that ship with standard Post.