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...
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...