Top of the box with a ruler for scale.

I just finished designing and building a (12.5″)x(12.5″)x(6″) ultraviolet light box with a pic16f54 microcontroller programmed as a timer for the exposure. It was made mostly to be a UV light source for exposing photosensitive film used as an etch-resist in the process of making printed circuit boards. It can also be used as a weapon against vampires.

Close-up of the controller board (upside down!)

The red LED indicates power is connected to the microcontroller (controlled by the small switch in the corner or just by unplugging the wall-wart). Pressing the round black button adds 30 seconds two minutes to the timer, which is indicated in binary on with the 8 orange LEDs; it is limited to 255 seconds (4 minutes, 15 seconds) and suffers overrun if you press the button enough times 16 minutes and doesn’t loop back to zero. Power is applied to the ultraviolet LEDS whenever the timer is greater than zero, which can be indicated by (a) the yellow LED indicating the UV lights are on, (b) the green led blinking once per second as the timer counts down, or (c) the bottom of the box emitting a faint blue glow. The assembly code I spent an afternoon writing can be found at the bottom of this post, if you are curious (My first real ASM program! It was actually kinda fun!).

Inside of the light box; still not sure what the cat likes about this place, but he sure likes trying to get in there.

Measurements indicated that the ultraviolet LEDs are using 29.1[mA] each, so the box should be outputting a total luminous intensity of \([16 * (1.375 * 80[mcd])]= 1.76[cd]\) at wavelengths between 350[nm]-420[nm] (peak @~380[nm]). The photoresist film that I use has an exposure sensitivity between 315[nm]-400[nm], with a peak response at 355[nm]-380[nm], which fits nicely with the LED selection.

The UV LED array has a square spacing of 2.5″, meaning the center of four adjacent LEDs is \({2.5[in] * sqrt{2} over 2} = 1.7677[in]\) away from any given led. Using the Radiation Diagram from the datasheet, the minimum surface distance from the tip of the LEDs at which the light cone would be at 25% intensity at these centers is then \({{tan (20,^{circ})} over 1.7677[in]} = 4.8569[in]\). I interpret this as the minimum distance an object needs to be from the UV LEDs in order for the light to be relatively uniform across the whole surface. Beyond this distance, it should become even more uniform; fortunately, my two glass plates, a standard 1/16″ copper clad board, photoresist film, and artwork transparencies add up just under 3/8″, so all is well for my application. The largest copper clad board I ever plan to use is 8″x10″, so my 2.5″ spacing works to keep the UV light at a decent intensity on the edges. UPDATE: Unfortunately, this is not the case, as tests have shown that the board needs to be at least another 1/2 inch from the LEDs. This may have something to do with where you measure from, exactly, but there are visibly contrasting regions visible on a white sheet of paper. The solution I have in mind will be to simply extend the bottom of the box.

