Go Down

Topic: Simplifying control of LED 2801 square pixel (Read 3735 times) previous topic - next topic

TSD_80

Hi there,

As say others, I'm a newbie, and want to create some 'very simple' Arduino code for controlling a strip of LED pixels on a string (of 20), 4 strings connected in total. My project will eventually monitor internet data and convert this into lighting particular LED modules (I'll save the ethernet/server bits for later when I have some development support).

The bit I'd love to work out now is how can I control each LED module in the string of 80 in such a way that I can write something like '1,7,9,25' to light LED number 1, 7, 9, and 25 in the string? Obviously intensity, time, colour, etc are also important but most of the tutorials out there seem to be using more pattern-based code (to create animations for example) rather than a basic identification and control of each module in the string. The variables i would love to control are:
- Which pixel in the string I want to control
- Whether it should be on/off
- For how long it remains on
- Fade in/out duration
- Colour value

I will then look to control multiple LEDs in small groups. E.g. 3-7 LEDs at a time.

Any support or example code would be greatly appreciated so I can start experimenting with it to getting a better grasp. Things such as wiring up the Arduino, LEDs and power supply are already understood.

Many thanks!

KirAsh4

You have one of the most used LED drivers to work with, the WS2801 (at least, I believe that's what you're referring to in your subject line.)  Use FastSPI to control the string.  You can leave it as one long string even (even if you cut it into four separate pieces, just connect the ends back together with wires.)

FastSPI keeps an array of the string:

NUM_LEDS = 20;
// there are some other needed lines here, but for this post they're irrelevant - get them from the FastSPI "testled" sketch.

leds[px].r = xxx;
leds[px].g = xxx;
leds[px].b = xxx;

Each 'px' refers to a specific pixel.  So in your case, you'd want px = 0, 6, 8, and 24 - remember it always starts counting from 0 on, not 1.

FastSPI does work with the SPI port, so if you have other SPI devices, keep in mind that the 2801's don't have an ENable pin.

Your other option is to bit-bang your way there, which I've done also in similar fashion: keep an array of the led count, then address each LED by it's array index.

TSD_80

KirAsh4 - thanks very much!

I had just downloaded the FastSPI ZIP when i read your response. Your input still really helps though - particularly addressing specific LEDs as I hadn't worked that bit out.

I'll try implementing this and see how far I get.

Much appreciated.


KirAsh4

No problem.  Let us know if you run into issues or have more questions.

TSD_80

Hi KirAsh4,

If I may ask another question or two...

So I've had a go at putting the basic code together for a predefined set of LEDs to switch on, as per your suggestions... i hope.

I'm trying to figure out how to 'group' a set of LEDs so that I can control, for example, 5 modules at once. Is it an array that I need to create? Such as this:

LED led[group name] = {LED(2), LED(20), LED(47), LED(60)};

Essentially, where I'm heading for is that these 4 LEDs light up in blue, whilst all unspecified LEDs remain white, for example. And then another set of LEDs light up in blue, and the remaining 75 go white. All dependent upon the XML data feed from elsewhere (that bits for later).

I appreciate there must be ws2801 snippets/examples out there that I can find to build around - I will continue to hunt for them - but no success yet, most likely due to my level of understanding. Any pointers or examples very much appreciated.

Thanks again,

T

P.S. This is the code I have put together so far:

#include <FastSPI_LED.h>

#define NUM_LEDS 80

// Sometimes chipsets wire in a backwards sort of way
struct CRGB { unsigned char b; unsigned char r; unsigned char g; };
// struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

#define PIN 4

void setup()
{
  FastSPI_LED.setLeds(NUM_LEDS);
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
  FastSPI_LED.setPin(PIN);
 
  FastSPI_LED.init();
  FastSPI_LED.start();

  leds = (struct CRGB*)FastSPI_LED.getRGBData();
}

void loop() {
 
//work out how to switch on/off groups - HIGH/LOW?,
//how to group different sets of LEDs - arrays?
//how to control the other 76 LEDs as one group as simply as possible
//how to fade in/out

leds[2].r = 255;
leds[2].g = 255;
leds[2].b = 255;
FastSPI_LED.show();
delay(3);
leds[20].r = 255;
leds[20].g = 255;
leds[20].b = 255;
FastSPI_LED.show();
delay(3);
leds[47].r = 255;
leds[47].g = 255;
leds[47].b = 255;
FastSPI_LED.show();
delay(3);
leds[60].r = 255;
leds[60].g = 255;
leds[60].b = 255;
FastSPI_LED.show();
delay(3);
}   

