Programming atmega to control led using SFH309 phototransistor

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

this are my coding...can anyone help me find the error in my programme or maybe help me solve on how to use adc interupt cause im not really sure that mines working.. Im using the ATmega328 as the controller. my phototransistor is connected to PC0 and and my LED is connected to PB2. As i put IR in front of the sensor, my led doesnt even show any response. I have double checked the wiring and even confirm that both phototransistor and LED are working fine using simple coding to test out. Btw, im programming it using the atmel studio 7.0.

 

 

#include <avr/io.h>

#include <avr/interrupt.h>

 

void setup_timer1(void)

{

DDRC |= (1<<DDC0);

TCCR1B = (1<<CS12)|(1<<CS10);

TCCR1A = (1<<COM1B1);

OCR1B = 65;

}

void setup_adc(void)

{

ADMUX = (1<<ADLAR);

ADCSRA =(1<<ADEN)|(1<<ADIE)|(1<<ADSC)|(1<<ADPS1)|(1<<ADPS0);

ADCSRB = 0;

}

 

ISR(ADC_vect)

{

OCR1B=250-ADCH;

}

int main(void)

{

DDRB |= (1<<PB2);

setup_timer1();

setup_adc();

sei();

while(1)

{

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please post your code using the code "<>" icon above, and show us your schematic too. 

Why do you need an ADC interrupt?

 

 

Jim

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:
Please post your code using the code "<>" icon above, and show us your schematic too

 

Full, illustrated instructions here: http://www.avrfreaks.net/comment...

 

Note that the ATmega328 has on-chip debug - have you used it to step through your code?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

Please post your code using the code "<>" icon above, and show us your schematic too. 

Why do you need an ADC interrupt?

 

 

Jim

 

 

 

actually i have been using attiny85 before to test out the same coding with their perspective registors and its working fine.. but now i just using same coding and try it out using the atrmega..as i want to intergrate the photoransistor with servo motor to detect Ir and replace the led with a laser module so that i can shoot the IR target. but i am not sure wether my register is correct with the connection that i have done.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

ki0bk wrote:
Please post your code using the code "<>" icon above, and show us your schematic too

 

Full, illustrated instructions here: http://www.avrfreaks.net/comment...

 

Note that the ATmega328 has on-chip debug - have you used it to step through your code?

 

 

i replaced the Led with the laser module..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

ki0bk wrote:
Please post your code using the code "<>" icon above, and show us your schematic too

 

Full, illustrated instructions here: http://www.avrfreaks.net/comment...

 

Note that the ATmega328 has on-chip debug - have you used it to step through your code?

 

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

void setup_timer1(void)
{
	DDRC |= (1<<DDC0);
	TCCR1B = (1<<CS12)|(1<<CS10);
	TCCR1A = (1<<COM1B1);
	OCR1B = 65;
}
void setup_adc(void)
{
	ADMUX = (1<<ADLAR);
	ADCSRA =(1<<ADEN)|(1<<ADIE)|(1<<ADSC)|(1<<ADPS1)|(1<<ADPS0);
	ADCSRB = 0;
}
ISR(ADC_vect)
{
	OCR1B=250-ADCH;
}
int main(void)
{
    DDRB |= (1<<PB2);
	setup_timer1();
	setup_adc();
	sei();
	while(1)
	{
		
	}
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A good habit to get into is to put comments in your code., even for short 'test' programs.


1) 470 ohms seems to me to be a very low value for most photo-transistors., try something in the 10k to 100k ohm range.
2) Only one ADC conversion will be performed because a) you do not initiate another conversion, or b) you are not in 'free-running mode' with Auto trigger enabled (ADATE).
3) You select AREF for the ADC reference (ADMUX : REFS0=0, REFS1=0), but your schematic does not show that AREF is connected.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A photo transistor may respond as fast as your PWM. So, depending on when you read the photo transistor, it MAY always read 100% on or 100% off.  In this regard, the photo transistor is not like your eye. An averaging capacitor across the 470 may be in order.

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) 470 ohms seems to me to be a very low value for most photo-transistors., try something in the 10k to 100k ohm range.

Thanks for the reply Mikech

 

For the resistor value, the datasheet for the SFH309 phototransistor specifies 75mA for the collector surge current. Since the voltage supply is 5V, the resistor value was calculated to be V/I -> 5V/0.075mA = 67 Ohms. However I am using the closest resistor value I can get find which was 68 ohm. Is this fine?

2) Only one ADC conversion will be performed because a) you do not initiate another conversion, or b) you are not in 'free-running mode' with Auto trigger enabled (ADATE).

