Build: The LED Light Source and Exposure Timer
Purpose
Section titled “Purpose”To build and bench-prove the half of the sensitometer that makes and times the light: an LED on a heatsink, fed a constant current, switched by a logic-level MOSFET from a Raspberry Pi Pico, watched by a monitor photodiode, and driven by firmware that reports the interval it achieved rather than the one it was asked for.
Nothing here goes into a box. That is the next page. The reason for separating them is that a light source whose stability you have not measured is not worth putting in a box, and once it is in a box you cannot get a meter near it.
You finish this session holding three things: a working module, a serial log of ten identical exposures with their spread computed, and a warm-up curve of your own lamp. The third is the one that matters, because everything the design lesson promised about repeatability depends on a drift figure that nobody can quote for your device.
Learning objectives
Section titled “Learning objectives”By the end of this session you should be able to:
- wire a low-side MOSFET switch from a microcontroller pin, and say what each of the two gate resistors is for;
- choose a drive current from the light the instrument actually needs rather than from the LED’s rating, and justify running far below maximum;
- read the five numbers off an LED, a MOSFET and an ADC datasheet and say which of them your circuit depends on;
- load and run MicroPython firmware on a Pico, read its serial output, and change the four settings that are meant to be changed;
- explain why the exposure is a busy-wait rather than a timer callback on this port;
- measure your own lamp’s warm-up drift and the repeatability of ten identical exposures, and express the second as a spread in log H;
- diagnose the four failures that account for most of the trouble in this circuit: a lamp that will not light, a lamp that will not go out, a microcontroller that resets when the lamp switches, and a monitor reading that is noise.
Prerequisites
Section titled “Prerequisites”Low-voltage electronics for the darkroom builder, in full. This page assumes Ohm’s law, the LED current-voltage curve, the low-side switch, the gate resistor and the pull-down, and the datasheet-reading table, and does not re-teach any of them.
Sensitometer design principles, for the two decisions this build implements without re-arguing: fixed direct current, no PWM during an exposure, and half a second as the design exposure.
A computer with a USB port and a serial terminal. Thonny is the usual choice and needs no setting up; any terminal that opens the Pico’s serial device will do.
Safety classification
Section titled “Safety classification”Level B, and the page says so plainly because the course’s own classification rubric says so. Its Level B criteria name UV exposure units, high-brightness LED sources, or low-voltage electronics builds where a certified power supply provides isolation from the mains — which is this build in one clause. Level A is reserved for work done with purchased, certified equipment, and a module you have soldered yourself is not that.
The rubric’s Level B controls for electronics are the ones this page applies: certified, isolated low-voltage supplies, and no exposed mains conductors at any stage. Both hold by construction. The supply is a USB charger or power bank with its own approvals, nothing in the build exceeds 5 V, and no mains enclosure is opened. HSE’s guidance names limiting the supply voltage to the lowest that will do the job as one of the best ways of reducing the risk of injury, and notes that 230 V AC can kill and that the risk is worst in wet surroundings — which is the room this instrument will end up in.
What is not a hazard here, and why. This page handles no chemistry at all. There is no developer, no fixer, no silver salt, no acid, no solution of any kind, and therefore no splash risk, no glove-selection problem, no eye-irrigation requirement, no vapour, and no liquid waste stream. Saying so plainly matters, because the reflex after twelve parts of chemical safety is to import the whole apparatus of controls, and importing controls that do not apply wastes the attention the real hazards need. The only substances present are a few grams of solder alloy, its flux, and a little isopropanol for cleaning residue.
Nor is there a shock hazard in the ordinary sense. Five volts across dry skin drives a current far below anything a person can feel, and the reason is arithmetic rather than reassurance: skin resistance is measured in tens of kilohms and Ohm’s law does the rest. What five volts can do is deliver a great deal of current into a short circuit, which is a heating and fire question rather than a shock one, and it is why a bare lithium cell is not permitted anywhere in this course and a certified power bank is.
Hazards
Section titled “Hazards”Burns, from the soldering iron and from fresh joints. The tip runs at about 350 °C and a joint stays at solder temperature for several seconds after the iron leaves. The iron returns to its stand every time it leaves your hand. If you are burned, the NHS instruction is cool running water for 20 minutes, as soon as possible; remove clothing and jewellery near the area but never anything stuck to it; and cover the cooled injury by laying cling film over it rather than wrapping. The course’s first aid page carries the general guidance.
Solder flux fume. HSE’s EH40 lists rosin-based solder flux fume, CAS 8050-09-7, at 0.05 mg/m³ over eight hours and 0.15 mg/m³ over fifteen minutes, annotated Sen — capable of causing occupational asthma. The controls are in the next two sections and they are proportionate: the fume rises, so the whole of your exposure comes from having your head in the plume.
Optical radiation from the emitter. A one-watt LED at arm’s length is a lamp; at 30 mm from an eye it is not. Risk groups under BS EN 62471 are assigned by measurement to a specific lamp system, and neither the maker nor this course has measured yours, so the course states no risk group for your LED. HSE’s guidance places exempt and Risk Group 1 LEDs among safe sources and Risk Group 2 LED systems among sources that are safe in normal use but can harm if placed extremely close to the eyes. The control that does not depend on knowing the group: never look into the unshielded emitter, point it away from your face while wiring, and run the bench tests at the lowest current that gives a usable monitor reading.
Heat from the LED and its heatsink. At a few hundred milliamps the star board and heatsink become hot enough to burn a finger held on them. Cree give the maximum junction temperature as 150 °C, and the solder point is not far below it.
Flying offcuts. Trimming component leads fires the cut end across the room. Cut with the offcut trapped between your fingers.
Trip and snag. A USB lead across a floor in a room worked in the dark is a hazard the darkroom inherits from this bench. Route and tape it now, not later.
Required PPE
Section titled “Required PPE”Safety spectacles with side protection, worn for all soldering and all lead trimming. This is the one item that is not optional, and the reason is the offcuts rather than the solder.
Nothing else is specified, and the reason is stated rather than assumed. Gloves are not among the controls here: there is no chemical to keep off the skin, and a glove between your fingers and a 350 °C iron makes the handling worse rather than better by dulling the feedback that stops a burn. A respirator is not among them either — the flux-fume control is ventilation and head position, and HSE’s own hierarchy puts those above personal protection. The isopropanol used for cleaning residue is handled in millilitres and the control is its own label.
Wash your hands before eating. Even with lead-free solder, a bench is a bench.
Ventilation
Section titled “Ventilation”Work at a bench with a window open and a small fan set to move air across the bench and away from your face — not blowing at the joint, which scatters the plume, but drawing it past you.
HSE’s HSG258 classes solder fume among fumes that rise, expand and mix with the room air, and its hierarchy puts eliminating, substituting and reducing the source ahead of extraction. Applied here, that means: solder for an hour rather than an afternoon, keep your head out of the rising plume, and make fewer joints by breadboarding first.
If you buy a bench-top fume extractor, buy it knowing what HSG258 says about them: some of the fan-and-filter units commonly used for solder fume control are ineffective, and a supplier should be able to show that a proposed system provides adequate control. Position it to capture the plume at the joint, a few centimetres away, rather than to stir the room from across the bench.
The bill of materials, with what each part is for and what may replace it. Nothing here is a proprietary kit and every line has a substitute.
| Part | Quantity | What it does | Substitutes and notes |
|---|---|---|---|
| White LED on a 20 mm aluminium star board, about 1 W | 1 | The source | Any mid-power white emitter on a star. The Cree XP-E2 is the course’s worked datasheet example, not a mandate; whatever you buy, find its forward voltage at your current, its maximum current, its maximum junction temperature and its thermal resistance before you wire it |
| Heatsink, 20 to 40 mm, with thermal pad or adhesive | 1 | Holds the junction temperature still, which holds the light output still | A 40 × 40 mm finned extrusion is ample. An offcut of 3 mm aluminium plate works. The thermal interface matters more than the fin area at these powers |
| Constant-current LED driver module, adjustable, 5 V input | 1 | Sets the current and holds it | Or a series resistor, below. The course has not verified a specific module and names none; see the callout under Build stage 2 for the five numbers to check on its datasheet |
| Resistor, 47 Ω, 0.5 W, for the resistor-limited route | 1 | Sets about 50 mA from 5 V | Only if you take the resistor route. Recompute it for your LED’s forward voltage |
| IRLZ44N logic-level N-channel MOSFET, TO-220 | 1 | Carries the LED current, switched by a 3.3 V pin | Any logic-level N-channel part whose datasheet quotes an on-resistance at 3.3 V of gate drive is a better choice than the IRLZ44N, which quotes 10, 5.0 and 4.0 V and nothing lower |
| Resistor, 330 Ω | 1 | Gate series resistor; limits the pin current to 10 mA while the gate capacitance charges | 220 Ω to 1 kΩ all work. Below 220 Ω the pin is asked for more than its 12 mA drive setting |
| Resistor, 100 kΩ | 1 | Gate pull-down; holds the lamp off while the Pico is in reset or unplugged | Not optional. This is the resistor that stops a lamp switching itself on inside a closed box |
| Resistor, 220 kΩ | 1 | Photodiode load; converts photocurrent to a voltage the ADC can read | Chosen on the bench in stage 3. Start at 220 kΩ and change it until the reading sits near two-thirds of full scale |
| BPW34 silicon PIN photodiode | 1 | The monitor: watches the lamp during every exposure | Optional but strongly recommended. An OPT101, which puts the photodiode and its amplifier on one die at 0.45 A/W at 650 nm, removes the load-resistor choice at higher cost |
| Raspberry Pi Pico, with headers | 1 | Times the exposure, reads the monitor, writes the log | A Pico W works and its wireless is unused. An Arduino or ESP32 runs the same circuit with the pin numbers and the language changed |
| Momentary push button | 1 | Triggers an exposure | Any normally-open switch to 0 V; the internal pull-up does the rest |
| Electrolytic capacitor, 470 µF, 10 V or more | 1 | Holds the 5 V rail up when the lamp switches on | The cure for a Pico that resets on every exposure. Fit it at the driver, not at the Pico |
| Ceramic capacitor, 100 nF | 2 | Decoupling at the driver and at the photodiode | Standard practice; cheap; fit them |
| Solderless breadboard, 400 or 830 points | 1 | The prototype, and a legitimate final form | Everything in this list is through-hole for exactly this reason |
| Stripboard, 0.1 in pitch, about 50 × 80 mm | 1 | The soldered final form | Optional. A breadboard taped down inside the enclosure measures just as well until something is knocked |
| Hook-up wire, 22 AWG solid and stranded | a few metres | Wiring | Solid for the breadboard, stranded for anything that flexes |
| USB supply or power bank, 1 A or better, and a lead | 1 | Power, at the only voltage this course builds at | A certified supply or a power bank. Never a bare lithium cell, never a bench supply of unknown provenance, never anything mains that has been opened |
| Heat-shrink sleeving, assorted | a little | Insulating and strain-relieving the LED leads | Electrical tape is a poor second and unwraps when warm |
The course’s firmware drives no display, and that is a decision rather than an omission. A small OLED is one more part, one more library and one more thing to fail in the dark, and the serial log is a better record than a screen because it can be pasted into the lab notebook. The enclosure page adds the one indicator the instrument actually needs, which is an LED you can see with the lid down.
| Tool | For | Notes |
|---|---|---|
| Temperature-controlled soldering iron, fine tip | Every joint | About 350 °C, back in the stand every time |
| Lead-free solder, 0.7 mm | Joints | The flux-fume limit applies to leaded and lead-free alike |
| Side cutters, wire strippers, tweezers | Preparation and trimming | Spectacles on for the trimming |
| Helping hands or a small vice | Holding the work | The commonest cause of a burn is holding a hot board |
| Digital multimeter | Everything | Continuity, then voltage, then current. The single most useful tool on the bench |
| Computer with a serial terminal | Loading and running the firmware | Thonny needs no configuration; mpremote or any terminal works |
| Lux meter, or a phone app you have compared with one | Recording the emitter’s output on the bench | The planner carries a lux-meter line already |
| Second timepiece, with a seconds display | The independent timing check | A phone stopwatch is adequate at the 0.1 per cent level over 60 s |
| Isopropanol and a stiff brush | Flux residue | Small quantities; read its label |
Estimated cost
Section titled “Estimated cost”Cost band ££. The Pico and the LED are the two named parts; everything else is passive components and wire that cost less together than either of them. The one line that can double the total is the constant-current driver module, and the resistor route removes it entirely at a stated cost in stability.
This page quotes no prices, because it cannot verify a current one and because the laboratory planner does not yet carry a single electronics line. The planner records what it could not price rather than guessing, and the electronics for Parts XIV to XVII are on the list of things it is waiting on. What is durable, and is on this page instead, is the specification: the five numbers to check on any substitute part’s datasheet outlast any price.
Estimated consumables cost
Section titled “Estimated consumables cost”Almost nothing in this session is consumed. The parts are capital: they go into an instrument that is meant to last for years and to be recalibrated rather than replaced. What is actually used up is a few grams of alloy and a little solvent.
| Consumed | This session | Sourced price | Cost this session |
|---|---|---|---|
| Lead-free solder, 0.7 mm | about 2 g, or none if you stay on the breadboard | None. The planner carries no electronics line | — |
| Heat-shrink sleeving | about 100 mm | None. The planner carries no electronics line | — |
| Isopropanol, for flux residue | a few millilitres | None. The planner prices isopropanol only in the darkroom quantities of Part II | — |
| Stripboard | one 50 × 80 mm piece, or none | None. The planner carries no electronics line | — |
No row here carries a dated price, so no total is given and none should be inferred. Nothing on this list is free. A run of this session a second time — to build a spare module, or after a mistake — consumes the same four lines and nothing else, because every component is reusable and the two most expensive are socketed rather than soldered in.
Seven stages, about three hours. Stage 0 is not optional and stage 5 is the one people skip.
Stage 0 — Fill in the five numbers (30 minutes)
Section titled “Stage 0 — Fill in the five numbers (30 minutes)”Before a single wire, open the datasheets for the LED and the MOSFET you actually bought and write these on the first page of the build record.
LED. Forward voltage at the current you intend; maximum DC forward current; maximum junction temperature; thermal resistance junction to solder point; temperature coefficient of forward voltage. For a white XP-E2 those are 2.84 to 3.1 V at 350 mA and 85 °C, 1500 mA, 150 °C, 5.8 °C/W and −1.5 mV/°C.
MOSFET. On-resistance at the gate voltage you will apply; gate threshold; input capacitance; maximum continuous drain current; gate-source voltage rating. For the IRLZ44N those are not quoted at 3.3 V — the datasheet gives 0.025 Ω at 5.0 V and 0.035 Ω at 4.0 V and stops — with a threshold of 1.0 to 2.0 V, 1700 pF, 47 A and ±16 V.
If your LED’s forward voltage is not 2.9 V, every resistor value below changes and you must recompute it. That is the point of the stage.
Stage 1 — The Pico and the button (20 minutes)
Section titled “Stage 1 — The Pico and the button (20 minutes)”Push the Pico into the breadboard across the centre channel. Wire the button from GPIO14 to a ground rail, and join the Pico’s ground pin to that rail. Nothing else yet.
Load MicroPython on the board if it is new: hold BOOTSEL while plugging in the USB lead, and the Pico
appears as a mass-storage device onto which the interpreter’s .uf2 file is dragged. Then, at the
REPL:
from machine import Pinb = Pin(14, Pin.IN, Pin.PULL_UP)print(b.value()) # 1 with the button releasedprint(b.value()) # 0 while you hold it downIf it reads 0 with nothing pressed, the button is wired to the wrong rail or is not a normally-open type. Fix it here; a button that reads backwards is very confusing three stages later.
Stage 2 — The switch and first light (30 minutes)
Section titled “Stage 2 — The switch and first light (30 minutes)”Wire the low-side switch exactly as the schematic shows. Build it with the LED disconnected first, check with the multimeter that GPIO15 high pulls the MOSFET’s drain to within a few tens of millivolts of ground and that GPIO15 low leaves it floating high, and only then connect the LED.
The complete module: switch, lamp, monitor and trigger
- +5 V rail, from USB only — certified supply or power bank; nothing mains, no bare cells
- Constant-current element — driver module set to the working current, or 47 Ω for the resistor route
- 470 µF and 100 nF at the driver — holds the rail up through the switching step; fit them here, not at the Pico
- LED on star board and heatsink — anode to the element, cathode to the MOSFET drain
- IRLZ44N, low side — source to 0 V; drain to the LED cathode
- 330 Ω gate series, 100 kΩ gate pull-down — 10 mA peak from the pin; gate defined when the Pico is not driving it
- BPW34 from 3V3 through 220 kΩ to 0 V — reverse biased; the ADC reads the voltage across the load resistor
- GPIO27 tied to 0 V — the converter reads its own offset on ADC1, as the Pico datasheet suggests
- Single ground junction — lamp current and logic meet once; a shared track is how a lamp resets a processor
Breadboard layout, seen from above
- Pico, USB to the left, columns 1 to 20 — pins land in row C and row H; the 0.7 in row spacing means it straddles the channel with rows A-B and I-J free
- C1 to top + rail, C3 to top − rail — VBUS carries the 5 V rail and the lamp current runs back through the Pico's USB connector; keep the total under 400 mA
- C9 to top − rail — GPIO27, ADC1, tied to 0 V so the firmware can read the converter's own offset
- C5 to B23, C10 to B25 — 3V3 out to the photodiode cathode column; GPIO26 to the monitor junction column
- BPW34: cathode D23, anode D25 — reverse biased — cathode to 3V3, never to the 5 V rail, because an ADC pin must not exceed the 3.3 V supply
- 220 kΩ from E25 to E27; A27 to top − rail — the photodiode load. Change this value in stage 3 until the reading sits near two-thirds of full scale
- 100 nF from C25 to C27 — across the load resistor; quietens the monitor reading
- Button from J19 to J21; I21 to bottom − rail — GPIO14 with its internal pull-up, so a press reads 0
- 330 Ω from I20 to I24 — GPIO15 to the MOSFET gate column; 10 mA peak into the gate capacitance
- 100 kΩ from H24 to bottom − rail — gate pull-down; the lamp stays off while the Pico is in reset or unplugged
- IRLZ44N: gate J24, drain J25, source J26 — check the pinout against your own datasheet — TO-220 packages are not all in this order
- H26 to bottom − rail — MOSFET source to 0 V
- Constant-current element: bottom + rail to F29 — the driver module's output, or the 47 Ω resistor of the resistor route
- 470 µF and 100 nF, bottom + rail to bottom − rail at columns 27 and 28 — watch the electrolytic's polarity; these belong here, at the current step, not by the Pico
- Two jumpers at column 30 — top + rail to bottom + rail, top − rail to bottom − rail
- LED on flying leads: anode from column 29, cathode to column 25 — off the board with its heatsink; heat-shrink and a cable tie on both leads
Check the whole board against the key with the meter on continuity before you plug the USB lead in. Three checks catch almost everything: the two rails are not connected to each other; the MOSFET’s gate and source are not connected to each other; and the photodiode’s cathode is on the 3V3 column and not the 5 V rail.
Then, at the REPL, with the LED connected and pointed away from your face:
from machine import Pinimport timelamp = Pin(15, Pin.OUT, value=0)lamp.value(1); time.sleep(1); lamp.value(0)Stage 3 — The monitor, and choosing its load resistor (25 minutes)
Section titled “Stage 3 — The monitor, and choosing its load resistor (25 minutes)”The BPW34 is wired reverse-biased from the Pico’s 3V3 output, not from the 5 V rail: an ADC input must not go above the 3.3 V supply by more than about 300 mV, because those pins carry a reverse diode to that rail. Cathode to 3V3, anode to the top of the load resistor, load resistor to 0 V, and the ADC reads the junction.
Sizing the load resistor is a two-line calculation and then a measurement. The datasheet gives a short-circuit current of 80 µA at 1000 lux under standard light A, so:
At 100 lux on the sensor — a plausible figure a few centimetres off-axis from the emitter — that is
8 µA, and 220 kΩ gives 1.76 V, comfortably over half of the 3.3 V range. But the real figure depends
entirely on where you put the sensor, so do this instead: fit 220 kΩ, switch the lamp on, read
monitor.read_u16(), and change the resistor until the reading sits between about 20,000 and
45,000. Below that you are wasting resolution; above about 62,000 the reading saturates and can no
longer detect an increase, which is the failure mode that hides a fault.
Position the sensor so it sees the emitter but not the film plane, and fix it permanently. A monitor that moves is a monitor that lies.
Stage 4 — The firmware (20 minutes)
Section titled “Stage 4 — The firmware (20 minutes)”Save the listing below to the board as sensitometer.py. Then, at the REPL:
import sensitometer as ss.selftest()selftest prints the button state, the monitor reading dark and lit, and passes or fails on whether
the lamp switches and the monitor is on scale. Do not go further until it passes.
The firmware in full
Section titled “The firmware in full”This is the whole of it. It is published under the course’s content licence and was tested on
MicroPython v1.24.1 for the RP2 port. Four settings near the top are meant to be changed and the rest
is not: EXPOSURE_MS, WARM_UP_S, CADENCE_S and SETTLE_US all get their real values from stage 5,
and the values in the listing are provisional starting points rather than measurements.
"""sensitometer.py - Pure Silver, Part XIV: LED light source and exposure timer.
Target Raspberry Pi Pico (RP2040), MicroPython v1.24.1 for RPI_PICO.Install copy to the board as sensitometer.py, then at the REPL: import sensitometer as s s.selftest()Licence CC BY-SA 4.0, as the rest of this course's content.
Every routine prints comma-separated values, with '#' beginning any line thatis a comment, so a captured terminal session is already a data file."""
import machineimport mathimport micropythonimport sysimport time
micropython.alloc_emergency_exception_buf(100)
VERSION = "1.0"
# --- Wiring. Rewiring the board means changing these four numbers only. -----PIN_GATE = 15 # -> 330 R -> IRLZ44N gate; 100k gate-to-source pull-downPIN_BUTTON = 14 # -> button -> 0 V; internal pull-up, so pressed reads 0PIN_MONITOR = 26 # ADC0 <- photodiode load resistorPIN_ZERO = 27 # ADC1 <- tied to 0 V, read as the converter's own offset
# --- Settings the calibration experiment will replace with measured ones. ---EXPOSURE_MS = 500 # the design exposure of Part XIVWARM_UP_S = 600 # continuous run before the first exposure of a sessionCADENCE_S = 30 # minimum interval between exposures, so each starts alikeSETTLE_US = 5000 # delay after switch-on before the monitor is sampledMONITOR_N = 32 # ADC readings averaged into one monitor valueDEBOUNCE_MS = 250 # further button edges ignored for this longGUARD_US = 60000 # below this exposure the monitor is not sampled at all
lamp = machine.Pin(PIN_GATE, machine.Pin.OUT, value=0)button = machine.Pin(PIN_BUTTON, machine.Pin.IN, machine.Pin.PULL_UP)monitor = machine.ADC(machine.Pin(PIN_MONITOR))zero = machine.ADC(machine.Pin(PIN_ZERO))try: # "LED" on current firmware, 25 on old heartbeat = machine.Pin("LED", machine.Pin.OUT, value=0)except (TypeError, ValueError): heartbeat = machine.Pin(25, machine.Pin.OUT, value=0)
_count = 0_press = False_press_at = 0COLUMNS = "n,kind,ticks_ms,requested_us,measured_us,monitor_mean,monitor_sd"
def _on_button(pin): """Soft-IRQ handler. Debounced in software: contacts bounce for milliseconds.""" global _press, _press_at now = time.ticks_ms() if time.ticks_diff(now, _press_at) < DEBOUNCE_MS: return _press_at = now _press = True
button.irq(trigger=machine.Pin.IRQ_FALLING, handler=_on_button)
def mean(xs): return sum(xs) / len(xs)
def sd(xs): """Sample standard deviation. Returns 0.0 for fewer than two values.""" n = len(xs) if n < 2: return 0.0 m = mean(xs) return math.sqrt(sum((x - m) * (x - m) for x in xs) / (n - 1))
def off(): """Everything dark. Call this if anything goes wrong.""" lamp.value(0) heartbeat.value(0)
def header(): print("# Pure Silver sensitometer firmware v{}".format(VERSION)) print("# {}".format(sys.implementation)) print("# exposure {} ms, cadence {} s, monitor {} samples".format( EXPOSURE_MS, CADENCE_S, MONITOR_N))
def read_monitor(n=MONITOR_N): """Mean and standard deviation of n monitor readings, offset-corrected.
The offset comes from a second ADC channel tied to 0 V, because the Pico's converter has an inherent offset of tens of millivolts that varies from chip to chip. read_u16 always returns 0 to 65535 whatever the real resolution, so the bottom four bits here carry no information. """ offset = zero.read_u16() xs = [] for _ in range(n): xs.append(monitor.read_u16() - offset) return mean(xs), sd(xs)
def expose(ms=EXPOSURE_MS): """Switch the lamp on for ms milliseconds. Return what actually happened.
Returns (requested_us, measured_us, monitor_mean, monitor_sd), with the two monitor values set to -1.0 when the exposure was too short to sample.
The interval is busy-waited on the microsecond counter. That is deliberate: machine.Timer on the RP2 port is a virtual timer whose callback can be delayed by garbage collection, so the tightest thing available is a loop that does nothing else. The loop can only end on an iteration, so the measured interval always slightly exceeds the requested one, and the routine reports the interval it achieved rather than the one it was asked for. """ target = int(ms * 1000) m_mean = -1.0 m_sd = -1.0 lamp.value(1) start = time.ticks_us() try: if target >= GUARD_US: time.sleep_us(SETTLE_US) m_mean, m_sd = read_monitor() while time.ticks_diff(time.ticks_us(), start) < target: pass finally: lamp.value(0) measured = time.ticks_diff(time.ticks_us(), start) return target, measured, m_mean, m_sd
def _log(kind, target, measured, m_mean, m_sd): global _count _count += 1 print("{},{},{},{},{},{:.1f},{:.1f}".format( _count, kind, time.ticks_ms(), target, measured, m_mean, m_sd))
def selftest(): """Prove the wiring before anything is exposed. Nothing runs for long.""" header() off() print("# button reads {} (1 = released, 0 = pressed)".format(button.value())) time.sleep_ms(200) dark, dark_sd = read_monitor() lamp.value(1) time.sleep_ms(300) lit, lit_sd = read_monitor() off() print("# monitor dark {:.1f} +/- {:.1f}".format(dark, dark_sd)) print("# monitor lit {:.1f} +/- {:.1f}".format(lit, lit_sd)) if lit - dark < 500: print("# FAIL: the monitor barely sees the lamp.") print("# Check the LED, the driver, the MOSFET gate and the photodiode polarity.") elif lit > 62000: print("# FAIL: the monitor is saturated and cannot detect a change.") print("# Reduce its load resistor, or move it further from the emitter.") else: print("# PASS: the lamp switches and the monitor is on scale.") return lit - dark
def warm_up(seconds=WARM_UP_S, interval=30): """Run the lamp continuously, logging the monitor, and print the curve.
This is the drift characterisation, not an operating step. Run it once, plot monitor_mean against elapsed_s, and read off how long the assembly takes to stop moving and by how much it moved. Set WARM_UP_S from your own plot; the 600 s here is a provisional starting value, not a measurement. """ print("# warm_up: {} s continuous, monitor every {} s".format(seconds, interval)) print("elapsed_s,monitor_mean,monitor_sd") lamp.value(1) start = time.ticks_ms() due = 0 try: while True: elapsed = time.ticks_diff(time.ticks_ms(), start) // 1000 if elapsed >= due: m, s = read_monitor() print("{},{:.1f},{:.1f}".format(elapsed, m, s)) due = due + interval if elapsed >= seconds: break time.sleep_ms(100) finally: off() print("# warm_up complete")
def repeat(n=10, ms=EXPOSURE_MS, cadence_s=CADENCE_S): """n identical exposures at a fixed cadence, with the statistics at the end.
This is the repeatability test, and the cadence is part of the result: with the lamp off between exposures the LED cools, so strips made two minutes apart are not the same measurement as strips made ten seconds apart. Fix the cadence, record it, and quote it with the figure. """ print("# repeat: {} exposures of {} ms at a {} s cadence".format(n, ms, cadence_s)) print(COLUMNS) times = [] lights = [] for i in range(n): if i: time.sleep(cadence_s) record = expose(ms) _log("repeat", *record) times.append(record[1]) if record[2] >= 0: lights.append(record[2]) t_mean = mean(times) print("# measured_us mean {:.1f} sd {:.2f} ({:.4f} % of the mean)".format( t_mean, sd(times), 100.0 * sd(times) / t_mean)) if len(lights) > 1: l_mean = mean(lights) l_sd = sd(lights) print("# monitor mean {:.1f} sd {:.2f} ({:.3f} % of the mean)".format( l_mean, l_sd, 100.0 * l_sd / l_mean)) print("# flux spread expressed as log H: {:.5f}".format( math.log10(1.0 + l_sd / l_mean))) return times, lights
def session(ms=EXPOSURE_MS, warm_s=WARM_UP_S, cadence_s=CADENCE_S): """Warm up, then make one exposure per button press, logging every one.
Runs until interrupted. Ctrl-C at the REPL leaves the lamp off, because expose() switches it off in a finally clause. """ global _press header() if warm_s: warm_up(warm_s) print(COLUMNS) last = time.ticks_ms() _press = False try: while True: if _press: _press = False wait = cadence_s * 1000 - time.ticks_diff(time.ticks_ms(), last) if wait > 0: print("# holding {} ms to keep the cadence".format(wait)) time.sleep_ms(wait) heartbeat.value(1) record = expose(ms) heartbeat.value(0) last = time.ticks_ms() _log("exposure", *record) time.sleep_ms(20) finally: off()Three things in that listing repay a second reading. expose switches the lamp off inside a finally
clause, so an interrupt at the REPL leaves the lamp dark rather than lit. The exposure interval is a
busy-wait on ticks_us, because machine.Timer on this port is a virtual timer whose callback can
be delayed by garbage collection, and the loop can only end on an iteration, so the measured interval
always slightly exceeds the requested one — which is why the routine reports the interval it achieved.
And read_monitor subtracts a reading from a second ADC channel tied to 0 V, which is the Pico
datasheet’s own suggestion for dealing with a converter whose reference is filtered from a switching
regulator and whose offset of some tens of millivolts varies from chip to chip.
Stage 5 — Characterise the lamp (40 minutes)
Section titled “Stage 5 — Characterise the lamp (40 minutes)”This is the stage that turns a circuit into an instrument, and it is the one that gets skipped.
s.warm_up(1800, 30) # 30 minutes continuous, a monitor reading every 30 ss.repeat(10, 500, 30) # ten 500 ms exposures at a 30 s cadenceCapture both to a file. The first is your drift curve and the second is your repeatability, and neither exists for your device anywhere else.
One exposure, end to end
Stage 6 — Commit it to metal, or do not (45 minutes)
Section titled “Stage 6 — Commit it to metal, or do not (45 minutes)”If the breadboard works and will live inside the enclosure on double-sided tape, it will measure exactly as well as a soldered board until something is knocked. Many readers should stop here.
If you solder: lay the stripboard out to match the breadboard, cut the tracks under the Pico’s two rows of pins and between the MOSFET’s three legs, and solder in this order — links first, then resistors, then the capacitors, then the MOSFET, then the Pico’s headers last. Check continuity with the multimeter before the first power-up, and check specifically that the MOSFET’s gate and source are not shorted, which is the failure a cut-track mistake produces.
The LED and its heatsink stay off the board, on flying leads, because they belong at the bottom of the enclosure and the board does not.
Stage 7 — Strain relief and labelling (10 minutes)
Section titled “Stage 7 — Strain relief and labelling (10 minutes)”Every wire that leaves the board gets a cable tie or a blob of hot-melt adhesive within 20 mm of its joint, so that a pull lands on the tie and not on the solder. The LED’s two leads get heat-shrink and a tie. Label the board with the date, the drive current, the load resistor value and the firmware version, in permanent marker, on the board itself — not on a note that will be lost. The instrument certificate the calibration experiment writes will refer to these, and a module whose current nobody recorded has to be characterised again from the beginning.
Testing and calibration
Section titled “Testing and calibration”Three tests, in this order, and all three produce numbers that go on the instrument certificate the calibration experiment later in this part writes. The tables below are blank on purpose. The course has not built and measured this module, and printing a plausible drift figure would be inventing a measurement — which is the one thing this course does not do. Fill them in from your own bench.
Test 1 — Exposure time, against an independent clock
Section titled “Test 1 — Exposure time, against an independent clock”The firmware’s own measured_us is honest but self-referential: it is the same counter that timed the
exposure. One check from outside is needed, and one is enough.
import sensitometer as ss.expose(60000) # sixty seconds; start a stopwatch on the same breathA minute timed by hand is good to about a tenth of a second, or 0.17 per cent — thirty times looser than the crystal’s own ±65 ppm and about six times tighter than the one per cent the instrument needs. If the two agree, the whole timing chain is proved and you need never test it again.
| Requested | Firmware’s measured_us | Independent clock | Difference | |
|---|---|---|---|---|
| 60 s check | 60.000 s | |||
| Repeat, next session | 60.000 s |
Test 2 — Flux stability over thirty minutes
Section titled “Test 2 — Flux stability over thirty minutes”s.warm_up(1800, 30)Plot monitor_mean against elapsed_s. What you are looking for is not a number but a shape: a
rise or fall that flattens, and the time at which it flattens. Read three things off it.
| Quantity | How to read it | Your figure |
|---|---|---|
| Total excursion, first reading to last | (max − min) ÷ mean, as a percentage | |
| Time to settle within 0.5 per cent of the final value | from the plot | |
| Residual drift after settling, per 10 minutes | slope of the flat part | |
| Residual drift expressed in log H | log₁₀(1 + fractional drift) |
The middle row is your warm-up rule and it replaces the provisional value in the firmware. If your
lamp settles in four minutes, WARM_UP_S = 600 is wasting six minutes of every session; if it takes
twenty, the provisional value is dangerously short.
Test 3 — Repeatability of ten identical exposures
Section titled “Test 3 — Repeatability of ten identical exposures”s.repeat(10, 500, 30)The firmware computes the statistics for you and prints the flux spread in log H, which is the form the error budget wants.
| Quantity | Firmware output | Your figure |
|---|---|---|
| Mean measured interval | measured_us mean |
|
| Timing spread, as a percentage of the mean | sd line |
|
| Mean monitor reading | monitor mean |
|
| Flux spread, as a percentage of the mean | sd line |
|
| Flux spread in log H | flux spread expressed as log H |
Then run it again at a different cadence — ten seconds instead of thirty — and record both. If the two differ, the cadence is part of your operating procedure and must be written on the certificate. The next section says why it might.
What is happening physically
Section titled “What is happening physically”Every exposure is a thermal event as well as an optical one.
At 350 mA and about 2.9 V the LED is dissipating roughly a watt, almost all of it as heat. Cree’s thermal resistance from junction to solder point is 5.8 °C/W for a white part, so the junction sits about 6 °C above its own solder point whenever it is running — and it gets there fast, because the die and the slug beneath it have very little heat capacity. The heatsink, by contrast, has a great deal, and warms over tens of seconds to minutes.
That split is the whole of the behaviour you are about to measure, and it has a consequence worth
stating before you see it. In a half-second exposure the junction reaches its excess over the
heatsink almost immediately and then stops moving. What changes from exposure to exposure is not the
junction’s excess but the heatsink’s own temperature, which depends on how long ago the last
exposure was. That is why repeat takes a cadence argument and why it is part of the result rather
than a convenience. Note what the course is doing here: Cree publish the thermal resistance, and that
is a datasheet fact; the time constants are not published for any assembly, which is precisely why
this is a measurement and not a calculation.
Two optical consequences follow the thermal one. Flux droops as the junction warms — Cree plot relative flux against junction temperature from 25 °C to 150 °C, and this course reads the axes of that chart and not its ordinates, because a value taken off a printed graph is a guess with a decimal point on it. And the spectrum shifts, because a phosphor white LED is a blue emitter under a phosphor and the two do not respond to temperature identically; Cree publish a chart of relative chromaticity against current and temperature, whose existence is the evidence that the mixture moves.
Constant-current drive removes the runaway that constant-voltage drive would add on top of all this, but it does not remove the droop: the current is held, the temperature still rises, and the light still falls. What removes most of the droop is the same starting temperature every time, which is what the cadence buys, and what accounts for the rest is the monitor, which turns the residue into a number you can put in the budget instead of an unknown you have to bound.
Troubleshooting
Section titled “Troubleshooting”| What you see | Likely cause | What to do |
|---|---|---|
| LED does not light at all | LED reversed, or the driver’s output open, or the MOSFET not switching | Meter first, guess second. With GPIO15 high, measure gate to source: it should read about 3.3 V. Then measure drain to source: a few tens of millivolts means the MOSFET is on and the fault is upstream. Then measure across the LED |
| LED is permanently on and the pin does nothing | Drain and source swapped, or the MOSFET is not a logic-level part, or the body diode is conducting | Check the pinout against the datasheet — TO-220 packages are not all the same order. If the gate is at 0 V and the LED still lights, the device is in backwards and its body diode is passing the current |
| LED lights dimly and the MOSFET gets hot | The gate is not being driven hard enough to bring the device fully on | Measure the gate voltage while it is on. If it is well below 3.3 V, the gate resistor is too large or the pin is loaded. If it is at 3.3 V and the drain still sits at a volt or more, your MOSFET is not logic-level: replace it with one whose datasheet quotes on-resistance at 3.3 V |
| The Pico resets every time the lamp switches on | Supply sag: the current step drops the 5 V rail through the resistance of the wiring, and the board browns out | Fit the 470 µF across the rail at the driver. Shorten and thicken the supply wires. Join grounds at one point rather than along a shared track. If it persists, power the lamp from a second USB supply, joining only the grounds |
| Monitor reading jumps about by thousands of counts | Mains-frequency light falling on the photodiode, or a floating ADC pin, or a ground loop | Shield the sensor from room light — it should see the emitter and nothing else. Check GPIO27 really is at 0 V. Increase MONITOR_N. The RP2 documentation warns that an unconfigured ADC pin sinks about 60 µA after a hard reset, which produces exactly this |
| Monitor sits near 65535 whatever the lamp does | Saturated: the load resistor is too large, or the sensor is too close | Reduce the load resistor, or move the sensor further from the emitter or off-axis. Saturation is dangerous because it hides an increase and looks like perfect stability |
| Monitor reads a few hundred with the lamp on | The photodiode is reversed, or the load resistor is far too small | Cathode goes to 3V3, anode to the load resistor. Reversed, it is a forward-biased diode and reads a fixed voltage that does not follow the lamp |
| One button press gives three exposures | Contact bounce outrunning the debounce window | Increase DEBOUNCE_MS to 400. If it persists, the button is worn: a hardware 100 nF across its contacts helps and does not replace the software |
| Measured interval far longer than requested | Something else is running: a print inside the loop, an interrupt firing, or garbage collection | Nothing may run during the busy-wait. Check you have not added a print or a monitor read inside the while loop. Call gc.collect() before the exposure, not during it |
| Nothing appears on the serial port | The board is in BOOTSEL mode, or the wrong device is open, or MicroPython is not installed | Unplug, replug without holding BOOTSEL. If it enumerates as a mass-storage device, the interpreter is not installed |
| Ten exposures show a steady downward trend in the monitor | The assembly is still warming, and you did not warm it up | Run warm_up first and read your own settling time off the curve. This is the fault the whole of test 2 exists to find |
Questions
Section titled “Questions”- Your LED measures 2.65 V forward at 50 mA rather than the 2.72 V assumed on this page, and you are taking the resistor route from a 5.0 V rail. Recompute the resistor, its dissipation, and the percentage change in current that a 1 per cent supply wobble now produces. Say whether the change in forward voltage made the supply sensitivity better or worse, and why.
- The firmware reports
measured_usof 500 312, 500 287 and 500 305 for three requested 500 ms exposures. Express the spread as a fraction of the exposure and in log H, and say whether it belongs in the error budget or can be ignored. Then explain why the offset of about 300 µs is not an error at all. selftestprints a lit reading of 63 800 and a dark reading of 640. It reports a pass. Why is that pass misleading, what will the module do wrong that will not be obvious for weeks, and what is the fix?- Your warm-up curve falls by 4 per cent over the first eight minutes and is then flat. Convert the 4 per cent to log H, compare it with the 0.02 log H uniformity target from the design lesson, and say what warm-up rule you would write. Then say what would change if the fall were 0.4 per cent instead.
- A friend wires the MOSFET on the high side — between the 5 V rail and the LED anode, with the LED cathode to ground — using the same IRLZ44N and the same 3.3 V pin. Explain why the lamp will either not light or light dimly, in terms of the gate-to-source voltage rather than in terms of convention.
- The driver module you bought says nothing about open-circuit operation. Give the two wirings that are then available, say what each one asks the driver to do at the moment of switching, and say which measurement in stage 5 would reveal a driver that is unhappy with the choice you made.
Further experiments
Section titled “Further experiments”Measure the intermittency effect on your own monitor, and then on film. The design lesson forbids
PWM during an exposure on the strength of Sheppard and Mees’s 1907 sector-wheel measurement, and says
plainly that the critical frequency for a modern emulsion is not published anywhere the course has
read. You can attack the second half of that. Drive the lamp with machine.PWM, whose duty_u16 sets the
duty cycle as a ratio of the value you give it to 65535, so half duty is duty_u16(32768); take
100 Hz, 1 kHz and 10 kHz in turn and confirm on the monitor that the mean is the same at all three —
it should be, since the photodiode integrates. Then expose three strips of film for the same total time at
the three frequencies plus one at fixed current at half the current, and develop all four together. If
the four strips differ, you have measured the intermittency effect with equipment you built.
Find your cadence dependence. Run repeat(10, 500, 10) and repeat(10, 500, 120) on the same
afternoon. Plot the monitor reading against exposure number for both. A rising or falling trend at the
short cadence and a flat line at the long one is the heatsink’s thermal time constant showing itself,
and the crossover tells you the shortest cadence the instrument may be operated at.
Compare the two current-setting routes head to head. Build both, and run each from a good regulated supply and then from a cheap USB charger under load — a phone charging from the same port is a realistic disturbance. The prediction from the arithmetic in stage 2 is a 2.1 per cent current change per 1 per cent supply change for the resistor and something far smaller for the driver. Measuring it turns a specification into your own number.
Build the green variant. A green emitter is the design lesson’s documented alternative: better matched to a lux meter, more stable in spectrum, and measuring a green speed rather than a panchromatic one. Build a second LED assembly, keep everything else identical, and expose the same film through both. The offset between the two curves is your own measurement of what the illuminant is worth — and it is a number nobody can look up for you.
Sources for this page
16 cited · checked 2026-09-05
- 01Raspberry Pi Pico Datasheet: An RP2040-based microcontroller boardRaspberry Pi Ltd§ Section 4.2, general purpose IO - GPIO powered from the on-board 3.3 V rail and fixed at 3.3 V, GPIO0 to GPIO22 digital only, GPIO26 to 28 ADC-capable, and the reverse diode to the 3.3 V rail that limits the input voltage on those pins; section 4.3, using the ADC - the reference filtered from the switching regulator through 201 ohms into 2.2 microfarads, the inherent offset of about 30 mV varying chip to chip, and the recommendation to tie a second channel to ground as an offset measurement; section 2.3 and the pin descriptions - VBUS 5 V plus or minus 10 per cent, VSYS 1.8 to 5.5 V, and the 3V3 pin load kept below 300 mA; section 3.1, current tablesdatasheets.raspberrypi.com/pico/pico-datasheet.pdftier 1, primary2026-09-05
- 02RP2040 Datasheet: A microcontroller by Raspberry PiRaspberry Pi Ltd§ Section 5.5.3.5, interpreting GPIO output voltage specifications - the 2, 4, 8 and 12 mA drive strengths are not hard limits, and the limits on the total current sourced and sunk by the IO bank; section 2.16.1.1, recommended crystalsdatasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdftier 1, primary2026-09-05
- 03IRLZ44NPbF HEXFET Power MOSFET, data sheet PD-94831International Rectifier, now Infineon Technologies, 2003§ Electrical Characteristics at TJ = 25 C - gate threshold voltage 1.0 to 2.0 V at VDS = VGS and ID = 250 microamps; on-resistance 0.022 ohm at 10 V, 0.025 ohm at 5.0 V and 0.035 ohm at 4.0 V of gate drive, with no figure at 3.3 V; input capacitance 1700 pF; Absolute Maximum Ratings - 55 V drain-source, 47 A continuous drain current at 25 C case, gate-source plus or minus 16 V, junction-to-ambient thermal resistance 62 C/Winfineon.com/dgdl/Infineon-IRLZ44N-DataSheet-v01_01-EN.pdftier 1, primary2026-09-05
- 04XLamp XP-E2 LEDs, product family data sheet CLD-DS56 rev 25BCree LED§ Characteristics - forward voltage 2.84 V minimum to 3.1 V maximum for white at 350 mA and 85 C and 3.12 V at 1000 mA; maximum DC forward current 1500 mA for white; maximum junction temperature 150 C; thermal resistance junction to solder point 5.8 C/W for white; temperature coefficient of voltage -1.5 mV/C for white; Relative Flux vs. Current, whose axes run to 1500 mA against a flux axis drawn to 300 per cent; and the absence of any switching or rise-time figure in the documentdownloads.cree-led.com/files/ds/x/XLamp-XPE2.pdftier 1, primary2026-09-05
- 05BPW 34 silicon PIN photodiode, data sheet version 1.5ams-OSRAM AG, 2020§ Characteristics at 25 C - short-circuit current 80 microamps at 1000 lux under standard light A, spectral sensitivity 80 nA/lx, wavelength of maximum sensitivity 920 nm, spectral range 420 to 1120 nm, radiant sensitive area 7.02 square millimetres, half angle 60 degrees, dark current 2 nA typical and 30 nA maximum, rise and fall times 0.02 microseconds; Maximum Ratings - reverse voltage 32 V, total power dissipation 150 mWlook.ams-osram.com/m/65d547088a09187c/original/BPW-34.pdftier 1, primary2026-09-05
- 06OPT101 monolithic photodiode and single-supply transimpedance amplifier, data sheet SBBS002Texas Instruments Incorporated§ Features and Electrical Characteristics - responsivity 0.45 A/W at 650 nm and 0.45 V per microwatt at the internal feedback resistor, with the photodiode and its transimpedance amplifier on one dieti.com/lit/ds/symlink/opt101.pdftier 1, primary2026-09-05
- 07Quick reference for the RP2, MicroPython documentationDamien P. George, Paul Sokolovsky and contributors§ Timers - the RP2040 system timer provides a global microsecond timebase but only the software timer is available; ADC - four 12-bit SAR channels on GP26 to GP29, standard range 0 to 3.3 V, read_u16 across that range, and the note that after a hard reset an unconfigured pin sinks about 60 microamps and can give wrong readings; Pins and GPIO - internal pull-up on an inputdocs.micropython.org/en/latest/rp2/quickref.htmltier 1, primary2026-09-05
- 08class Timer, control hardware timers, MicroPython library documentationDamien P. George, Paul Sokolovsky and contributors§ Timer Types - most ports support hardware timers except Zephyr and RP2, which support only virtual timers, and soft-interrupt callbacks are prone to garbage-collection jitterdocs.micropython.org/en/latest/library/machine.Timer.htmltier 1, primary2026-09-05
- 09time, time related functions, MicroPython library documentationDamien P. George, Paul Sokolovsky and contributors§ time.ticks_us and time.ticks_diff - counters from an arbitrary reference that wrap at an unexposed value, on which only ticks_diff and ticks_add are valid; time.sleep_us, documented as delaying for at least the requested intervaldocs.micropython.org/en/latest/library/time.htmltier 1, primary2026-09-05
- 10class ADC, analog to digital conversion, MicroPython library documentationDamien P. George, Paul Sokolovsky and contributors§ ADC.read_u16 - one reading returned as an integer from 0 to 65535 scaled across the input range, whatever the converter's real resolutiondocs.micropython.org/en/latest/library/machine.ADC.htmltier 1, primary2026-09-05
- 11class PWM, pulse width modulation, MicroPython library documentationDamien P. George, Paul Sokolovsky and contributors§ Constructor and methods - freq in hertz, duty_u16 setting the duty cycle as the ratio of the given value to 65535, and duty_ns setting the pulse width directly; and the note that on the rp2 port there are eight independent PWM blocks each with two outputs and a 16-bit counter, so setting the frequency of one object may affect another sharing the same generatordocs.micropython.org/en/latest/library/machine.PWM.htmltier 1, primary2026-09-05
- 12EH40/2005 Workplace exposure limits, containing the list of workplace exposure limits for use with COSHHHealth and Safety Executive, 2005§ Table 1 - rosin-based solder flux fume, CAS 8050-09-7, 0.05 mg/m3 over eight hours and 0.15 mg/m3 over fifteen minutes, annotated Sen; Annotations - Sen means capable of causing occupational asthmahse.gov.uk/pubns/priced/eh40.pdftier 1, primary2026-09-05
- 13Controlling airborne contaminants at work: A guide to local exhaust ventilation (LEV), HSG258Health and Safety Executive, 2011§ The list of controls that come before extraction, and paragraph 93, that some bench-mounted fan and filter units commonly used for solder fume control are ineffective and that a supplier should show the proposed system provides adequate controlhse.gov.uk/pubns/priced/hsg258.pdftier 1, primary2026-09-05
- 14Guidance for Employers on the Control of Artificial Optical Radiation at Work Regulations 2010Health and Safety Executive, 2010§ List 1 and the intermediate list - exempt and Risk Group 1 lamps and lamp systems including LEDs among safe sources, and Risk Group 2 lamps and LED systems among the sources that are safe under normal conditions but can cause harm if placed extremely close to the eyes; and the supplier's duty under section 6 of the Health and Safety at Work etc Act 1974 to provide information for safe useaber.ac.uk/en/media/departmental/healthsafetyenvironment/employers-aor.pdftier 1, primary2026-09-05
- 15Electrical safety and you: A brief guide, INDG231(rev1)Health and Safety Executive, 2012§ Reducing the risk, Reduce the voltage - limit the supply voltage to the lowest needed to get the job done; What are the hazards - 230 volts AC can kill, and the risk is greatest in wet surroundingshse.gov.uk/pubns/indg231.pdftier 1, primary2026-09-05
- 16Burns and scalds: TreatmentNational Health Service, 2026§ Treatment - cool running water for 20 minutes as soon as possible, remove clothing and jewellery near the burn but nothing stuck to it, cover with cling film laid over rather than wrapped, and the routes to 111 and to accident and emergencynhs.uk/conditions/burns-and-scalds/treatmenttier 1, primary2026-09-05
Formulas, hazard statements, historical dates and process descriptions on this page were checked against the sources above on the date shown. Safety data changes: obtain the current safety data sheet for the product you actually buy before you open it.