Assistance with LPD8806
Moderators: adafruit_support_bill, adafruit

Assistance with LPD8806

by cjs on Thu Nov 08, 2012 3:10 pm

Good afternoon,
I'm working on an Arduino LPD8806 application and ran into a bit of a snag, would anyone mind advising me?

Without getting into a LOT of detail and boring you to death I need to color chase five times (without back-filling) to LEDx on a 5 meter strip. I want to start the color chase not from the beginning of the strip, but from LEDx - 15 LEDs. Once the chase has been executed five times LEDx and the one beside it (LEDx-1) need to alternately blink on and off. (In case you couldn't tell I'm trying to draw something's attention to the physical location around LEDx.)

I don't get to work with Arduino but once a year so I usually forget what I learn by the next time I have the opportunity, it's like being a noob ALL THE TIME. ;P Because of this I try to break the overall project up into smaller bits and work my way through each one, it's not so daunting that way.

So far I have used example code and the forum to successfully

1. Not back-fill the LED chase.
2. Stop the chase on LEDx and LEDx-1.
3. Execute only five times before stopping.

Remaining is
4. Blink LEDx and LEDx-1 on and off, alternately.
5. Start chase from LEDx-15.

To begin step 4 (Blink LEDx and LEDx-1 on and off, alternately) in as simple a way as possible I want to turn on two adjacent LEDs, green. Based on the code from this post: viewtopic.php?f=47&t=33308&start=0&hilit=lpd8806

I have this:

#include "LPD8806.h"
#include "SPI.h"

// Choose 2 pins for output; can be any valid output pins:
int dataPin = 11;
int clockPin = 12;
int nLEDs = 160;

// First parameter is the number of LEDs in the strand.  The LED strips
// are 32 LEDs per meter but you can extend or cut the strip.  Next two
// parameters are SPI data and clock pins:
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);

void setup() {

  strip.begin(); // Start up the LED strip
  strip.show(); // Update the strip, to start they are all 'off'
}
void loop()
{
  strip.setPixelColor(50, strip.Color(0, 128, 0)); // set pixel #50 Green
  strip.setPixelColor(49, strip.Color(0, 128, 0)); // set pixel #49 Green
  strip.show();
}




It compiles and uploads fine but unfortunately nothing is happening on any of the pixels of the strip. I've run your test and show-off code for a couple days now, and it's running off a re-purposed PC power supply capable of sourcing 18 Amps of power, so we're good there.

I'm convinced that, as usual, I'm missing something simple because I don't understand the IDE as well as I should.

Thanks for the assist.
cjs
 
Posts: 9
Joined: Sun Feb 22, 2009 2:49 pm

Re: Assistance with LPD8806

by cjs on Mon Nov 12, 2012 9:25 am

I'm still at a complete loss, I have NO idea why this does not work. I've looked at twenty pages of LPD8806 search-results on the forum here and have nothing to show for it.

That's not entirely true. I got a couple laughs out of a post by some guy throwing a tantrum like a three year old. :lol:

I'm JUST trying to turn on an LED, I've looked at this conversation many times and don't know what to try next.

viewtopic.php?f=47&t=33308&start=0&hilit=lpd8806

So is the function of setPixelColor not defined somewhere? I should think that would be covered by #include "LPD8806.h"

Code: Select all | TOGGLE FULL SIZE
#include "LPD8806.h"
#include "SPI.h"

// Choose 2 pins for output; can be any valid output pins:
int dataPin  = 11;
int clockPin = 12;
int nLEDs = 160; //Number in the strip
int LED1 = 20; // First LED
int LED2 = 19; // Second LED
int Color = (0, 128, 128); // Color to apply to the LEDs
int wait = 200; // delay between loops

// First parameter is the number of LEDs in the strand.  The LED strips
// are 32 LEDs per meter but you can extend or cut the strip.  Next two
// parameters are SPI data and clock pins:
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);

void setup() {
  strip.begin(); // Start up the LED strip
  strip.show(); // Update the strip, to start they are all 'off'
}
void loop()
{
  strip.setPixelColor(LED1, Color); // set pixel # Green
  strip.setPixelColor(LED2, Color); // set pixel # Green
  strip.show(); // Apply the above changes
  delay(wait);
}


Again, all the test sketches work fine. I'm missing something silly here. Usually a weekend away from work makes that kind of thing apparent but not this time. :)
cjs
 
Posts: 9
Joined: Sun Feb 22, 2009 2:49 pm

Re: Assistance with LPD8806

by adafruit_support_rick on Mon Nov 12, 2012 9:49 am

