Problem controlling led strip(WS2811) with lux-sensor(TSL2561)

Hey folks, I hope someone can help me find out what I'm missing.

The purpose of this project is to have the lux-sensor read the changes in brightness of my Philips Wake-Up Light, so as the intensity increases/decreases - the led strip follows in color intensity.

As far as I can see everything works, but after a few days of it running, the lux-sensor stops reading changes.
I can see this on an LCD Display module I hooked up to the board, the numbers just freeze, which means the led strip is always on or always off depending on what the lux value was at when it stopped reading.

For the led strip I'm using the NeoPixel Library even though it's not a NeoPixel strip. (Because I found an example of it working else ware :-[)

Could you guys give a "quick" look at my code and see if I'm missing something or just have done something wrong?

(This is my first Arduino-project, hence the code is surely not optimized.)

Cheers

luxSensor.ino (8.1 KB)

A lot of people look at this forum on mobile devices and they can’t cope with .ino files that is why we have other ways of posting your code. Please read the how to use this forum sticky post to see how.

If the code works for a day it is unlikely to be a problem with your code and more likely to be a hardware problem, possibly one of some interference pickup. Can you post a schematic of your circuit and a photograph of the wiring. If there is a Solderless bread board involved that is also likely to be a problem, otherwise it is probably a lack of sufficient supply decoupling.

Grumpy_Mike:
A lot of people look at this forum on mobile devices and they can’t cope with .ino files that is why we have other ways of posting your code. Please read the how to use this forum sticky post to see how.

If the code works for a day it is unlikely to be a problem with your code and more likely to be a hardware problem, possibly one of some interference pickup. Can you post a schematic of your circuit and a photograph of the wiring. If there is a Solderless bread board involved that is also likely to be a problem, otherwise it is probably a lack of sufficient supply decoupling.

Thank you for the insight Mike. I understand, I read the sticky first and I would've posted the code directly in the post but it stated it was too large to fit (over 9000), probably because of all the comments (and likely unnecessary code).

I removed some comments so I could paste the code now:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

/***** LED-STRIP ******/

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 5
#define NUM_LEDS 100

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ400);

/***********************/

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2


#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);

/**************************************************************************/
/*
    Configures the gain and integration time for the TSL2561
*/
/**************************************************************************/
void configureSensor(void) {
  /* You can also manually set the gain or enable auto-gain support */
  // tsl.setGain(TSL2561_GAIN_1X);      /* No gain ... use in bright light to avoid sensor saturation */
  // tsl.setGain(TSL2561_GAIN_16X);     /* 16x gain ... use in low light to boost sensitivity */
  tsl.enableAutoRange(true);            /* Auto-gain ... switches automatically between 1x and 16x */
  
  /* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
  tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS);      /* fast but low resolution */
  // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS);  /* medium resolution and speed   */
  // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS);  /* 16-bit data but slowest conversions */

  /* Update these values depending on what you've set above! */  
  Serial.println("------------------------------------");
  Serial.print  ("Gain:         "); Serial.println("Auto");
  Serial.print  ("Timing:       "); Serial.println("13 ms");
  Serial.println("------------------------------------");
}

void setup(void) {
  Serial.begin(9600);
  Serial.println("Light Sensor Test"); Serial.println("");
  
  /* Display some basic information on this sensor */
  
  //displaySensorDetails();
  
  /* Setup the sensor gain and integration time */
  configureSensor();

  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
  // init done

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(1000);

  // Clear the buffer.
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.setTextColor(WHITE);

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  delay(500);

}

/**************************************************************************/
/*
    Arduino loop function, called once 'setup' is complete (your own code
    should go here)
*/
/**************************************************************************/
void loop(void) 
{  
uint16_t broadband = 0;
uint16_t infrared = 0;
  
  /* Get a new sensor event */ 
  sensors_event_t event;
  tsl.getEvent(&event);

  /* Populate broadband and infrared with the latest values */
  tsl.getLuminosity (&broadband, &infrared);
  
  /* Display the results (light is measured in lux) */
  if (event.light) {
    Serial.print(event.light); Serial.println(" lux");   
    Serial.print(infrared); Serial.println(" ir");   
    Serial.print(broadband); Serial.println(" bb");
    fadeColor (event.light);
  }
  else {
    //we dont have any info, lets fade to black
    /* If event.light = 0 lux the sensor is probably saturated
       and no reliable data could be generated! */
       Serial.println("Sensor blocked or 0 lux");
       colorWipe(0, 0, 0, 10); // Fade to black
  }
  delay(200);

  display.setCursor(0, 0);
  display.print("LUX: ");
  display.println(event.light);
  display.print("IR: ");
  display.println(infrared);
  display.print("BB: ");
  display.println(broadband);
  display.display();
  delay(30);
  display.clearDisplay();
  
}

