NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Sensors, Actuators, and Robotics » Photoresistors

April 14, 2009
by ranger
ranger's Avatar

Awhile back, my brother gave me his box of misc old/hand-me-down/salvaged parts. Most of it was junk, but I did find a few useful things... including a ton of brand new photoresistors!

I was able to figure out a little by wiring one up like this:

+5v > LED > Photoresistor > GND

...namely that the brighter the light on the photoresistor, the less resistant it becomes.

How can I calculate the resistance on the MCU? I tried modifying the tempsensor code, with no luck... it displays a temp of 499.51 degrees no matter how much light is on it.

April 14, 2009
by wayward
wayward's Avatar

ranger,

while waiting for the Nerdsperts to answer, I will hazard a guess. The ADC works by measuring the relative voltage on the ADCn pin as compared to the voltage on AREF (actually it does "binary guessing" in ten steps). So, you need a way to turn variable resistance into variable voltage.

What I'd try is put a resistor R across AREF and ADC0, and photoresistor Rp across ADC0 and GND. This will form a voltage divider between AREF and GND, with ADC0 picking up the voltage drop across the photoresistor. Depending on the values of R and Rp_max (resistance you measure on the photoresistor in complete darkness), the voltage range you can measure will go from close to 0V (when the photoresistor is illuminated sufficiently) to Vref*Rp/(R+Rp) (in the dark). Obviously this can't go all the way up to Vref, so you'll probably want to choose a sufficiently high value of R, at least an order of magnitude higher than Rp_max.

Photoresistor on ADC

I didn't try it! I wash my hands. :)

Zoran

April 14, 2009
by mikeyw
mikeyw's Avatar

A better circuit would be +5v>10K ohm resistor>photoresistor>GND. then measure the voltage across both the resistor and the photocell. The resistance of the photocell will be porportional to the voltage across it. R1/R2 = V1/V2. You might have to use a 100K ohm resistor or a 1K ohm resistor depending on the photocell. You will also need a high impedence meter for accuracy. The diode(LED) in your circuit has a relatively constant voltage across it regardless of the current going through it. The photodiode therefore has a fairly constant voltage across it too. Only the current will change much. If the processor accepts a 5 Volt input the resistor circuit will read the voltage at the point between the resistor and the photocell and will give you a porportional reading. If it takes 3.3V for the processor then you will need to supply the 3.3V to the circuit to get a correct and porportional reading.

November 13, 2009
by NK_EK
NK_EK's Avatar

Hi!

