12v/2W LED control DIGITAL
Hardware design:See also the analog page as reference. The digital implementation is done by using a CPU. I use the A-Star 328PB Micro which is very similar to the Arduino Nano (which can also be used). To measure the ambient light intensity an LDR is connected to an ADC input. Furhter we need to control the led intensity (PWM) and the on-time duration. For that we add two variable resistors and measure the value by two ADC inptut. The thing left is to measure the on-time. Lets do crazy and just add an RTC module.
Further a PWM output of the CPU is used to control the same Power Driver (darlington) as described on the analog implementation.
M1:
Supply module to convert the mains supply to a 12V DC supply. Based on the requirements 5W would be enough. The selected module is a Hi-Link 5M12 (5W/12V) version.
M2:
The CPU. In this case the A-star 328PB is used, version is 8MHz/3.3V. An arduino Nano would also do. This module has an on-board power regulator which converts the VBat input supply to 3V3 which is also available on the VCC pin. The VCC pin supplies the RTC module and resistors to make sure the read values do not exceed the supply of the CPU.
M3:
The RTC module contains teh DS3231 real time clock and an EEPROM, which is not used in this application.
There are serveral RTC modules on the (Chinese) market. This is the observation:
RTC/EEPROM module DS1307 - Do not use, it is inaccurate by several seconds per day (wrong crystal used - Cload fails).
RTC/EEPROM module DS3231 - Perfect to use, accurate.
Power driver:
The CPU cannot direclty control the LED. The BD139 can but it requires a base current of 1/10th of the collector current, collector current = 2W/12V=167mA, thus Ib=17mA to reach saturation. This is hard for the CPU in PWM fast switching mode, but more important, the transistor does not get fast enough out of saturation, thus the LED is always on. Therefor T1 is added, this highly reduces the current delivered by the CPU. The total hFE is 100*40=4000, thus Ib is less than 1mA. Further it reduces how hard the BD139 goes into saturation and the base charge can discharge over T1 switching off T2. Transistor T1/T2 are put into a darlington configuration. The led 'module' X1 is turned on/off by the PWM signal on the basis of this darlington. You can also use a MOSFET (better solution), but I did not have those available (AO3400)
Test:
This schematic is implemented and tested. Benefit of this implementation related to the analog implementation: Using a CPU gives flexibility, more conditions can be added easily. An example: Assume the LED should always be off after midnight till 4.00AM, or, When the on-time potentiometer is at max position, the LED should always be on.
Cost:
For an overview of the cost comparason Analog/Digital, see the cost comparison page.
Schematic:

Software:
The CPU can be programmed using a Pololu USB ABR programmer (v2.1 Pololu 3172).
For software development the Arduino IDE is used, which directly programs the device using above mentioned programmer.
For details about the CPU or programmer, please see the internet, or this document:
DOWNLOAD: Document in PDF format
Software design:
The RTC is controlled via the RTClib library. The RTC is programmed to generate a 1Hz pulse on the SQ output, this generates an interrupt in the CPU. Some items will run on this interrupt, this is of course a design choice, it can be done in many ways, also without this interrupt.
Since we have more flexibility the spec is enhanced by the requirement to use the 'on-time' potentiometer to be able to turn the led on, independent from any other functionality, thus 'overruled on'. The user interface is designed as shown here:
1) DIM potentiometer, indicating 0% light to 100% light.
2) TIME potentiometer, on-time can be set from 0 hours to roughly 6 hours, rightmost position is unconditional always on.

The LDR input level is converted to a boolean on/off and that signal is delayed to detect the rising edge, again, this can be done in many ways, this is just one of them. Further we use the 1Hz interrupt to check if the LED should go on or off.

First the 'overrule' functionality is implemented, since that should work independent of anything else, This is the DIM function and the Always On function. After that the timed on is implemented. Here we make use of the RTC. Using the RTClib it is easy to calculate the time where the LED should go off. A caveat is the + operator to add time, this uses unfortunately signed chars in the implementation, meaning adding 240 minues would result in adding a negative value (240 is larger than 127 and thus negative signed char), I fell into this caveat, did not expect this limitation. But there is a workaround.
Another detail is the TIME potentiometer implementation:
I first read the ADC converted value for each user interface indicated mark, thus at 1 hour, at 2 hours, etc. Those values should result in exactly that amount of time. The potentiometer readings for values inbetween whole hours are interpolated.
Thus given two points: (R1, t1) and (R2, t2) where Rx is the read potentiometer value, the the interpolated t(R) value is:
t(R) = t1 + (R - R1) * (t2 - t1) / (R2 - R1) In software this is:
//-------------------------------------------------------------------------------------------------
// Converts read resistor value to a time using fixed values for marked positions + interpolation
// Measured values:
// Position Reading Time[min]
// 0 0 0
// 1 130 60
// 2 308 120
// 3 508 180
// 4 713 240
// 5 889 300
// 6 1023 360
//-------------------------------------------------------------------------------------------------
uint16_t calculateTime(uint16_t Rin) {
uint16_t t;
if ( Rin < 130) { t = (uint16_t)( Rin * 60/130); }
if ((Rin >=130) && (Rin < 308)) { t = (uint16_t)((Rin - 130) * 60/178 + 60); }
if ((Rin >=308) && (Rin < 508)) { t = (uint16_t)((Rin - 308) * 60/200 + 120); }
if ((Rin >=508) && (Rin < 713)) { t = (uint16_t)((Rin - 508) * 60/205 + 180); }
if ((Rin >=713) && (Rin < 889)) { t = (uint16_t)((Rin - 713) * 60/176 + 240); }
if ((Rin >=889) && (Rin < 1024)) { t = (uint16_t)((Rin - 889) * 60/134 + 300); }
return t;
}
DOWNLOAD: The Arduino sketch sources in ZIP format
Case design:
The case is created by using the box creation software, see Box Tool.
The generated svg file is fed into xTool Studio and engraving is added as well as holes for cables, LDR and potmeters.
The scale engraving is created by inkscape, saved as PNG and dropped into xTool Studio. PNG is used to keep the thickness of the lines. The case is designed for 3 mm plywood.
DOWNLOAD: The xTool Studio design file
Result:
| The different modules are soldered and wired on a PCB. The user potentiometers are soldered on another PCB which is glued at the backside of the front plate. The LDR is glued in the hole in the top of the case. The "Box Tool" software has the feature to define a width/offset to take into account for the interconnections, this should be roughly half of the laser beam width. I use the xTool S1 machine, laser beam is 0.2 mm. For the cut-margin I use the value 0.08 mm. As a result the interconnections fit nicely. The sides and top of the case is glued, and this fits nicely on the bottom (not glued, no screws, just fits). The knows are printed on a 3D printer. The knobs are designed in Fusion 360 (Autodesk) software. |
![]() |
![]() |
![]() |


