Arduino LDR Light Sensor: Calibrate Bright and Dark, Wiring and Complete Code
Editorial review required — incomplete hardware verification. Confirm the shipped ANU-LDR-SM-02 module supports 5 V, identify its +/−/S pins, and verify its analog output, fitted resistor and current requirement before powering this build. The store listing does not provide a manufacturer datasheet or voltage rating. A similar-looking KY-018 is not proof of electrical equivalence.
Build a light-response indicator with an LDR photoresistor module and Arduino Uno R3. Watch raw readings in Serial Monitor, capture your own bright and dark reference points, and make the built-in LED turn on when the sensor is covered. This desk experiment teaches calibration and stable switching without adding a lamp or relay.
What you will build
A USB-powered learning project with three sensor connections and no extra libraries. The displayed relative percentage describes your two calibration conditions; it is not a lux measurement. The built-in LED is the only controlled load.
Contents
- How it works
- Components
- Circuit and wiring
- Assembly and setup
- Complete program
- Calibration and testing
- Troubleshooting and FAQs
How it works
An LDR changes resistance with light. A compatible analog module combines it with a fixed resistor to create a changing signal voltage. The Uno reads that signal on A0. Depending on which part of the divider connects to the positive supply, readings may rise or fall with increasing light.
Our original sketch handles either direction by recording a dark reading and a bright reading. It averages 16 samples, converts the result to a relative scale and keeps the LED state unchanged between 40% and 60%. That gap is hysteresis: it reduces flickering near a single switching threshold. It does not correct poor wiring or a saturated signal.
Components and purchase links
| Component | Required | Specification / sold quantity |
|---|---|---|
| LDR photoresistor sensor module | 1 | ANU-LDR-SM-02, 3 pins S/+/-; one module. Confirm electrical ratings before use. |
| Arduino Uno R3 | 1 | 5 V ATmega328P board with USB-B and built-in LED. |
| Male-to-female jumper wires | 3 leads | 20 cm, sold as 40 pieces. Male ends to Uno sockets; female ends to sensor header. |
| USB A-to-B data cable | 1 | USB-B at Uno; USB-A at computer. Use a suitable adapter if your computer lacks USB-A. |
A computer is needed for uploading and Serial Monitor. The fitted sensor header allows direct wiring, so no breadboard or external LED resistor is needed for this build. Use the Uno built-in LED only.
Pinout and connections
| Module label | Uno pin | Purpose |
|---|---|---|
| + | 5V | Power, only for a confirmed 5 V-compatible module |
| − | GND | Common ground |
| S | A0 | Analog input, kept within 0–5 V |
Connection schematic

Visual module wiring