Just showing off the light emission.
  1. ; Timer for UV Light Box Control
  2. ; Initially off. Waits for input to set length of ON time, waits for lack of input, then starts. PORTB acts as indicator of number of 2xminutes to set timer.
  3. ; PIC16F54 @ 3.579545 MHz
  4. ; Drew Jaworski 2012
  5. include

  7. UDATA
  8. ; delay counter vars
  9. dc1 res 1
  10. dc2 res 1
  11. dc3 res 1
  12. ptm res 1 ; 120 second run timer
  14. init
  15. movlw b'11110010' ;RA0 is UV control output, RA1 is timer increment button input (active low), RA2 is clock indicator LED output, RA3 is UV on indicator
  16. tris PORTA
  17. movlw 0x00 ;RB7-RB0 are time display outputs
  18. tris PORTB
  19. start
  20. movlw 0x00 ;set all outputs OFF initially
  21. movwf PORTA
  22. movlw 0x00 ;initial time to display
  23. movwf PORTB
  24. movlw 0x78 ; initial 2xminute run timer setting (120)
  25. movwf ptm
  26. wait_start
  27. btfsc PORTA,b'001' ;check button status
  28. goto wait_start ;skip back if button was not pressed
  29. wait_input
  30. ;delay 0.25 seconds
  31. movlw 0xC7
  32. movwf dc1
  33. movlw 0xAF
  34. movwf dc2
  35. Delay_2
  36. decfsz dc1, f
  37. goto $+2
  38. decfsz dc2, f
  39. goto Delay_2
  40. ;end delay
  41. btfsc PORTA,b'001' ;check button status
  42. goto begin_run_timer;start if button was not pressed
  43. btfsc PORTB,b'000'
  44. goto $+3
  45. bsf PORTB,b'000'
  46. goto wait_input
  47. btfsc PORTB,b'001'
  48. goto $+3
  49. bsf PORTB,b'001'
  50. goto wait_input
  51. btfsc PORTB,b'010'
  52. goto $+3
  53. bsf PORTB,b'010'
  54. goto wait_input
  55. btfsc PORTB,b'011'
  56. goto $+3
  57. bsf PORTB,b'011'
  58. goto wait_input
  59. btfsc PORTB,b'100'
  60. goto $+3
  61. bsf PORTB,b'100'
  62. goto wait_input
  63. btfsc PORTB,b'101'
  64. goto $+3
  65. bsf PORTB,b'101'
  66. goto wait_input
  67. btfsc PORTB,b'110'
  68. goto $+3
  69. bsf PORTB,b'110'
  70. goto wait_input
  71. btfsc PORTB,b'111'
  72. goto wait_input
  73. bsf PORTB,b'111'
  74. goto wait_input
  75. begin_run_timer
  76. bsf PORTA,b'000'
  77. bsf PORTA,b'011'
  78. run_timer
  79. ;delay 0.5 seconds
  80. movlw 0xAF
  81. movwf dc1
  82. movlw 0xFA
  83. movwf dc2
  84. movlw 0x01
  85. movwf dc3
  86. Delay_0
  87. decfsz dc1, f
  88. goto $+2
  89. decfsz dc2, f
  90. goto $+2
  91. decfsz dc3, f
  92. goto Delay_0
  93. goto $+1
  94. goto $+1
  95. nop
  96. ;end delay
  97. bsf PORTA,b'010' ;set led
  98. ;delay 0.5 seconds
  99. movlw 0xAF
  100. movwf dc1
  101. movlw 0xFA
  102. movwf dc2
  103. movlw 0x01
  104. movwf dc3
  105. Delay_1
  106. decfsz dc1, f
  107. goto $+2
  108. decfsz dc2, f
  109. goto $+2
  110. decfsz dc3, f
  111. goto Delay_1
  112. goto $+1
  113. goto $+1
  114. nop
  115. ;end delay
  116. bcf PORTA,b'010' ;clear led
  117. decfsz ptm,f ; decrement run_timer
  118. goto run_timer ;continue next cycle if iwt decrement result was not zero
  119. movlw 0x78
  120. movwf ptm ;reset run timer if it hit zero
  121. ;also remove a minute from timer
  122. btfss PORTB,b'111'
  123. goto $+3
  124. bcf PORTB,b'111'
  125. goto run_timer
  126. btfss PORTB,b'110'
  127. goto $+3
  128. bcf PORTB,b'110'
  129. goto run_timer
  130. btfss PORTB,b'101'
  131. goto $+3
  132. bcf PORTB,b'101'
  133. goto run_timer
  134. btfss PORTB,b'100'
  135. goto $+3
  136. bcf PORTB,b'100'
  137. goto run_timer
  138. btfss PORTB,b'011'
  139. goto $+3
  140. bcf PORTB,b'011'
  141. goto run_timer
  142. btfss PORTB,b'010'
  143. goto $+3
  144. bcf PORTB,b'010'
  145. goto run_timer
  146. btfss PORTB,b'001'
  147. goto $+3
  148. bcf PORTB,b'001'
  149. goto run_timer
  150. btfss PORTB,b'000'
  151. goto run_timer
  152. bcf PORTB,b'000'
  153. goto start ;reset everything if time has run out
  154. END