Thanks, I have now set ADATE to enable auto trigger, as it is using free running mode.

3) You select AREF for the ADC reference (ADMUX : REFS0=0, REFS1=0), but your schematic does not show that AREF is connected.

The AREF is connected to the 5V power supply. I have updated the schematic. I have set  REFS0=1, REFS1=0 to select AVcc with external capacitor at AREF pin.

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


void setup_timer1(void)
{
	DDRC |= (1<<DDC0); //set pin PINC0 to input
	TCCR0A = (1<<COM0B1)|(1<<WGM00);
	TCCR0B = (1<<CS02)|(1<<CS01); //Using 8 bit timer, select clock source
	
	/*TIFR0  = 0b00000100;*/
	/*GTCCR = (1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC);*/
	OCR0B = 65; //set the compare value
	/*TIMSK0 = 0b00000100;*/
}

void setup_adc(void)
{
	ADMUX = (1<<ADLAR)|(1<<REFS0); //set prescaler REFS0 and store result of ADC conversion (ADLAR)
	ADCSRA =(1<<ADEN)|(1<<ADIE)|(1<<ADSC)|(1<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
	ADCSRB = 0; //free running mode
}
ISR(ADC_vect)
{
	OCR0B=(255-ADCH);
}
int main(void)
 {
	DDRD |= (1<<5); //set PORTD as output
	setup_timer1(); //initialize timer and ADC 
	setup_adc();
	sei(); // turn on global interrupts
// 	while(1)
// 	{
// 		
// 	}
	/* DDRD |= (1<<5); //makes PORTD5 as Output*/
	 DDRC &= ~(1<<0);
	 while(1) //infinite loop
	 {  
		 
		 if(PINB |= (1<<0)) //read PINB0(phototransistor),if its detecting IR then move into loop
		 {
		 PORTD = (1<<5); //Turns ON All LEDs
		 _delay_ms(1000); //1 second delay
		 }
		 else
		 {
		 PORTD &= ~(1<<5); //Turns OFF All LEDs
		 _delay_ms(1000); //1 second delay
		 }
	 }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

phototransistor specifies 75mA for the collector surge current

that is Absolute Maximum Rating.  The datasheet says 400-5000 uA so use that for your calculation. 

 

David 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks David! I switched to a 10k resistor.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mike coentrao wrote:
specifies 75mA for the collector surge current.

It does indeed - but that's an "absolute maximum" not a measure of sensitivity.

 

The photo-current (Ee = 0.5 mW/cm2 , VCE = 5V) you should be working on depends on the sensitivity grading of the device and is around 1mA or so.

I used a 2K2 resistor which balanced O/P voltage sensitivity versus rise time for my application.

 

{Edit for Spelling and note to self: "Must type even quicker"}

Last Edited: Wed. Sep 6, 2017 - 08:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
DDRC |= (1<<DDC0); //set pin PINC0 to input

But this sets the pin as output!

 

Try to write the code according to this pseudocode.

 

// Intensity of Led on portb.2 is controlled with ADC0 voltage

#include <avr/io.h>

uint8_t adc_value;

uint8_t get_adc0(void)
{
   //1. start conversion (ADSC = 1)
   //2. wait for conversion finished (wait until ADSC = 0)
   //3. return ADCH
}

               
int main(void)
{
   // init ports
   //1. set pin OC1B as output (pwm1b output)       
   //2. set pin ADC0 as input  (adc input)

   // init timer1
   //1. set timer1 in mode 5 (fast pwm 8-bit, as we use 8-bit adc)  
   //   mode is set with bits WGM10...WGM13, see table "Waveform generation mode bit description"
   //2. set bit COM1B1 - noninverted pwm on OC1B, see table "Compare output mode, fast PWM"
   //3. set prescaler
   

   // init ADC
   //1. enable ADC (bit ADEN) and set prescaler (bits ADPSx)
   //2. set reference voltage to AVCC - bits REFS1, REFS0
   //3. set 8-bit adc  (ADLAR = 1)
   //4. choose channel ADC0 - bits MUX0...MUX3


   while(1)
   {
      //1. read adc0  (adc_value = get_adc0;)
      //2. set OCR1A value (to the adc_value or 256-adc_value)  
   }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mikech wrote:
A good habit to get into is to put comments in your code., even for short 'test' programs.

Absolutely!!

 

Especially when you're expecting others to help you with your code.

 

See: http://www.avrfreaks.net/comment...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use a phototransistor as an ambient light sensor for a small demo prototype some time ago.  The one thing you might not realise is that a photostransistor can/will conduct with background lighting depending on it's sensitivity, and it certainly will conduct with sunlight.

 

If you have a DMM(Digital Multi Meter) or an AMM(Analog Multi Meter) read the voltage on the collector of the phototransistor with normal room light based on your ADC setup you can then figure out what the ADC reading value should be.  It could be that it's pegged at one specific spot.

 

Do the same test with your light source and see what you get.  It could be that the differences are too small to make a difference.

 

Question:  Are you looking for simple detection i.e. On/Off, or are you looking to measure the actual light intensity?  If simple On/Off, you might want to look at possibly just using an I/O pin and poll that.  Modify your collector resistor accordingly to get the desired result.

 

If you want to measure actual light levels, then I would suggest adding an Op-amp to the circuit to scale the transistor output accordingly.  I would have to look, but I think I set up my Op-amp as a difference amplifier in my ambient light sensor.  Worked like a champ and it fed the ADC which fed the PWM like you are doing.

 

Can you post a spec sheet for the phototransistor?  Also can you post EXACTLY what it is you are trying to do?  In one instance you mention an LED, and in another a laser module.

 

 

 

Jim

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks again. I followed the pseudocode you provided, and followed your recommendations, however I am not receiving any feedback from the LED/Laser :( I have checked the datasheet and I cannot figure out what is wrong. I was able to get it working on an ATtiny85, using the same pseudocode with the appropriate changes according the datasheet. The error seems to be regarding the sensor, however I am lost as to why is does not work. Here is the code I made from the pseudocode:


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


uint8_t adc_value;

uint8_t get_adc0(void)
{
	ADCSRA = (1<<ADSC);//1. start conversion (ADSC = 1)
	while(ADCSRA & (1<<ADSC)){
	//2. wait for conversion finished (wait until ADSC = 0)
	}
	return ADCH;//3. return ADCH
}


int main(void){
	
	// init ports
	DDRB = 0xFF;//1. set pin OC1B as output (pwm1b output)
	DDRC = 0x00;//2. set pin ADC0 as input  (adc input)
	
	// init timer1 -> can be put in a intialise function later
	TCCR1A = (1<<WGM10); // set fast bit 8bit PWM
	TCCR1B = (1<<WGM12);//1. set timer1 in mode 5 (fast pwm 8-bit, as we use 8-bit adc) TCCR1A
	//   mode is set with bits WGM10...WGM13, see table "Waveform generation mode bit description"
	TCCR1A = (1<<COM1A1);//2. set bit COM1B1 - noninverted pwm on OC1B, see table "Compare output mode, fast PWM"
	//TCCR1B = (1<<COM1B1);
	TCCR1B = (1<<CS10);//3. set prescaler -> using a MCU speed of 125kHz so set the prescaler to be zero 1:1 ratio
	

	// init ADC
	ADCSRA = (1<<ADEN) | (1<<ADPS0);//1. enable ADC (bit ADEN) and set prescaler (bits ADPSx) -> set prescaler 0.
	//ADMUX = ~(1<<REFS1) | ~(1<<REFS0);//2. set reference voltage to AVCC - bits REFS1, REFS0 -> set as zero. AREF connected, internal Vref off. IN ADMUX
	ADMUX = (1<<ADLAR);//3. set 8-bit adc  (ADLAR = 1) in ADMUX
	//ADMUX = ~(1<<MUX0) | ~(1<<MUX3) | ~(1<<MUX2) | ~(1<<MUX2);//4. choose channel ADC0 - bits MUX0...MUX3 -> keep at zero for ADC0 *****updated this,where before these bits were set in ADCSRA*****
	

	while(1) // forever continue reading the adc and outputting to the LED. 
	{
		adc_value = get_adc0();//1. read adc0  (adc_value = get_adc0;)
		OCR1A = 255-adc_value;//adc_value;//2. set OCR1A value (to the adc_value or 255-adc_value)
	}
}
/*General notes:

The MCU runs on 125k Hz by default. Thus a prescaler of 1 is used throughout, as this will get the closest value to 200kHz which
is the maximum recommended and will produce the fasted prescaler. (125k)^-1 gives 8us clock tick. In a 16 bit register:
63535 * (8e-6) = 0.52428s
This gives a max duration of 0.52428 seconds for the 16 bit register. 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You should show your complete schematic used for testing.
.
What do you mean MCU runs on 125khz by default? I don't get it.
.

mike coentrao wrote:
i want to intergrate the photoransistor with servo motor to detect Ir and replace the led with a laser module so that i can shoot the IR target.

Why you need adc for that?
.
MG

I don't know why I'm still doing this hobby