KirAsh4

Create an array with the led numbers you want to control, for example:
Code: [Select]
byte BlueLEDgroup[] = {2, 20, 47, 60};
Then all you have to do is loop through that array:
Code: [Select]

for (p = 0; p < sizeof(BlueLEDgroup); p++) {
  // do something with BlueLEDgroup[p], for example
  BlueLedGroup[p].r = 0;
  BlueLedGroup[p].g = 0;
  BlueLedGroup[p].b = 255;
}

That will affect whatever is in the array at index 'p'.  So the first iteration of that loop, p = 0 which translates to LED 2.  The next iteration p = 1 which is LED 20.  Etc., etc.

TSD_80

Thanks very much! Really appreciate your help on that.

It's currently giving me an error saying...

request for member 'b' in 'BlueLedGroup[p]', which is of non-class type 'byte''

But I'll try to figure that out.

Cheers

t

KirAsh4


TSD_80

Probably like a chimp has been hacking away ;-). Here's where I've got to so far:

#include <FastSPI_LED.h>

#define NUM_LEDS 80

// Sometimes chipsets wire in a backwards sort of way
struct CRGB { unsigned char b; unsigned char r; unsigned char g; };
// struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

#define PIN 4

void setup()
{
  FastSPI_LED.setLeds(NUM_LEDS);
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
  FastSPI_LED.setPin(PIN);
 
  FastSPI_LED.init();
  FastSPI_LED.start();

  leds = (struct CRGB*)FastSPI_LED.getRGBData();
 
}


void loop() {

byte BlueLEDgroup[] = {2, 20, 47, 60};

// BlueLedGroup ON
//have I declared 'p' correctly?
for (int p = 0; p < sizeof(BlueLEDgroup); p++) {
  BlueLEDgroup[p].r = 0;
  BlueLEDgroup[p].g = 0;
  BlueLEDgroup[p].1b = 255;
}
//following array equals all LEDS that are not specified in BlueLedGroup (0-79 LEDs possible)
byte WhiteLEDgroup[] = {0, 1, 3-19, 21-46, 48-59, 61-79};

//WhiteLedGroup ON whilst BlueLedGroup is ON
for (int p = 0; p < sizeof(WhiteLEDgroup); p++) {
WhiteLEDgroup[p].r = 255;
WhiteLEDgroup[p].g = 255;
WhiteLEDgroup[p].b = 255;
}   
}

KirAsh4

Please use the code button to insert code in your posts.  It looks like a #-sign.


#define PIN 4

This is not needed for the WS2801 chips.


  FastSPI_LED.setPin(PIN);

Neither is this.

However, you do need a data rate line for the WS2801s.  This isn't defined in the test program.  Add this line within the setup() portion:
Code: [Select]

FastSPI_LED.setDataRate(2);



  BlueLEDgroup[p].1b = 255;

What's '1b' ?


//following array equals all LEDS that are not specified in BlueLedGroup (0-79 LEDs possible)
byte WhiteLEDgroup[] = {0, 1, 3-19, 21-46, 48-59, 61-79};

That won't work for defining the remaining LEDs.  You're better off not bothering with this second array.  Just set everything to white first (you don't need an array for that), then cycle through the BlueLEDgroup array and turn those blue.  When you're done with that, then you can call FastSPI_LED.show() which will turn the LEDs on.

TSD_80

Legend. Thanks once again. All comments will be addressed and are gratefully received. 1b was a typo alone. Great to know I can simplify the loop by having all default to white upfront too.

TSD_80

Sorry to be so demanding here. I've reviewed the code and added more to it - all code seems to verify with the exception of the same issue as before. I still get the error message 'LED_arrays_3.cpp: In function 'void loop()':
LED_arrays_3:48: error: request for member 'r' in 'BlueLEDgroup[p]', which is of non-class type 'byte'
LED_arrays_3:49: error: request for member 'g' in 'BlueLEDgroup[p]', which is of non-class type 'byte'
LED_arrays_3:50: error: request for member 'b' in 'BlueLEDgroup[p]', which is of non-class type 'byte''

for:
Code: [Select]
byte BlueLEDgroup[] = {2, 20, 47, 60};
// BlueLedGroup ON
for (int p = 0; p < sizeof(BlueLEDgroup); p++) {
  BlueLEDgroup[p].r = 0;
  BlueLEDgroup[p].g = 0;
  BlueLEDgroup[p].b = 255;
}
FastSPI_LED.show();
}