Code: Select all | TOGGLE FULL SIZE
int dataPin  = 11;
int clockPin = 12;

The example sketches use pins 2 and 3. Have you changed them to run with 11 and 12, and do they work that way?

If you want to use hardware SPI, you want to call a different constructor:
Code: Select all | TOGGLE FULL SIZE
LPD8806 strip = LPD8806(nLEDs);  //Use hardware SPI

The constructor you're calling disables SPI and configures the pins for "soft" SPI
Code: Select all | TOGGLE FULL SIZE
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);  //Use 'soft' SPI
User avatar
adafruit_support_rick
 
Posts: 11993
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Assistance with LPD8806

by cjs on Mon Nov 12, 2012 10:00 am

Added serial output to make sure it's actually executing and it is, my color data must not be right.

Huh.

Code: Select all | TOGGLE FULL SIZE
#include "LPD8806.h"
#include "SPI.h"

// Choose 2 pins for output; can be any valid output pins:
int dataPin  = 11;
int clockPin = 12;
int nLEDs = 160; //Number in the strip
int LED1 = 20; // First LED
int LED2 = 19; // Second LED
int wait = 200; // delay between loops

// First parameter is the number of LEDs in the strand.  The LED strips
// are 32 LEDs per meter but you can extend or cut the strip.  Next two
// parameters are SPI data and clock pins:
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);

void setup() {
  strip.begin(); // Start up the LED strip
  strip.show(); // Update the strip, to start they are all 'off'
  Serial.begin(9600);  // Open the serial port at 9600 bps:
}
void loop() {
  strip.setPixelColor(LED1, (0,128,0)); // set pixel # Green
  Serial.println ("Pixel 1");
  strip.setPixelColor(LED2, (0,128,0)); // set pixel # Green
  Serial.println ("Pixel 2");
  strip.show(); // Apply the above changes
  Serial.println ("Show");
  delay(wait);
  Serial.println ("DelayComplete");
}


Serial Output:

Pixel 1
Pixel 2
Show
DelayComplete
Pixel 1
Pixel 2
Show
DelayComplete
cjs
 
Posts: 9
Joined: Sun Feb 22, 2009 2:49 pm

Re: Assistance with LPD8806

by adafruit_support_rick on Mon Nov 12, 2012 10:22 am

Get rid of the parens in the call to setpixelcolor. Also, the pixel values are 7 bit, and 128 is an 8-bit value, which will be truncated to 0.
Code: Select all | TOGGLE FULL SIZE
  strip.setPixelColor(LED1, 0,127,0); // set pixel # Green
  Serial.println ("Pixel 1");
  strip.setPixelColor(LED2, 0,127,0); // set pixel # Green
User avatar
adafruit_support_rick
 
Posts: 11993
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Assistance with LPD8806

by cjs on Mon Nov 12, 2012 10:39 am

driverblock wrote:Get rid of the parens in the call to setpixelcolor. Also, the pixel values are 7 bit, and 128 is an 8-bit value, which will be truncated to 0.
Code: Select all | TOGGLE FULL SIZE
  strip.setPixelColor(LED1, 0,127,0); // set pixel # Green
  Serial.println ("Pixel 1");
  strip.setPixelColor(LED2, 0,127,0); // set pixel # Green


Oh my Crom I knew I was missing something silly. If I didn't spend so much time sabotaging myself I might actually be able to get something accomplished.

Code: Select all | TOGGLE FULL SIZE
#include "LPD8806.h"
#include "SPI.h"

// Choose 2 pins for output; can be any valid output pins:
int dataPin  = 11;
int clockPin = 12;
int nLEDs = 160; //Number of pixels in the strip
int LED1 = 20; // First LED
int LED2 = LED1--; // Second LED
int wait = 200; // delay between loops

// First parameter is the number of LEDs in the strand.  The LED strips
// are 32 LEDs per meter but you can extend or cut the strip.  Next two
// parameters are SPI data and clock pins:
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);

void setup() {
  strip.begin(); // Start up the LED strip
  strip.show(); // Update the strip, to start they are all 'off'
  Serial.begin(9600);  // Open the serial port at 9600 bps:
}
void loop() {
  strip.setPixelColor(LED1, 0,127,0); // set pixel # Green
  Serial.println ("Pixel 1");
  strip.setPixelColor(LED2, 0,127,0); // set pixel # Green
  Serial.println ("Pixel 2");
  strip.show(); // Apply the above changes
  Serial.println ("Show");
  delay(wait);
  Serial.println ("DelayComplete");
}


