PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LED-Sensor am RP6



radbruch
05.04.2008, 00:05
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 (https://www.roboternetz.de/wissen/index.php/Diode#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:

// 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:

// 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:

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