Manchmal ist es gut zu wissen, wie hell es eigentlich ist. Das kann dazu verwendet werden, die Helligkeit von Displayhintergrundbeleuchtungen zu regeln, dass nur soviel Energie verbraucht wird wie nötig, oder um bei Kameras die Belichtungszeit einzustellen oder einfach um Sonnenauf- und -untergang festzustellen. Mit dem Umgebungslichtsensor (ambient light sensor) TSL2550 von ams bzw. früher TAOS kann man das feststellen.
Aufbau
Der TAOS besitzt 2 Fotodioden. Eine davon erfasst Licht im gesamten Wellenlängenbereich inkl. Infrarotbereich. Die zweite erfasst nur den Infrarotbereich. Der zweite Wert kann dann vom ersten vereinfacht gesprochen abgezogen werden und man erhält in etwa die Empfindlichkeit vom menschlichen Auge.
Der Sensor besitzt eine SMBus- bzw. I2C-Schnittstelle mit dem die Werte ausgelesen werden können.
Das Datenblatt zum Sensor gibt es hier:
http://ams.com/eng/Products/Light-Sensors/Ambient-Light-Sensor-ALS/TSL2550
Datenaufbereitung
Der TSL2550 arbeitet intern mit einem 12 bit ADC, liefert die Daten am I2C-Bus aber nur in einem 8 bit Register. Dazu werden intern die 12 bit über ein logarithmische Funktion auf 8 bit gestaucht. Bevor die Werte verwendet werden können, müssen sie wieder auf 12 bit umgerechnet werden.
Im Datenblatt steht dazu folgende Formel:
ADC Count Value + (INT (16.5 (((exp2( C ))*1))) ) (S*(exp2( C )))
Als C-Quellcode schaut das so aus:
adc_0=adc_0&0x7f; // remove valid bit
adc_0_chord=(adc_0&0xf0)>>4;;
adc_0_step=adc_0&0x0f;
adc_0_count=((33*((1<<adc_0_chord)-1))>>1)+(adc_0_step*(1<<adc_0_chord));
Aus den ADC-Werten der beiden Fotodioden, kann dann die Beleuchtungsstärke berechnet werden. Die Formeln vom Datenblatt ergeben dann folgenden Quellcode:
r=(double)adc_1_count/((double)(adc_0_count-adc_1_count));
light_level=(double)(adc_0_count-adc_1_count)*0.39*exp(-0.181*r*r);
Das Ergebnis ist dann die Beleuchtungsstärke in lux.
Aktivierung des Sensors
Nach dem Einschalten befindet sich der Sensor in einem Power-Down-Modus. Bevor Werte ausgelesen werden können, muss er mit einem Schreibzugriff auf das Register 0×18 aktiviert werden.
Programm
Das komplette Programm für den Sensor am I2C-Bus von Raspberry Pi oder Beaglebone Black sieht folgerndermaßen aus:
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <linux/i2c-dev.h> #include <fcntl.h> #include <math.h>
int main(void) { int file; unsigned char x, adc_0, adc_1; int adc_0_chord, adc_0_step, adc_0_count; int adc_1_chord, adc_1_step, adc_1_count; double r, light_level;
printf("ams TSL2550\n"); if((file=open("/dev/i2c-1",O_RDWR))<0) // open i2c-bus { perror("cannot open i2c-1"); exit(1); } if(ioctl(file, I2C_SLAVE, 0x39)<0) // open slave, address TSL2550 = 0x39 { perror("cannot open slave address"); exit(1); } i2c_smbus_write_byte(file,0x18); // power up to standard range mode
x=i2c_smbus_read_byte_data(file, 0x03); // check power up state printf("Power-up state: 0x%02x\n", x); // should be 0x03;
while(!((adc_0=i2c_smbus_read_byte_data(file, 0x43))&0x80)); // read ADC channel 0 until data is valid adc_0=adc_0&0x7f; // remove valid bit adc_0_chord=(adc_0&0xf0)>>4;; adc_0_step=adc_0&0x0f; adc_0_count=((33*((1<<adc_0_chord)-1))>>1)+(adc_0_step*(1<<adc_0_chord)); printf("ADC channel 0: 0x%02x = % 4i\n", adc_0, adc_0_count);
while(!((adc_1=i2c_smbus_read_byte_data(file, 0x83))&0x80)); // read ADC channel 1 until data is valid adc_1=adc_1&0x7f; // remove valid bit adc_1_chord=(adc_1&0xf0)>>4;; adc_1_step=adc_1&0x0f; adc_1_count=((33*((1<<adc_1_chord)-1))>>1)+(adc_1_step*(1<<adc_1_chord)); printf("ADC channel 1: 0x%02x = % 4i\n", adc_1, adc_1_count);
if((adc_0_count-adc_1_count)!=0) { r=(double)adc_1_count/((double)(adc_0_count-adc_1_count)); light_level=(double)(adc_0_count-adc_1_count)*0.39*exp(-0.181*r*r);
printf("R = %f\n", r); printf("Light level = %f lux\n", light_level); }
close(file);
return 0; }
Da hier die math.h Bibliothek verwendet wird, muss beim Compilieren die Option -lm mit angegeben werden.
Kommentare
Kommentarfunktion für diesen Artikel geschlossen.