KirAsh4

#12
Sep 19, 2012, 07:55 pm Last Edit: Sep 19, 2012, 07:58 pm by KirAsh4 Reason: 1
Right.  While BlueLEDgroup holds the position of each pixel that you want to change to blue, it doesn't translate to what FastSPI needs.  FastSPI keeps an array called 'leds' which is what you manipulate.  That array contains all of the pixels in your string.  Your BlueLEDgroup only holds those pixels you want changed, so you need to pass that information to the leds array, like so:
Code: [Select]
#include <FastSPI_LED.h>

#define NUM_LEDS 10

struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

byte BlueLEDgroup[] = {2, 20, 47, 60};
int done = 0;

void setup() {
 FastSPI_LED.setLeds(NUM_LEDS);
 FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);

 FastSPI_LED.setDataRate(2);
 
 FastSPI_LED.init();
 FastSPI_LED.start();

 leds = (struct CRGB*)FastSPI_LED.getRGBData();
}

void loop() {
 if (!done) {  // this stops the for loop from constantly being called
   for (int p = 0; p < sizeof(BlueLEDgroup); p++) {
     leds[BlueLEDgroup[p]].r = 0;
     leds[BlueLEDgroup[p]].g = 0;
     leds[BlueLEDgroup[p]].b = 0;
   }
   FastSPI_LED.show();
   done = 1;
 }
}


Now when you run this, 'p' becomes the counter from 0 to the size of the BlueLEDgroup array.  Each time it iterates through it, it returns whatever is at that position in that array.  So the first time, it returns the value '2'.  When that gets passed to the 'leds' array, you get 'leds[2].r = 0', etc., etc.  At the next iteration, p = 1, BlueLEDgroup[1] = 20, which when passed to the 'leds' array you get 'leds[20].r' etc., etc.

Does that make sense?

TSD_80

Yes it does. At least on initial read-through - I'll digest it over a few times so the array handling has sunk it and give it a try. It seems you've essentially packaged up /referenced the original LEDGroup code within the form of array that's understood by FastSPI.

In practical terms then, presumably if I create multiple LEDGroups I add them at the top of the code as you've done:
Code: [Select]
#include <FastSPI_LED.h>

#define NUM_LEDS 10

struct CRGB { unsigned char r; unsigned char g; unsigned char b; };
struct CRGB *leds;

byte BlueLEDgroup[] = {2, 20, 47, 60};
byte SecondLEDgroup[] = {x,x,x};
byte ThirdLEDgroup[] = {x, x, x, x, x};
int done = 0;


And then duplicate the Loop code against those as necessary:

Code: [Select]
void loop() {
//First group
  if (!done) {  // this stops the for loop from constantly being called
    for (int p = 0; p < sizeof(BlueLEDgroup); p++) {
      leds[BlueLEDgroup[p]].r = 0;
      leds[BlueLEDgroup[p]].g = 0;
      leds[BlueLEDgroup[p]].b = 0;
    }
    FastSPI_LED.show();
    done = 1;
  }
//SecondGroup
  if (!done) {  // this stops the for loop from constantly being called
    for (int p = 0; p < sizeof(SecondLEDgroup); p++) {
      leds[SecondLEDgroup[p]].r = 0;
      leds[SecondLEDgroup[p]].g = 0;
      leds[SecondLEDgroup[p]].b = 0;
    }
    FastSPI_LED.show();
    done = 1;
  }
//ThirdGroup
  if (!done) {  // this stops the for loop from constantly being called
    for (int p = 0; p < sizeof(ThirdLEDgroup); p++) {
      leds[ThirdLEDgroup[p]].r = 0;
      leds[ThirdLEDgroup[p]].g = 0;
      leds[ThirdLEDgroup[p]].b = 0;
    }
    FastSPI_LED.show();
    done = 1;
  }
}


Ever grateful. Thanks very much.

KirAsh4

Bingo!

Keep in mind, I just added the 'done' part in my test program so it stops.  Having built several battery-based LED displays, the less you have to invoke any kind of changes, the better.  And one way to do that is to monitor how often you're sending data down the line.  And if the lights aren't meant to change for several cycles, then why tell the program to do anything other than to wait outside of the loop.  There's certainly no need to call FastSPI_LED() over and over again if nothing's changed.

Since you may have several "sections" of different colors, if they're all going to get set at the same time, you can run all those loops in one shot before jumping out and waiting.

Go Up