Both drawings are symbolic: follow the verified pin labels, not their illustrated physical positions. They show the external connections; the unverified internal PCB circuit is intentionally omitted. Do not copy a pin order from a different sensor board.
Assembly and Arduino IDE setup
- Before powering anything, obtain the supplier pinout, voltage range and current rating for the delivered module. Confirm S is an analog output and the module is appropriate for 5 V operation. Stop if these checks fail.
- Unplug USB. Connect the three leads according to the table. Check for loose connectors and reversed power.
- Power the Uno using its USB-B socket. Do not connect an external supply to the sensor or feed a voltage into AREF.
- Install Arduino IDE from the official Arduino website. Install Arduino AVR Boards in Boards Manager if needed. Select Arduino Uno and its serial port.
- Create a sketch named arduino_ldr_calibration and paste the complete program below. No library installation or cloud account is required.
The module is powered from a supply pin, never a digital output. For a confirmed passive 10 kΩ series divider, the theoretical current is at most 5 V / 10 kΩ = 0.5 mA; this calculation is not a verified current rating for the store module. Verify the fitted circuit before using that bound.
Complete Arduino program
Download complete code (.txt); save as arduino_ldr_calibration.ino in a folder with the same name.
// Original Anu Electronics tutorial: confirmed analog LDR module + Uno R3.
// Only power the module at 5V after its rating and pinout are verified.
// + -> 5V, - -> GND, S -> A0. Uses the Uno built-in LED.
const byte SENSOR = A0;
int darkValue = 0, brightValue = 0;
bool haveDark = false, haveBright = false, darkState = false;
int sampleSensor() {
long total = 0;
for (byte i = 0; i < 16; ++i) {
total += analogRead(SENSOR);
delay(2);
}
return (int)(total / 16);
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(9600);
Serial.println(F("Cover sensor: send d. Illuminate: send b. Reset: r."));
}
void loop() {
int raw = sampleSensor();
while (Serial.available() > 0) {
char command = Serial.read();
if (command == 'd') { darkValue = raw; haveDark = true; }
if (command == 'b') { brightValue = raw; haveBright = true; }
if (command == 'r') { haveDark = false; haveBright = false; }
}
int span = brightValue - darkValue;
Serial.print(F("Raw: ")); Serial.print(raw);
if (!haveDark || !haveBright || abs(span) < 50) {
darkState = false;
digitalWrite(LED_BUILTIN, LOW);
Serial.println(F(" | Calibrate d and b; need separation >= 50 counts."));
} else {
long relative = (long)(raw - darkValue) * 100L / span;
relative = constrain(relative, 0L, 100L);
if (relative < 40) darkState = true;
if (relative > 60) darkState = false;
digitalWrite(LED_BUILTIN, darkState ? HIGH : LOW);
Serial.print(F(" | Relative: ")); Serial.print(relative);
Serial.print(F("% | LED: "));
Serial.println(darkState ? F("ON") : F("OFF"));
}
delay(200);
}
Key code sections
-
sampleSensor()averages 16 readings over roughly 32 ms to reduce brief variations. - The commands
dandbcapture the current averaged sample. Calibration remains in RAM and resets after power loss. - A minimum separation of 50 counts rejects nearly identical calibration points. This is a practical starting criterion, not a sensor specification.
- The signed span supports either rising or falling raw readings. A long integer multiplication avoids overflow on the Uno.
- Below 40% the LED turns on; above 60% it turns off. At exactly 40% or 60%, or between them, it retains its previous state.
Upload, calibrate and test
- Click Verify, then Upload. Open Serial Monitor at 9600 baud.
- Cover the sensor, wait a second, enter lowercase
dand press Send. - Expose it to your chosen brighter room lighting, wait a second, then send lowercase
b. Newline characters are ignored. - If the separation warning remains, choose more distinct light conditions and capture both points again.
- Move your hand slowly over the sensor. The relative reading should decrease as it approaches your dark reference and the LED should turn on below 40%.
- Uncover it. The LED turns off above 60%. Send
rto clear calibration and repeat.
A sample dark=800 and bright=200 would map raw=500 to 50%. Your values can differ or run in the opposite direction. Keep the sensor away from the built-in LED so its light does not feed back into the measurement.
Expected output

The animation uses invented demonstration values to explain the program. It is not a recording or a claim of measured performance.
Troubleshooting
| Symptom | Check |
|---|---|
| Always 0 or 1023 | Disconnect power and check +, −, S, common ground and A0. Confirm the output is analog and the sensor is not saturated. |
| Unstable values | Secure the wires, keep the light steady and avoid shadows from moving hands. A disconnected A0 can float. |
| Calibration warning | Capture both d and b with more distinct illumination. Recalibrate after reset. |
| Cannot upload | Check Uno board/port selection, data-capable cable and USB connection; close other programs using the port. |
| LED seems reversed | Capture d while covered and b while illuminated. Do not swap the power connections. |
FAQs
Does 100% mean a fixed light level?
No. It means the chosen bright calibration point or brighter. The scale is nonlinear with physical illumination and is not lux.
Can this control a room light?
This tutorial controls only the built-in LED. A real lamp needs a separately designed driver and power system. Keep mains wiring out of this beginner build.
Can I connect it directly to ESP32?
Do not transfer this 5 V wiring unchanged. An ESP32 needs a compatible supply, safe analog input range and different ADC setup.
Can I use a four-pin comparator board?
That is a different module. It may expose AO and DO and have a threshold potentiometer. Verify its pinout and use its analog output only after checking compatibility.
Keep learning and get the parts
Explore the 10 kΩ voltage-divider tutorial to understand divider behaviour, or the push-button counter tutorial for digital input practice.
Start with the LDR photoresistor module, Uno R3 and the matching wires and USB cable above. Confirm the module ratings before buying it for this exact circuit.
Sources and review status
- Arduino Uno R3: analog inputs and board specifications
- Arduino Uno R3 manual and pinout
- Joy-IT KY-018 reference: similar divider principle, not identification of this store module
The article, sketch and diagrams are original. The CircuitDigest weather-station tutorial informed the section structure only. The cover uses the store product image as reference. Calibration arithmetic and hysteresis were checked with simulated inputs; the sketch has not been compiled or physically tested. Exact module voltage, current, pinout and manufacturer documentation remain pending review.