Hallo RP6-Fans

Zum xten mal ein Versuch eine LED als Helligkeitssensor zu verwenden. Wer das Thema schon gründlich durchgekaut hat wird hier wohl nichts neues lernen.

In einem Artikel habe ich kürzlich gelesen, LEDs haben in Sperrrichtung eine relativ große Kapazität. Dies kann man nutzen, indem man die Entladezeit der LED mißt; sie schwankt durch den Leckstrom welcher lichtabhängig ist. AHA! (Das steht auch im RN-Wissen unter Photodiode)

Das muste ich natürlich gleich mal testen: Eine LED (ohne Vorwiderstand, aber richtig gepolt!) in Sperrrichtung zwischen Pin und GND, den Pin kurz auf Ausgang/High, dann auf Eingang und Spannung einlesen. Zeit messen bis Spannung unter Schwellpegel. Je kürzer desto hell:
Code:
// LED-Sensor Vorbereitung zur Helligkeitsmessung mit einer LED      3.4.2008 mic

// Die Pins ADC0 und ADC1 werden kurz auf High geschaltet, anschließend wird
// mit dem ADC gemessen, wie lange es dauert, bis sie einen eingestellten
// Spannungslevel unterschreiten.

// Zum Testen der LED-Funktion kann man eine LED in Sperrichtung zwischen
// Pin ADC0/1 und GND klemmen

// Mit diesem Programm und mit unbeschalteten ADC0/1 (ich habe bei meinem RP6
// nur Steckerleisten angelötet) reagieren die Pins schon auf eine bloße Annäherung
// mit der Hand oder einem Gegenstand. Diesen Effekt sollte man mal näher untersuchen.

#include "RP6RobotBaseLib.h"

uint16_t count0, count1;

int main(void)
{
	initRobotBase();
	DDRA &= ~3; // Eingang ohne Pullup
	PORTA &= ~3;
	while(1)
	{
		DDRA |= 3; // Ausgang setzen
		PORTA |= 3;
		sleep(20);
		count0=0;
		DDRA &= ~1; // Eingang 0
		PORTA &= ~1; // ohne Pullup
		while(readADC(0) > 500) count0++;
		count1=0;
		DDRA &= ~2; // Eingang 1
		PORTA &= ~2; // ohne Pullup
		while(readADC(1) > 300) count1++;
		writeInteger(count0, 10);
		writeString_P(" - ");
		writeInteger(count1, 10);
		writeString_P("\n\r");
		mSleep(300);
	}
	return(0);
}
Das Progamm mißt die Zeit in Schleifendurchgängen. Je nach angeschlossener LED und Beleuchtung treten bei mir Werte zwischen 30 und 800 auf. Ohne Beschaltung von ADC0 und ADC1 liegt der Wertebereich zwischen 2 und weit über 4000! Und ohne LED reagiert der RP6 auf Annäherung mit der Hand oder einem Gegenstand. Ein sehr interessanter Effekt den man mal untersuchen sollte.

Aber zurück zu Helligkeitsmessung. LEDs messen im Bereich des Abstahlwinkels. Man könnte sie deshalb beim RP6 vielleicht besser zur Peilung verwenden als die eingebauten LDRs. Die einzigen dafür nutzbaren LEDs sind wohl die vom ACS, deshalb gleich mal ein Test mit Bordmitteln:
Code:
// LED-Sensor Die ACS-LEDs werden kurz in Sperrichtung "geladen"    4.4.2008 mic
// und dann wird die Entladezeit gemessen. (Kathode gegen 5V geschaltet)

#include "RP6RobotBaseLib.h"

