photocell or photo resistor is a Light Dependent Resistors (LDR). LDR's are sensors that detect light. They are small, inexpensive, low-power, easy to use and don't wear out.

 

Overview

A photocell or photo resistor is a Light Dependent Resistors (LDR). LDR's are sensors that detect light. They are small, inexpensive, low-power, easy to use and don't wear out.

An LDR is a resistor that changes its resistive value (in ohms Ω) depending on how much light is shining onto it. They are very low cost, easy to get in many sizes and specifications, but are very innacurate. Each LDR sensor will act a little differently than the other, even if they are from the same batch. The variations can be really large, 50% or higher! For this reason, they shouldn't be used to try to determine precise light levels. Instead, you can expect to only be able to determine basic light changes. When light falls on the sensor the resistance will drop. When it is dark the resistance can be as much as 10Mohm, when the light increases the resistance can drop to 1Kohm. You can test the photocell with a multimeter. Below you see a graph how the resistance of the LDR changes when the light changes.It is a logaritmic scale.

The photocell is the most sensitive between the green light (400nm) and the red light (700nm).
 


You can test how your photocell works by connecting a multimeter in resistance-measurement mode to the two leads and see how the resistance changes when you shine a light on it and then shading the sensor with your hand. Because the resistance changes a lot, put the meter in auto-ranging mode. Otherwise, just make sure you try different ranges, between 1MΩ and 1KΩ.

measuring a photocell


 Circuit example

In this example the LDR-sensor is connected to the power (5V) and to a pull down resistor to ground. Then the junction between the pulldown resistor and the LDR is connected to the analog input PORTC1 of the microcontroller.
The analog voltage reading is used to determine if a row of 8 LED is on or off. The darker it is, the more LED's will be on, if the light is bright the LED's will be off. The LED's have to be connected to PORTD of the ATmega328. In the example the ATMega328 board is used. The circuit can be build on a breadboard.

adc ldr sch

 

adc ldr pic1

Program Example

This is a simple program that switch a led on or off depending the amount of light falling on the LDR. The program is written in WinAVR C-code.

M328 LDR LED WinAVR C-Code

/*
* program name: ADC_LDR.c
* target device: ATMega328P
* Created: 15-7-2017 20:13:21
* Author : www.avrprojects.net
*/

#define F_CPU 1600000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

const unsigned char level[9] = {0b00000000,0b10000000,0b11000000,0b11100000,0b11110000,0b11111000,0b11111100,0b11111110,0b11111111};

void ADC_init(void)
{
ADMUX |= (1<<MUX0) | (1<<ADLAR); // set ADC1, set ADC Left Adjust Result
ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0); //enable ADC, set prescaler to 32
}

unsigned char ADC_raw(void)
{
ADCSRA |= 1<<ADSC; //start conversion;
while (ADCSRA&(1<<ADSC)); //wait conversion end
return ADCH;
}

int main(void)
{
DDRD = 0xFF;
ADC_init();
unsigned int adc_data;
while (1)
{
adc_data = ADC_raw();
adc_data = adc_data/31;
PORTD = level[adc_data];
_delay_ms(10);
}
}


In this project the light on the LCD makes a LED light brighter or dimmer, while the program makes use of a software PWM.

/*
program name: M328 led pwm
date: 11-04-2015
author: www.avrprojects.net
version: 1.0
purpose: reads the value of an LDR and adjust a leds brightness depending on the amount of light on the LDR
target device: M328
*/

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL

// globals
unsigned char adc_data,level;
volatile unsigned char e ;
volatile unsigned char pwm;

void abc(unsigned char a,unsigned char status)
{
if ((status==a))
{
PORTB&= ~(1<<0);
}
}


//overflow isr timer0
ISR(TIMER0_OVF_vect)
{
if (e==255)
{e=0;
PORTB |= (1<<0);
}

abc(pwm,e);
e++;
}

// this function read the value of ADC channel 0
unsigned char read_adc(void)
{
ADCSRA |= 1<<ADSC; //start conversion;
while (ADCSRA&(1<<ADSC)); //wait conversion end
return ADCH;
}


// main program
int main (void)
{
//Timer Initialisation
TCCR0A = 0x00;
TCCR0B = 0x01;//No Prescaling
TIMSK0=0x01;// unmask Timer 0 overflow interrupt
sei();//Global Interrupts Enabled

//adc init
ADMUX = 0b00100000; // set ADC0
ADCSRA = 0b10000111; //set ADEN, precale by 128
DDRB = 0xFF; //portb for output

while(1)
{
adc_data = read_adc();
level = adc_data;
if (level <(1*255)/5) {
pwm = 255;
} else {if (level <(2*255)/5) {
pwm = 200;
} else {if (level <(3*255)/5) {
pwm = 150;
} else {if (level <(4*255)/5) {
pwm = 100;
} else {if (level <(5*255)/5) {
pwm = 0;
} else {pwm = 0;
}
}
}
}
}
_delay_ms(100);
pwm = 0;
} // end while

} //END MAIN

 

Video

LDRLED from avrprojects.net on Vimeo.


This example code reads the analog value of the LDR and convert it into milliVolts. Then it shows the result on a LCD. 

/*
project name : atm328 - ldr lcd
Version : 1.1
Website : www,avrprojects.net
Date Created : 29.03.2015
Target : ATmega328P microcontroller
Language : C WINAVR
Hardware : LCD display 2*16, ATM328 board
Description : reading analog value of the LDR nad disply it on LCD.
*/

// INCLUDES
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>
#include <lcd.h>

// this function read the value of ADC channel 0
unsigned int read_adc(void)
{
ADCSRA |= 1<<ADSC; //start conversion;
while (ADCSRA&(1<<ADSC)); //wait conversion end
{
return ADCW;
}
}

int main(void)
{
//adc init
ADMUX = 0b00000000; // set ADC0
ADCSRA = 0b10000110; //set ADEN, precale by 64
LCD_init();
LCDgoto(0,0);LCDtext ("LDR Light Sensor");

while(1)
{
unsigned int rawdata = read_adc();
float millivolts= (rawdata/1024.0) * 5000;
LCDgoto(0,1);
if (millivolts < 1000) {
LCDtext(" ");LCDint(millivolts);LCDtext(" mV ");
} else {
LCDint(millivolts);LCDtext(" mV ");
}
if (millivolts < 1250) {
LCDtext("= Dark ");
} else if (millivolts < 2500) {
LCDtext("= Dim ");
} else if (millivolts < 3750) {
LCDtext("= Light ");
} else {
LCDtext("= Bright");
}
_delay_ms(250);
}
}