PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : AtMega8: Phototransistor vom Umgebungslicht unabhängig machen?



teamohnename
18.06.2011, 11:46
Hallo,
vor kurzem bin ich mit meinem ersten richtigen µC Projekt mit einem AtMega8 angefangen. Ziel war es, einen ,,digitalen" Lichtschalter zu bauen. Ich möchte den normalen Lichtschalter aus der Wand ausbauen und meinen einbauen. Bedient wird alles über eine Plexiglasscheibe mit vier IR LEDs und vier Phototransistoren. Ich kann dann z.B. nachher berührungslos das Licht schalten, eventuell sogar mit Gesten (drüber streichen anstatt zu berühren). Bevor das alles gemacht werden kann, muss ich mit den Phototransistoren erkennen, ob sich z.B. meine Hand darüber befindet. Die Lichtwerte ändern sich dann natürlich (ADC funktioniert, schon getestet). Problem ist aber, dass das Umgebungslicht wegen der Sonne (1. Zeitpunkt des Tages und 2. Bedeckter Himmel etc.) stark schwankt. Heute ist der Schwellenwert, um zu erkennen, ob die Hand da ist z.B. 700 und morgen 800. Deshalb muss ich es irgendwie schaffen, das Umgebungslicht zu ignorieren. Ich habe mal gelesen, dass man dazu einmal den Lichtwert mit LED an und einmal den Lichtwert mit LED aus misst, dann die beiden Werte voneinander subtrahieren. So richtig funktioniert das bei mir aber noch nicht. Hier mein Code:

#include <stdlib.h>

#include <avr/io.h>

#include <util/delay.h>



#define F_CPU 8000000UL //CPU Frequenz



/*****************************ENDE USART***************************************/



/********************SYSTEM:*********************** ****************************/

//ADC-Code von Microcontroller.net



uint16_t ADC_Read(uint8_t channel)

{

ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);

ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"

while (ADCSRA & (1<<ADSC) ); // auf Abschluss der Konvertierung warten



return ADCW; // ADC auslesen und zurückgeben

}



void init_ADC()

{

//AD Wandler konfigurieren.

ADMUX = (1<<REFS0); // VCC als Referenz

ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler

ADCSRA |= (1<<ADEN);

}



void init_SYSTEM()

{

//Pins bzw. Ports als Ein-/Ausgänge konfigurieren

DDRB = 0b11111111;

DDRD = 0b11111111;



//Blinken:

for(uint8_t i=4; i<8; i++)

{

PORTD |= (1<<i);

PORTB |= (1<<1);

_delay_ms(50);

}

for(uint8_t i=4; i<8; i++)

{

PORTD &= ~(1<<i);

_delay_ms(50);

}

PORTB &= ~(1<<1);

}

/**************************ENDE SYSTEM*****************************************/



/************************************************** *****************************

**************************### Hauptschleife ###*********************************

************************************************** *****************************/



int main(void)

{

/*###Initialisierungsphase###*/

init_SYSTEM();

init_ADC();

init_USART();



while(1)

{

PORTD |= (1<<2);
//IR LED an
_delay_ms(5);

uint16_t wertLightOn = ADC_Read(0);
//Wert messen
_delay_ms(10);



PORTD &= ~(1<<2);
//IR LED aus
_delay_ms(5);

uint16_t wertLightOff = ADC_Read(0);
Wert messen
_delay_ms(10);



int16_t wert = (wertLightOn-wertLightOff);
//berechnen


if(wert<-20)

{

PORTD |= (1<<4);
//Signal LED an
}

else

{

PORTD &= ~(1<<4);
//Signal LED aus
}


}



return 0;

}
Anscheinend wird etwas erkannt, das aber sehr unzuverlässig. Die Signal LED flackert manchmal, weil irgendetwas unbegründet erkannt wird. Woran liegt das? Anscheinend sind entscheidende Parameter die Werte in den _delay_ms und natürlich der Endwert (,,wert").
Gibt es eventuell noch Alternativen zu meiner Methode (ich glaube, man nennt das Pulsen)?
Vielen Dank für Eure Hilfe schonmal im Vorraus und
Viele Grüße
teamohnename

EDIT: Problem gelöst, ich habe die LED genommen, die diagonal zum FT war, der gemessen hat. Ich habe also nicht den genommen, der unter dem FT ist.
Trotzdem würde es mich interessieren, ob es eine andere (bessere?) Methode gibt. Das funktioniert jetzt schon sehr gut...

BurningWave
18.06.2011, 13:16
Ich habe das bei einer Lichtschranke, die dem Umgebungslicht ziemlich stark ausgesetzt war so gelöst:
Ich habe nach dem Starten des Programms ein paar Referenzwerte gemessen (Lichtschranke nicht unterbrochen) und wusste dann, dass sie bei einer bestimmten Abweichung unterbrochen wurde. Die Veränderungen des Tageslichts ließen sich miteinbeziehen, indem man misst, in welchem Zeitraum sich der gemessene Wert verändert und ggf. neue Referenzwerte misst.

Besserwessi
18.06.2011, 17:06
Die normale Lösung ist es das Licht zu modulieren. Mit den µC kann man dazu jeweils 2 mal messen, einmal ohne LED und einmal mit LED, und dann nur die Differenz zu betrachten.

teamohnename
20.06.2011, 15:02
Hallo,
ich habe das jetzt mit dem Modulieren (Pulsen) gemacht. Das funktioniert auch super, aber es gibt ein etwas größeres Problem: Ich habe auch RGB LEDs da drin, die mit PWM alle Farben mit Übergängen durchgehen. Dieses PWM scheint dem Phototransistor zu stören. Wenn die RGB LEDs an sind, geht die angeschlossene Lampe also an bzw. aus. Ohne die RGB LEDs funktioniert alles perfekt. Wie kann ich das Problem beheben? Ich müsste ja irgendwie die Frequenz vom PWM oder die der IR LED ändern. Einen speziellen IR Empfänger habe ich nicht hier. Was würdet ihr machen?
Danke und
Viele Grüße
teamohnename

Searcher
20.06.2011, 16:11
Was würdet ihr machen?Hallo,
ich würde versuchen die Differenz von zwei lichtempfindlichen Sensoren auszuwerten.

Werden beide Sensoren beschienen, ist die Differenz 0. Egal ob gepulstes oder Tageslicht drauffällt. Bewegt man die Hand über beide Sensoren, wird zunächst ein Sensor abgedunkelt und die Differenz ist nicht mehr 0. Das kann man zum Schalten nutzen.

Ist natürlich noch zu beachten, das man keinen ungewollten Schatten auf die Sensoren bekommt oder eine genügend große Toleranz einstellen.

Gruß
Searcher

teamohnename
20.06.2011, 17:01
Hallo,
gute Idee. Ich habe das Problem jetzt aber gelöst, indem ich doppelt so oft abfrage, das PWm stört jetzt nicht mehr.
Trotzdem danke und
Viele Grüße
teamohnename