I'm looking for some advice on a small test project I'm working on: I have three phototransistors connected to the ADC of the ATmega168 (ADC0, ADC1 & ADC2). The transistors are connected as follows: +5V-- R1(1k)-- Node to ADC--Phototransistor---GND (as suggested by mikeyw above and elsewhere on the 'net).

When I connect them individually, they work fine, but as soon as I connect two or all three, the ADC pins seem to get switched around (I know, it sounds fishy, but it's true) - ADC0 becomes ADC1, ADC1 becomes ADC2 and ADC2 becomes ADC0.

It does not seem to be the code, because I use a flashlight to test and they really seem to switch, but I may very well miss something.

Here is my code:

#define F_CPU 14745600

#include <stdio.h>
#include <math.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

void adc_init() {
    // Set ADC (analog to digital converter) 
    // for external reference +5V, single ended input ADC0
    ADMUX = 0;

    // Set ADC to be enabled, with a clock prescale
    // of 1/128 so that the ADC clock runs @ 115.2Khz
    ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);

    // fire a conversion just to get the ADC warmed up
    ADCSRA |= (1<<ADSC);

}

uint16_t adc_read() {

    // read from ADC, waiting for conversion to finish
    // (assumes someone else asked for a conversion).
    // wait for it to be cleared.
    while (ADCSRA & (1<<ADSC)) {
        // do nothing, just hold your breath
    }
    // bit is cleared, so we have a result

    // read from the ADCL / ADCH registers and combine the result
    // NOTE: ADCL must be read first (datasheet p259)
    uint16_t result = ADCL;
    uint16_t temp = ADCH;
    result = result + (temp<<8);

    // set ADSC bit to get the *next* conversion started
    ADCSRA |= (1<<ADSC);

    return result;

}

int main() {

    // Set PC5 as output, low
    PORTC = (0<<PORTC5);
    DDRC = (1<<DDC5);

    // start up the LCD
    lcd_init();
    FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
    lcd_home();

    // start up the ADC
    adc_init();

    // start up the serial port
    uart_init();
    FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
    stdin = stdout = &uart_stream;

    uint16_t a0 = 0;
    uint16_t a1 = 0;
    uint16_t a2 = 0;

    while(1) {

        // Read ADC0
        ADMUX = (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0); // I tried '0', same result
        a0 = adc_read();

        // Read ADC1
        ADMUX = (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (1<<MUX0); // I tried '1', same result
        a1 = adc_read();

        // Read ADC2
        ADMUX = (0<<MUX3) | (0<<MUX2) | (1<<MUX1) | (0<<MUX0); // I tried '2', same result
        a2 = adc_read();

        // switch on LED on PC5
        if (a0 < 100) {
            PORTC = (1<<PORTC5);
        } else {
            PORTC = (0<<PORTC5);
        }

        // write message to LCD
        lcd_line_one();
        // lcd_write_string(PSTR("ADC0: "));
        fprintf_P(&lcd_stream, PSTR("ADC0: %i mV   "), a0);
        lcd_line_two();
        // lcd_write_string(PSTR("ADC1: "));
        fprintf_P(&lcd_stream, PSTR("ADC1: %i mV   "), a1);
        lcd_line_three();
        // lcd_write_string(PSTR("ADC2: "));
        fprintf_P(&lcd_stream, PSTR("ADC2: %i mV   "), a2);

        // write message to serial port
        printf_P(PSTR("adc_read returns: ADC0: %i mV / ADC1: %i mV / ADC3: %i mV\r\n"), a0, a1, a2);

    }

    return 0;

}

BTW, I used Mike's suggestion of reading multiple ADC values here: http://www.nerdkits.com/forum/thread/6/

I'll admit, I'm stuck :-) Everything seems to work, but I need it to work in the right 'order'.

Any help (or even a nudge in the right direction) will be highly appeciated.

Thanks

November 13, 2009
by NK_EK
NK_EK's Avatar

Hi!

Sorry, figured it out (actually had to just read the rest the thread I mentioned :-).

I changed the adc_read function to the following:

uint16_t adc_read() {

    // wait for it to be cleared.
    // set ADSC bit to get the *next* conversion started

    ADCSRA |= (1<<ADSC);

    // read from ADC, waiting for conversion to finish
    // (assumes someone else asked for a conversion).
    while (ADCSRA & (1<<ADSC)) {
        // do nothing, just hold your breath
    }

    // bit is cleared, so we have a result
    // read from the ADCL / ADCH registers and combine the result
    // NOTE: ADCL must be read first (datasheet p259)
    uint16_t result = ADCL;
    uint16_t temp = ADCH;
    result = result + (temp<<8);

    return result;

}

Now everything works and in the right order!

THANKS!

November 15, 2009
by tech20
tech20's Avatar

just for future reference if anyone else spots this, a good link for the wiring of the LDR is on here: Photoresistor Tutorial

December 24, 2009
by BobaMosfet
BobaMosfet's Avatar

You should make a voltage divider when connection your photo-resistor to the ADC. The spec sheet for the photoresistor (photocell or photovoltaic) will tell you what resistance it needs in order to even begin registering light (for example 1K Ohm at 2 foot candles for a CL74PL).

In order for you to get it started at less than that, you need to make it into a voltage divider with the photocell on one side, the 1K (or whatever you require) resistor on the other, and the middle leg (between the two) going to your ADC.

December 24, 2009
by BobaMosfet
BobaMosfet's Avatar
5V O------VVVVV 1K Ohm VVVV------+----CL74PL--------O GND
                                 |
                                ADC

Very straightforward. That way, the instant light hits it, just the slightest, it will start registering it.

Post a Reply

Please log in to post a reply.

Did you know that a thermometer can be made "faster" by using a bit of math? Learn more...