Thank you my friend, I'll dance at your funeral.

Or your wedding. Whichever comes first.
cjs
 
Posts: 9
Joined: Sun Feb 22, 2009 2:49 pm

Re: Assistance with LPD8806

by adafruit_support_rick on Mon Nov 12, 2012 11:04 am

The 7-bit thing tripped me up, too. If I had designed that chip, I think I might have left-shifted the data format by 1.

Got married eons ago, so too late for that. Funeral it is. :wink:
User avatar
adafruit_support_rick
 
Posts: 11993
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Assistance with LPD8806

by cjs on Tue Nov 13, 2012 2:06 pm

Almost done, thanks again for the help.

I have everything working as planned except for the thing I didn't plan for. :oops:

If you look at the code section titled

"void DualChaseToTarget()"

It's close to the bottom and you'll see that I'm incrementing/decrementing two strip.setPixelColor commands by one for every iteration until they reach LEDLoc1, or the 'center' LED of both chases, then repeating a certain number of times.

This is great except when the two chases need to start different distances from the center of the chases. If the number of LEDs to the RIGHT is greater than the number of LEDs to the LEFT then the chase over-runs. If the case is reversed it under-runs.

Strip_Array.jpg
Strip_Array.jpg (39.8 KiB) Viewed 1300 times


I tried using 'if' statements but I ended up neck-deep in curly braces. I'm not really sure how to go at this. Any advice? Ideally I'd like to stop whichever chase has reached the center before the other but let the other to complete normally.

I have this idea that it might be possible to determine which is a greater distance form the center then iterate that number of times, then use an 'if' statement inside the loop to determine if one chase has already reached the center but my brain doesn't quite wrap around that.

If you want to test this you'll need a five meter strip, connect to pins 11 and 12, open the serial monitor and paste/send this:

Code: Select all | TOGGLE FULL SIZE
312,43,33,53,0,127,0,350,75,5


Adjust the starting points of the chases by changing the third and fourth group of numbers (33 and 53). More details about this data string in the comments at the top of the sketch.

I'm sure that there is a LOT of good advice to be given about changing other things in this sketch and I definitely want to hear what anyone has to say if they can explain WHY they would make the change. This IS the way it IS because it makes sense to me and (but for this issue) works well for me. Let me know if I've broken any major rules or can benefit from you suggestion.

Thanks.

Code: Select all | TOGGLE FULL SIZE
#include "LPD8806.h"
#include "SPI.h"

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

// Name the strings used.
String stringBinLoc, stringLEDLoc1, stringLEDLoc2, stringLEFT, stringRIGHT, stringRED, stringGRN, stringBLU, stringBlinkDelay, stringChaseDelay, stringChaseRepetitions;

// LED color and location information comes in from the computer to the Arduino as
// BinLocation,LEDLocation,LEFTLocation,RIGHTLocation,REDValue,GreenValue,BlueValue,BlinkDelay,ChaseDelay,ChaseRepetitions
// ex.: 312,43,33,53,0,127,0,350,75,5

int nLEDs = 160; // Number of RGB LEDs in strip
int BinLoc = 0; // Value for Bin Location
int LEDLoc1 = 0; // Value for LED Location
int LEDLoc2 = 0; // Value for second LED Location
int RED = 0; // Value for Red
int GRN = 0; // Value for Green
int BLU = 0; // Value for Blue
int i = 0; // Current chase loop iteration
int j = 0; // LEFT value for chase
int k = 0; // RIGHT value for chase
int LEFT = 0; // Fill from left starting pixel
int RIGHT = 0; // Fill from right starting pixel
int REPS = 5; // Number of times to chase to target
int waitBlink = 350; // Delay between blink shifts
int waitChase = 75; // Delay between chase shifts
int incomingByte = 0; // for incoming serial data

// Choose 2 pins for output; can be any valid output pins:
int dataPin  = 11;
int clockPin = 12;

// First parameter is the number of LEDs in the strand.  The LED strips
// are 32 LEDs per meter but you can extend or cut the strip.  Next two
// parameters are SPI data and clock pins:
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);

void setup() {

  stringBinLoc = String("Bin Location: ");
  stringLEDLoc1 = String("LED Location 1: ");
  stringLEDLoc2 = String("LED Location 2: ");
  stringLEFT = String("Left Location: ");
  stringRIGHT = String("Right Location: ");
  stringRED = String("Red Value: ");
  stringGRN = String("Green Value: ");
  stringBLU = String("Blue Value: " );
  stringBlinkDelay = String("Blink Delay: ");
  stringChaseDelay = String("Chase Delay: ");
  stringChaseRepetitions = String ("Chase Repetitions: ");

  strip.begin(); // Start up the LED strip
  strip.show(); // Update the strip, to start they are all 'off'
  Serial.begin(9600);  // Open the serial port at 9600 bps:
}