int main(void)
{
	initRobotBase();

// Beide ACS-LEDs allpollig auf GND legen
 	DDRB |= ACS_PWRH | ACS_L;						// Pins als Ausgang
	DDRC |= ACS_R;
	DDRD |= ACS_PWR;
	PORTB &= ~(ACS_PWRH | ACS_L);					// alle auf GND
	PORTC &= ~ACS_R;
	PORTD &= ~ACS_PWR;
	while(1)
	{

		DDRB |= ACS_L;                        	// Kathoden als Ausgang
		DDRC |= ACS_R;
		PORTB |= ACS_L;                   		// Kathoden gegen 5V schalten
		PORTC |= ACS_R;
		sleep(10);                             // Kurz warten und Stoppuhren starten
		setStopwatch1(0);
		setStopwatch2(0);
		startStopwatch1();
		startStopwatch2();
		DDRB &= ~ACS_L;                        // Kathoden als Eingang
		DDRC &= ~ACS_R;
		PORTB &= ~ACS_L;                  		// PullUps aus
		PORTC &= ~ACS_R;
// Entladung messen
		while((PINB & ACS_L) || (PINC & ACS_R))
		{
			if(!(PINB & ACS_L)) stopStopwatch1();
			if(!(PINC & ACS_R)) stopStopwatch2();
		}
		stopStopwatch1();                      // sicher ist sicher!
		stopStopwatch2();
// Debug
		writeInteger(getStopwatch1(), 10);
		writeString_P(" - ");
		writeInteger(getStopwatch2(), 10);
		writeString_P("\n\r");
		//mSleep(300);                         // weniger hecktisch :)
	}
	return(0);
}
Das funktioniert schon mal prima, bei "Hell" werden Werte unter 10 gemessen, "Dunkel" bis zu 2000. 2000ms! Total lahm. Das liegt daran, das ich hier einen normalen Pin ohne ADC verwende. Es wird die Zeit gemessen, nach der der Pin wieder Low wird. Da die Pegel für Low- und High-Erkennung nicht identisch sind, bringt folgendes Programm eine Besserung:
Code:
// LED-Sensor Die ACS-LEDs werden kurz in Sperrichtung "geladen"    4.4.2008 mic
// und dann wird die Entladezeit gemessen. (Anode gegen GND geschaltet)

#include "RP6RobotBaseLib.h"

int main(void)
{
	initRobotBase();

// Beide ACS-LEDs allpollig auf 5V legen
 	DDRB |= ACS_PWRH | ACS_L;						// Pins als Ausgang
	DDRC |= ACS_R;
	DDRD |= ACS_PWR;
	PORTB |= (ACS_PWRH | ACS_L);					// alle auf 5V
	PORTC |= ACS_R;
	PORTD |= ACS_PWR;
	while(1)
	{

		DDRD |= ACS_PWR;                       // Pins als Ausgang
		DDRB |= ACS_PWRH;
		PORTD &= ~ACS_PWR;                     // Anoden gegen GND schalten
		PORTB &= ~ACS_PWRH;
		sleep(10);                             // Kurz warten und Stopuhren starten
		setStopwatch1(0);
		setStopwatch2(0);
		startStopwatch1();
		startStopwatch2();
		DDRD &= ~ACS_PWR;                  		// Anoden als Eingang
		DDRB &= ~ACS_PWRH;
// Entladung messen
		while((!(PIND & ACS_PWR)) || (!(PINB & ACS_PWRH)))
		{
			if(PIND & ACS_PWR) stopStopwatch1();
			if(PINB & ACS_PWRH) stopStopwatch2();
		}
		stopStopwatch1();                      // sicher ist sicher!
		stopStopwatch2();
// Debug
		writeInteger(getStopwatch1(), 10);
		writeString_P(" - ");
		writeInteger(getStopwatch2(), 10);
		writeString_P("\n\r");
		mSleep(300);
	}
	return(0);
}
Hier wird nicht Vcc geschaltet sondern GND. Gemessen wird die Zeit, nach der wieder High anliegt und erzeugt werden Werte von ca. 2-200. Allerdings wird dabei nicht seitenunabhängig ausgewertet weil die PWR-Leitungen beider ACS-LEDs verbunden sind. Die unterschiedlichen Werte kommen von den PWR-Vorwiderständen (R8/9, 1k5/2k2). (Wenn man zusätzlich die PullUps als Entladewiderstand verwendet ist die Zeit == 0 ;)

Gruß

mic