void fadeColor (int luxval) {
  
  if (luxval >= 110.00 and luxval <= 130.00) {
      Serial.print ("fading to goodmorning_6 :");
      Serial.println (luxval);
      colorWipe(35, 0, 12, 10); // Y3
  } else if (luxval >= 90 and luxval < 110.00) {
      Serial.print ("fading to goodmorning_5 :");
      Serial.println (luxval);
      colorWipe(30, 0, 10, 10); // Y3
  } else if (luxval >= 70 and luxval < 90) {
      Serial.print ("fading to goodmorning_4 :");
      Serial.println (luxval);
      colorWipe(25, 0, 8, 10); // Y3
  } else if (luxval >= 50 and luxval < 70) {
      Serial.print ("fading to goodmorning_3 :");
      Serial.println (luxval);
      colorWipe(20, 0, 6, 10); // Y3
  } else if (luxval >= 30 and luxval < 50) {
      Serial.print ("fading to goodmorning_2 :");
      Serial.println (luxval);
      colorWipe(15, 0, 4, 100); // Y2
  } else if (luxval >= 10 and luxval < 30) {
      Serial.print ("fading to goodmorning_1 :");
      Serial.println (luxval);
      colorWipe(10, 0, 2, 200); // Y1
  } else if (luxval >= 6 and luxval < 10) {
      Serial.print ("fading to goodmorning_0 :");
      Serial.println (luxval);
      colorWipe(5, 0, 1, 300); // Y0
  } else if (luxval >= 3 and luxval < 6) {
      Serial.print ("fading to goodmorning :");
      Serial.println (luxval);
      colorWipe(3, 0, 1, 400); // Y
  } else if (luxval < 3) {
      Serial.print ("fading to black :");
      Serial.println (luxval);
      colorWipe(0, 0, 0, 500); // Black
  }
  
}

void colorWipe(uint8_t r, uint8_t g, uint8_t b, uint8_t wait) {
  for(uint16_t i = 0; i < strip.numPixels(); i++) {
      uint8_t curr_r, curr_g, curr_b;
      strip.getPixelColor(i); // get the current colour
      curr_b = strip.getPixelColor(i) & 0xFF; curr_g = (strip.getPixelColor(i) >> 8) & 0xFF; curr_r = (strip.getPixelColor(i) >> 16) & 0xFF;  // separate into RGB components

      while ((curr_r != r) || (curr_g != g) || (curr_b != b)){  // while the curr color is not yet the target color
        if (curr_r < r) curr_r++; else if (curr_r > r) curr_r--;  // increment or decrement the old color values
        if (curr_g < g) curr_g++; else if (curr_g > g) curr_g--;
        if (curr_b < b) curr_b++; else if (curr_b > b) curr_b--;
        
          for(uint16_t i = 0; i < strip.numPixels(); i++) {
            strip.setPixelColor(i, curr_r, curr_g, curr_b);  // set the color
          }
          
        strip.show();
        delay(50);  // add a delay if its too fast
      }
      
  }
  
}

There is a bread board involved yes, and also an external power supply(the power supply is more then sufficient for one led led strip).

I have also tried to create a schematic and will take some pictures of the wiring when I get home.

Cheers for helping out.

Thanks for that. If posting a large code as an attachment you are best to give the .ino file a .txt extension insted as that will load into a mobile device and after all a .ino is just simply a text file anyway.

What I would do is to:-

  1. Add a 0.1uF ceramic capacitor between power and ground across the OLED display.
  2. Add a 470uF or bigger capacitor across the power and ground of the LED strip.
  3. Solder everything up on strip board.

These sort of things are very tricky to fix mainly because of how long you have to wait for the error to occur and also it is hard to know when it is fixed.

The code looks fine and I can't see any reason why it should crash. The main software reason for crashing is using String variables and you are not using any.

One way the code could reset things automatically if it freezes is to use the watchdog timer set on the longest delay. See Watch Dog PDF

Thanks for the tips! And sorry for the late reply, sometimes work gets in the way of my hobbys. ::slight_smile:

Ok, so I did number 1 and 2 (I don't have a strip board but I will look into getting one) and reset the arduino last night, I also removed some comments to make the sketch smaller in size.
However this morning after the Wake-light turned on, the led-strip stayed on even after I turned the Wake-light off again, and after a look at the OLED display the numbers had stopped moving, indicating the lux-sensor stopped reading - a.k.a the loop has stopped/crashed? So it seems the capacitors were not the problem, at least not the only problem.

So I'm thinking my next steps are:

  1. I will tonight remove all the "Serial.print" lines as I've read they can sometimes make an sketch unstable.
  2. I will also add the line display.printIn(freeMemory()); to the OLED display (from the MemoryFree Library) so maybe when it stops(hopefully wont, probably will) next time I can see if there is a difference in memory usage and hence it should explain a memory leak, if I am correct?

If none of these options work I will have to try and solder everything up.

I guess I'll have to use the Watch Dog timer as a last resort, but I would of course rather find the culprit so I can eventually extend the project and/or share it with others!

If you have any other ideas I'm all ears!

Cheers

OK, so..

  1. Removing the serial.print lines didn't help.
  2. Printing freeMemory() to the display showed the value of 777, and that value was the same this morning when the loop stopped again, so I guess that means no memory leak?

I've tried to reproduce the problem manually, but everything seems to work when I reset the arduino and play with the lights on/off. It's only after the loop has been running for several hours (+8) and then registers a change that it stops.

I am out of options, and only thing left to do is to solder all the cables, but I'm not optimistic that it will change much, since everything is working straight after I do a reset, but after every night when the light turns on - the loop breaks. :frowning:

Anyone else have any tips except using the Watch Dog Timer?

Cheers