void loop()
{
  Serial.println(RED);
  Serial.println(GRN);
  Serial.println(BLU);
  if (Serial.available() > 0) // if there's any serial data available...
  {
    ////////////////////////////////////////////////////////////////////
    // Parse all the data from the PC, look for the next valid integer
    // in the incoming serial stream:
    int BinLoc = Serial.parseInt(); // Assign this value to BinLoc
    // do it again:   
    LEDLoc1 = Serial.parseInt(); // Assign this value to LEDLoc1
    LEFT = Serial.parseInt(); // Assign this value to LEFT
    RIGHT = Serial.parseInt(); //Assign this value to RIGHT
    RED = Serial.parseInt(); // Assign this value to RED
    GRN = Serial.parseInt(); // Assign this value to GRN
    BLU = Serial.parseInt(); // Assign this value to BLU
    waitBlink = Serial.parseInt(); // Assign this value to waitBlink
    waitChase = Serial.parseInt(); // Assign this value to waitChase
    REPS = Serial.parseInt(); // Assign this value to REPS
    LEDLoc2 = LEDLoc1++; // Assign second LED location value by
    // incrementing LEDLoc1 by 1.
    if (Serial.read() == '\n'); // Newline is the end of the sentence:

    /////////////////////////////////////////////////////////////////////
    // Return the values received to the computer for debugging purposes.
    Serial.println(stringBinLoc+BinLoc);
    Serial.println(stringLEDLoc1+LEDLoc1);
    Serial.println(stringLEDLoc2+LEDLoc2);
    Serial.println(stringLEFT+LEFT);
    Serial.println(stringRIGHT+RIGHT);
    Serial.println(stringRED+RED);
    Serial.println(stringGRN+GRN);
    Serial.println(stringBLU+BLU);
    Serial.println(stringBlinkDelay+waitBlink);
    Serial.println(stringChaseDelay+waitChase);
    Serial.println(stringChaseRepetitions+REPS);

    DualChaseToTarget(); // Perform the "Attention Getter"
  }
  else
  {
    Blink(); // Indicate desired location for the product.
  }
}

////////////////////////////////////////////////////////////////
// This subroutine executes the blinking function
void Blink()
{
  strip.setPixelColor(LEDLoc1, RED,GRN,BLU); // set pixel # ON
  //  Serial.println ("Pixel 1 On");
  strip.setPixelColor(LEDLoc2, 0,0,0); // set pixel # OFF
  //  Serial.println ("Pixel 2 Off");
  strip.show(); // Apply the above changes
  delay(waitBlink);
  // Alternate
  strip.setPixelColor(LEDLoc1, 0,0,0); // set pixel # OFF
  //  Serial.println ("Pixel 1 Off");
  strip.setPixelColor(LEDLoc2, RED,GRN,BLU); // set pixel # ON
  //  Serial.println ("Pixel 2 On");
  strip.show(); // Apply the above changes
  delay(waitBlink);
}

////////////////////////////////////////////////////////////////
// This subroutine executes the chase function
void DualChaseToTarget()
{
  //  Serial.println(REPS);
  i = 0;
  while (i < REPS) // Perform the loop a number of times = to REPS
  {   
    j = LEFT; // Assign the value of LEFT to j so we can increment it but not lose the value of LEFT
    k = RIGHT;  // Assign the value of RIGHT to k so we can decrement it but not lose the value of RIGHT
    while (j < LEDLoc1) // Chase until j is not less than the pixel number of LEDLoc1
    {
      strip.setPixelColor(j++, RED,GRN,BLU); // Turn on pixel j+1
      strip.setPixelColor(k--, RED,GRN,BLU); // Turn on pixel k-1
      strip.show();  // Apply
      strip.setPixelColor(j-1, 0,0,0); // Turn off pixel j-1 so we don't leave a trail
      strip.setPixelColor(k+1, 0,0,0); // Turn off pixel k+1 so we don't leave a trail
    }     
    delay(waitChase);
    i = i + 1;
    Serial.println (i);
  }
}
cjs
 
Posts: 9
Joined: Sun Feb 22, 2009 2:49 pm

Re: Assistance with LPD8806

by tldr on Wed Nov 14, 2012 1:52 am

