Read PWM light signal with TSL250 sensor only when PWM is high

Hi,
I am having trouble reading light intensity with a TAOS light-to-voltage sensor, TSL250r-LF http://www.taosinc.com/getfile.aspx?type=press&file=tsl250r-e30.pdf. The light source that is being measured is an RGB LED controlled by PWM pins 9 (red), 10 (green) and 11 (blue) on an Arduino Mega 2560 board.

The board takes readings from two TSL250 sensors every second, and sends data to serial out. Because the LED is either on or off, depending on the PWM signal duty cycle, the reading from the sensor is a mixture of high and low numbers. When the PWM is set to dim light, the numbers are mostly 0’s and a few 1021 (and some random number in-between). When the LED is set to bright light, the numbers are mostly 1021 and a few 0’s.

I need the readings to be very steady. The project is a photometer that measures light absorbance.

I know there are ways to smooth the PWM to DC using hardware such as a DAC. It would be nice if a change in the software would resolve the issue.

My question: Would it fix this issue to have the light sensor take a reading only when the PWM signal is high? The frequency is about 500 hz, so the PWM signal changes to high every 2 msec.

The code is below. I deleted most of the non-relevant parts. The lines that trigger the sensor readings are:

// read the analog in values from the 2 sensors:
sensorValue = analogRead(analogInPin);
sensorValue1 = analogRead(analogInPin1);

Could I use an attachInterrupt somehow to delay running these lines until the LED is powered? Or is there a better way?

It would be ideal to be able to control all three LEDs independently. Are the PWM signals synchronous, so just one pin needs to be monitored for changes in PWM to high?

Thanks, DW :slight_smile:

[code]/*
 
 // Assign constants
 const int analogInPin = A0;  // Analog input pin that is attached to first light 2 voltage sensor
 const int analogInPin1 = A1;  // Analog input pin that is attached to second light 2 voltage sensor
 int adjustment = 2;
 int sensorValue = 0;        // value read from sensor 0
 int sensorValue1 = 0;        // value read from sensor 1
 int outputValue = 0;        // map output 0-1023 to 5000 mV, store in outputValue
 int outputValue1 = 0;        // map output 0-1023 to 5000 mV, store in outputValue1

 //For RGB common anode LED
 const int redPin = 9; //LED lead 1, looking left to rt
 const int greenPin = 10;  //lead 3 left to rt
 const int bluePin = 11;  //lead 4 left to rt
 int powerPin = 0; // current pin to be powered
 int brightnessRGB = 0; // brightness level

 //Keep track of time
 unsigned long count = 0;  // Counts the number of seconds since the sketch started
 
 void setup() {
  // Set the LED pins as outputs:
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
   
  Serial.begin(9600); 
  Serial.println("Enter color (R, G or B) and brightness (0 to 9). r5g0b0 for red, etc");

  delay(2000);
}

void loop() {
 //Control of RGB LED 
  if (Serial.available() >0)  //Serial.available >0, or "true", if text is entered in serial monitor
  {  //Watch for input text. If input present, start reading with while loop
    Serial.println();
    Serial.print("  ***   New RGB Setting: ");
    while (Serial.available() >0) 
    { //while loop 1. Reads one character at a time
      //Serial.available >0, or "true", until the end of the input text is reached
      //Serial.available = 0, or "false", after all text is read
      int RGBinByte = Serial.read();  //Copy the text in Serial.read into RGBinByte
      //Now use Serial.write to echo the input. 
      //It prints or echos one character with each pass of the while loop.
     Serial.write(RGBinByte); //Serial print r g b 
      // Respond to the values 'r' or 'R', etc
      if (RGBinByte == 'r'||RGBinByte == 'R') {
        powerPin = redPin; 
      }
      if (RGBinByte == 'g'||RGBinByte == 'G') {
        powerPin = greenPin;
      }
      if (RGBinByte == 'b'||RGBinByte == 'B') {
        powerPin = bluePin;
      } 
      //The LED pin has been chosen at this point, now set power level
      if (RGBinByte >= '0' && RGBinByte <= '9') {
      
        //Map the incoming byte value (0-9) to the range of the analogRead() command (0-255):
        //Reverse of normal mapping because high voltage from PWM pin blocks current flow, causing low light level. 
        brightnessRGB = map(RGBinByte, '9', '0', 0, 255);  //common anode, so high value yields low light
        
        //print brightness
        Serial.print("  ");
        Serial.print(255-brightnessRGB);
        Serial.print(" * ");
        
        //Set the current pin to the current brightness:
        analogWrite(powerPin, brightnessRGB); //Eg, input b9 will power blue LED to max level
      } //Exit if statement
      
    }   //End of while loop 1

    //If-statement flows here after all input has been read-in and echoed by while loop
  }  //Exit if (Serial.available) loop 
  
  // read the analog in values from the 2 sensors:
  sensorValue = analogRead(analogInPin);       
  sensorValue1 = analogRead(analogInPin1);     
  
  Serial.print(sensorValue);
  Serial.print("\t  "); 
  Serial.print("\t sensor 1 = ");      
  Serial.print(sensorValue1);  
  Serial.print("\t  "); 

  count++; // Increment the count of the number of seconds. 
  }   
  delay(1000);                     
}

[/code]

Do you always have to measure that RGB LED with your project? In this case the sensor you used isn't able to give you correct results because it's to slow (it needs about 0.3ms for a rise/fall, with a 500Hz PWM signal you'll get a resolution of about 3 bits at best). Use a simple photodiode which is much faster and measure the time the signal is on and off, then calculate the duty time and you'll get the intensity the eye sees.

If you always measured the light when the LED was fully on would you not always get the same reading irrespective of the PWM settings?

It looks to me like you want a longer integration time on your sensor, so a simple RC filter between the sensor and the analogue input should fit the bill.

Hi Grumpy_Mike and Pylon, Thank you for the very helpful feedback. I added an RC filter. Here are my notes: http://www.instructables.com/id/Arduino-RC-Circuit-PWM-to-analog-DC/. I also tried a double RC filter. Both the single and double RC filters worked well, but still to much jiggle for my purposes. Adding a smoothing algorithm with running averages helped, but did not solve the problem. Measuring the light output, the numbers had a slight variation over time - less than 1%, good but not rock steady.

I think I'll try to control LEDs directly with a digital pot, as in this Tom Igoe tutorial: http://arduino.cc/en/Tutorial/SPIDigitalPot. Thanks again, Dave

What's the target of your project? Measuring the light that an LED connected to the same Arduino produces? I doubt that. Please describe what you want to achieve.

To be sure the problem is from the sensor you should try driving the LED(s) from a simple voltage divider and steady power supply so you have no PWM signal and see if the results settle down and behave as expected on the sensor. If they do then maybe using RC circuit on the LED(s) instead of on the sensor is the answer or at least you would know the digital pot route is more likely to work.