Tsl230r Sensor
Tsl230r Sensor
CONEXIONES
// output frequency. 1000 milliseconds == 1 second. FreqCount.begin(1000); } void loop() { unsigned long f = 0; if (FreqCount.available()) { // Read the counts per second multiply by fscale to get the // actual frequency. f = fscale*(FreqCount.read()); Serial.print(f); Serial.print("\n"); delay(20); } }
Liberia .cpp
/* FreqCount Library, for measuring frequencies * http://www.pjrc.com/teensy/td_libs_FreqCount.html * Copyright (c) 2011 PJRC.COM, LLC - Paul Stoffregen <[email protected]> * Version 1.0 * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "FreqCount.h" #include "util/timers.h" static uint16_t count_msw; static uint32_t count_prev; static volatile uint32_t count_output; static volatile uint8_t count_ready;
static uint16_t gate_length; static uint16_t gate_index; void FreqCountClass::begin(uint16_t msec) { if (msec < 10) return; gate_index = 0; count_msw = 0; count_prev = 0; count_ready = 0; counter_init(); gate_length = timer_init(msec); uint8_t status = SREG; cli(); timer_start(); timer_isr_latency_delay(); counter_start(); SREG = status; } uint8_t FreqCountClass::available(void) { return count_ready; } uint32_t FreqCountClass::read(void) { uint32_t count; uint8_t status; status = SREG; cli(); count = count_output; count_ready = 0;
SREG = status; return count; } void FreqCountClass::end(void) { timer_shutdown(); counter_shutdown(); } ISR(TIMER_ISR_VECTOR) { uint16_t count_lsw; uint32_t count; uint16_t index, length; count_lsw = counter_read(); if (counter_overflow()) { counter_overflow_reset(); count_msw++; } index = gate_index + 1; length = gate_length; if (index >= length) { gate_index = 0; count = ((uint32_t)count_msw << 16) + count_lsw; count_output = count - count_prev; count_prev = count; count_ready = 1; restore_other_interrupts(); } else { if (index == length - 1) disable_other_interrupts(); gate_index = index;
} } FreqCountClass FreqCount;
Liberia .h
#ifndef FreqCount_h #define FreqCount_h #include <inttypes.h> class FreqCountClass { public: static void begin(uint16_t msec); static uint8_t available(void); static uint32_t read(void); static void end(void); }; extern FreqCountClass FreqCount; #endif
// 1000ms = 1s #define READ_TM 1000 // our pulse counter for our interrupt unsigned long pulse_cnt = 0; void add_pulse() { // increase pulse count pulse_cnt++; return; } // two variables used to track time unsigned long cur_tm = millis(); unsigned long pre_tm = cur_tm; // we'll need to access the amount // of time passed unsigned int tm_diff = 0; // set our frequency multiplier to a default of 1 // which maps to output frequency scaling of 100x int freq_mult = 100; // need to measure what to divide freq by // 1x sensitivity = 10, // 10x sens = 100, // 100x sens = 1000 int calc_sensitivity = 10; void setup() { Serial.begin(9600); // attach interrupt to pin2, // send output pin of TSL230R to arduino 2 // call handler on each rising pulse attachInterrupt(0, add_pulse, RISING); // setup TSL230R pins
pinMode(TSL_FREQ_PIN, INPUT); pinMode(TSL_S0, OUTPUT); pinMode(TSL_S1, OUTPUT); pinMode(TSL_S2, OUTPUT); pinMode(TSL_S3, OUTPUT); // 1x sensitivity, // divide-by-100 scaling digitalWrite(TSL_S0, HIGH); digitalWrite(TSL_S1, LOW); digitalWrite(TSL_S2, HIGH); digitalWrite(TSL_S3, HIGH); } void loop() { // check the value of the light sensor every READ_TM ms // calculate how much time has passed pre_tm = cur_tm; cur_tm = millis(); if( cur_tm > pre_tm ) { tm_diff += cur_tm - pre_tm; } else if( cur_tm < pre_tm ) { // handle overflow and rollover (Arduino 011) tm_diff += ( cur_tm + ( 34359737 - pre_tm )); } // if enough time has passed to // do a new reading... if( tm_diff >= READ_TM ) { // re-set the ms counter tm_diff = 0; // get our current frequency reading
unsigned long frequency = get_tsl_freq(); // calculate radiant energy float uw_cm2 = calc_uwatt_cm2( frequency ); // calculate illuminance float lux = calc_lux_single( uw_cm2, 0.175 ); float lux_gauss = calc_lux_gauss( uw_cm2 ); Serial.print("Freq "); Serial.print(frequency); Serial.println(" Hz"); Serial.print("Engy "); Serial.print(uw_cm2); Serial.println(" uW/cm2"); Serial.print("LuxS "); Serial.println(lux); Serial.print("LuxG "); Serial.println(lux_gauss); Serial.println(""); } } unsigned long get_tsl_freq() { // we have to scale out the frequency -// Scaling on the TSL230R requires us to multiply by a factor // to get actual frequency unsigned long freq = pulse_cnt * freq_mult; // reset the pulse counter pulse_cnt = 0; return(freq); } float calc_lux_single(float uw_cm2, float efficiency) { // calculate lux (lm/m^2), using standard formula:
// Xv = Xl * V(l) * Km // Xl is W/m^2 (calculate actual receied uW/cm^2, extrapolate from sensor size (0.0136cm^2) // to whole cm size, then convert uW to W) // V(l) = efficiency function (provided via argument) // Km = constant, lm/W @ 555nm = 683 (555nm has efficiency function of nearly 1.0) // // Only a single wavelength is calculated - you'd better make sure that your // source is of a single wavelength... Otherwise, you should be using // calc_lux_gauss() for multiple wavelengths // convert to w_m2 float w_m2 = (uw_cm2 / (float) 1000000) * (float) 100; // calculate lux float lux = w_m2 * efficiency * (float) 683; return(lux); } float calc_uwatt_cm2(unsigned long freq) { // get uW observed - assume 640nm wavelength // calc_sensitivity is our divide-by to map to a given signal strength // for a given sensitivity (each level of greater sensitivity reduces the signal // (uW) by a factor of 10) float uw_cm2 = (float) freq / (float) calc_sensitivity; // extrapolate into entire cm2 area uw_cm2 *= ( (float) 1 / (float) 0.0136 ); return(uw_cm2); } void set_scaling ( int what ) { // set output frequency scaling // adjust frequency multiplier and set proper pin values // e.g.: // scale = 2 == freq_mult = 2
// scale = 10 == freq_mult = 10 // scale = 100 == freq_mult = 100 int pin_2 = HIGH; int pin_3 = HIGH; switch( what ) { case 2: pin_3 = LOW; freq_mult = 2; break; case 10: pin_2 = LOW; freq_mult = 10; break; case 100: freq_mult = 100; break; default: // don't do anything with levels // we don't recognize return; } // set the pins to their appropriate levels digitalWrite(TSL_S2, pin_2); digitalWrite(TSL_S3, pin_3); return; } void sensitivity( bool dir ) { // adjust sensitivity in 3 steps of 10x either direction int pin_0; int pin_1;
if( dir == true ) { // increasing sensitivity // -- already as high as we can get if( calc_sensitivity == 1000 ) return; if( calc_sensitivity == 100 ) { // move up to max sensitivity pin_0 = HIGH; pin_1 = HIGH; } else { // move up to med. sesitivity pin_0 = LOW; pin_1 = HIGH; } // increase sensitivity divider calc_sensitivity *= 10; } else { // reducing sensitivity // already at lowest setting if( calc_sensitivity == 10 ) return; if( calc_sensitivity == 100 ) { // move to lowest setting pin_0 = HIGH; pin_1 = LOW; } else { // move to medium sensitivity
pin_0 = LOW; pin_1 = HIGH; } // reduce sensitivity divider calc_sensitivity = calc_sensitivity / 10; } // make any necessary changes to pin states digitalWrite(TSL_S0, pin_0); digitalWrite(TSL_S1, pin_1); return; } float calc_ev( float lux, int iso ) { // calculate EV using APEX method: // Ev = Av + Tv = Bv + Sv // We'll use the right-hand side for this operation // Bv = log2( B/NK ) // Sv = log2( NSx ) float Sv = log( (float) 0.3 * (float) iso ) / log(2); float Bv = log( lux / ( (float) 0.3 * (float) 14 ) ) / log(2); return( Bv + Sv ); } float calc_exp_tm ( float ev, float aperture ) { // Ev = Av + Tv = Bv + Sv // need to determine Tv value, so Ev - Av = Tv // Av = log2(Aperture^2) // Tv = log2( 1/T ) = log2(T) = 2^(Ev - Av) float exp_tm = ev - ( log( pow(aperture, 2) ) / log(2) ); float exp_log = pow(2, exp_tm); return( exp_log ); }
unsigned int calc_exp_ms( float exp_tm ) { unsigned int cur_exp_tm = 0; // calculate mS of exposure, given a divisor exposure time if( exp_tm >= 2 ) { // deal with times less than or equal to half a second if( exp_tm >= (float) int(exp_tm) + (float) 0.5 ) { // round up exp_tm = int(exp_tm) + 1; } else { // round down exp_tm = int(exp_tm); } cur_exp_tm = 1000 / exp_tm; } else if( exp_tm >= 1 ) { // deal with times larger than 1/2 second float disp_v = 1 / exp_tm; // get first significant digit disp_v = int( disp_v * 10 );
cur_exp_tm = ( 1000 * disp_v ) / 10; } else { // times larger than 1 second int disp_v = int( (float) 1 / exp_tm); cur_exp_tm = 1000 * disp_v; } return(cur_exp_tm); } float calc_exp_aperture( float ev, float exp_tm ) {
float exp_apt = ev - ( log( (float) 1 / exp_tm ) / log(2) ); float apt_log = pow(2, exp_apt); return( apt_log ); } // our wavelengths (nm) we're willing to calculate illuminance for (lambda) int wavelengths[18] = { 380, 400, 420, 440, 460, 480, 500, 520, 540, 560, 580, 600, 620, 640, 660, 680, 700, 720 }; // the CIE V(l) for photopic vision - CIE Vm(l) 1978 - mapping to the same (l) above float v_lambda[18] = { 0.0002, 0.0028, 0.0175, 0.0379, 0.06, 0.13902, 0.323, 0.71, 0.954, 0.995, 0.87, 0.631, 0.381, 0.175, 0.061, 0.017, 0.004102, 0.001047 }; // CIE SPD graph for Illuminant A light sources, again mapping to same lambda as included in wavelengths float ilA_spd[18] = { 9.795100, 14.708000, 20.995000, 28.702700, 37.812100, 48.242300, 59.861100, 72.495900, 85.947000, 100.000000, 114.436000, 129.043000, 143.618000, 157.979000, 171.963000, 185.429000, 198.261000, 210.365000 }; float calc_lux_gauss( float uw_cm2 ) { // # of wavelengths mapped to V(l) values - better have // enough V(l) values! int nm_cnt = sizeof(wavelengths) / sizeof(int); // W/m2 from uW/cm2 float w_m2 = ( uw_cm2 / (float) 1000000 ) * (float) 100; float result = 0; // integrate XlV(l) dl // Xl = uW-m2-nm caclulation weighted by the CIE lookup for the given light // temp // V(l) = standard luminous efficiency function for( int i = 0; i < nm_cnt; i++) { if( i > 0) { result += ( ilA_spd[i] / (float) 1000000) * (wavelengths[i] - wavelengths[i - 1]) * w_m2 * v_lambda[i]; } else { result += ( ilA_spd[i] / (float) 1000000) * wavelengths[i] * w_m2 * v_lambda[i];