Code: Select all | TOGGLE FULL SIZE
      strip.setPixelColor(j++, RED,GRN,BLU); // Turn on pixel j+1
      strip.setPixelColor(k--, RED,GRN,BLU); // Turn on pixel k-1


actually, this code turns on pixels j and k, then increments j and decrements k. to get the code's behavior to match your comments use ++j and --k.

this might work for you. the idea is to turn on an led only if it is further from of the same distance from the target led as the other one.

Code: Select all | TOGGLE FULL SIZE
////////////////////////////////////////////////////////////////
// This subroutine executes the chase function
void DualChaseToTarget()
{
  //  Serial.println(REPS);
  i = 0;
  while (i < REPS) // Perform the loop a number of times = to REPS
  {   
    j = LEFT; // Assign the value of LEFT to j so we can increment it but not lose the value of LEFT
    k = RIGHT;  // Assign the value of RIGHT to k so we can decrement it but not lose the value of RIGHT
    while (j < LEDLoc1) // Chase until j is not less than the pixel number of LEDLoc1
    {
      if ((LEDLoc1 - j) >= (k - LEDLoc1))
        strip.setPixelColor(j, RED,GRN,BLU); // Turn on pixel j
      if ((k - LEDLoc1) >= (LEDLoc1 - j))
        strip.setPixelColor(k, RED,GRN,BLU); // Turn on pixel k
      strip.show();  // Apply
      if ((LEDLoc1 - j) >= (k - LEDLoc1))
        strip.setPixelColor(j++, 0,0,0); // Turn off pixel j
      if ((k - LEDLoc1) >= (LEDLoc1 - j))
        strip.setPixelColor(k--, 0,0,0); // Turn off pixel k so we don't leave a trail
    }     
    delay(waitChase);
    i = i + 1;
    Serial.println (i);
  }
}
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 466
Joined: Thu Aug 30, 2012 12:34 am

Re: Assistance with LPD8806

by cjs on Wed Nov 14, 2012 8:06 am

Thank you for responding. This code improvement actually works best if j and k starting points are NOT equidistant from LEDLoc1.

Doing the math:

In this case the chase starting points are equidistant from LEDLoc1 but k doesn't light throughout the entire sequence.

LEDLoc1 = 33
j (LEFT) = 23
k (RIGHT) = 43

if ((LEDLoc1 - j) >= (k - LEDLoc1))
if (33 - 23) >= (43 - 33)
if 10 >= 10 Turn on pixel j (this turns on)

if ((k - LEDLoc1) >= (LEDLoc1 - j))
if (43 - 33) >= (33 - 23)
if 10 >= 10 Turn on pixel k (this does not turn on, I'm not sure why)

Math on only one cup of coffee sounds like a path to failure.

Lemmee see if I can work through this on my own the rest of the way since you got me started in a better direction. I appreciate it. :wink:
cjs
 
Posts: 9
Joined: Sun Feb 22, 2009 2:49 pm

Re: Assistance with LPD8806

by cjs on Mon Nov 26, 2012 3:09 pm

This is what I ended up going with, it chases from one direction then the other direction. It happens so fast that you can't really tell it's not simultaneous.

Code: Select all | TOGGLE FULL SIZE
////////////////////////////////////////////////////////////////
// This subroutine executes the chase version 2 function
// Version 2 alternates chase from right/chase from left
void DualChaseToTarget()
{
  //  Serial.println(REPS);
  i = 0;
  while (i < REPS) // Perform the loop a number of times = to REPS
  {   
    j = LEFT; // Assign the value of LEFT to j so we can increment it but not lose the value of LEFT
    while (j < LEDLoc1) // Chase until j is not less than the pixel number of LEDLoc1
    {
      strip.setPixelColor(j++, RED,GRN,BLU); // Turn on pixel j+1

      strip.show();  // Apply
      strip.setPixelColor(j-1, 0,0,0); // Turn off pixel j-1 so we don't leave a trail
    }
    k = RIGHT;  // Assign the value of RIGHT to k so we can decrement it but not lose the value of RIGHT
    while (k > LEDLoc1) // Chase until j is not less than the pixel number of LEDLoc1
    {
      strip.setPixelColor(k--, RED,GRN,BLU); // Turn on pixel k-1
      strip.show();  // Apply
      strip.setPixelColor(k+1, 0,0,0); // Turn off pixel k+1 so we don't leave a trail
    }     
    delay(waitChase);
    i = i + 1;
    //    Serial.println (i);
  }
}
cjs
 
Posts: 9
Joined: Sun Feb 22, 2009 2:49 pm