LED GLOBE

Hello all,

I built and LED GLOBE using an ATMEGA328 and 34 shift register.

I followed the configuration given by the arduino website (see attachment).
code:

/*
  Shift Register Example
  Turning on the outputs of a 74HC595 using an array

 Hardware:
 * 74HC595 shift register 
 * LEDs attached to each of the outputs of the shift register

 */
//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;

//holders for infromation you're going to pass to shifting function
byte data;
byte dataArray[10];

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  Serial.begin(9600);

  //Arduino doesn't seem to have a way to write binary straight into the code 
  //so these values are in HEX.  Decimal would have been fine, too. 
  dataArray[0] = 0xFF; //11111111
  dataArray[1] = 0xFE; //11111110
  dataArray[2] = 0xFC; //11111100
  dataArray[3] = 0xF8; //11111000
  dataArray[4] = 0xF0; //11110000
  dataArray[5] = 0xE0; //11100000
  dataArray[6] = 0xC0; //11000000
  dataArray[7] = 0x80; //10000000
  dataArray[8] = 0x00; //00000000
  dataArray[9] = 0xE0; //11100000

  //function that blinks all the LEDs
  //gets passed the number of blinks and the pause time
  blinkAll_2Bytes(2,500); 
}

void loop() {

  for (int j = 0; j < 10; j++) {
    //load the light sequence you want from array
    data = dataArray[j];
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, data);
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(300);
  }
}



// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first, 
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);

  //clear everything out just in case to
  //prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte myDataOut?
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights. 
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to myDataOut and a bitmask result 
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000 
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {  
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin  
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}

(code tags added by moderator)

Ok as you can see in thepicture attached is working; however, the stripe is too wide to build figures such a circle, a letter V or, an earth mode display.

I am also using an IR (infrared) to keep the stripe from moving when I want.

To obtain this stripe I set the delay located after the latch pin high to 50us , and we I go try to below 45 us, I start getting glitches and the LED start spiking, so I believe the ATMEGA328 is not responding fast enough and I do not now why.

What I am trying to achieve is to display a single LED turn on because when I turn on an LED now, I get a line of about 2 1/2 inches.
I could be the configuration or the way the code is written. Please help me.

If you want things to run faster, change lines like these digitalWrite(latchPin, 0);

to use direct port manipulation. Say latchPin was on port D, bit 2 (just using that as an example), and, instead of a for loop, use 10 discrete transfers. All combined:

PORTD = PORTD & 0b11111011; // bit 2 low
// and use SPI.transfer vs shiftout
// shiftOut(dataPin, clockPin, data);
SPI.transfer(dataArray[0]);
SPI.transfer(dataArray[1]);
SPI.transfer(dataArray[2]);
SPI.transfer(dataArray[3]);
SPI.transfer(dataArray[4]);
SPI.transfer(dataArray[5]);
SPI.transfer(dataArray[6]);
SPI.transfer(dataArray[7]);
SPI.transfer(dataArray[8]);
SPI.transfer(dataArray[9]);
PORTD = PORTD | 0b11111011; // bit 2 high

Further, get rid of delay(300); and use blink without delay style code to test millis() or micros() and make data output changes when the next time interval occurs.

void loop(){
currentMicros = micros(); // capture the 'time'
elapsedMicros = currentMicros - nextMicros; // see how much has passed
if (elapsedMicros > duration){ // duration being 300000 for 300mS
nextMicros = nextMicros + duration; // set up for next occurrence
// do the 300mS update stuff
}
// then do other stuff that is going in
} // end loop

Also, get rid of the cap on the control line,that just stresses the control line. Add a 0.1uF cap on the Vcc pin, going to Gnd.

I've deleted the duplicate of this topic in "Programming questions".

DO NOT CROSS-POST.

Thank you for replying so quickly.

Now is there a difference between SPI and just shifting out the LEDs?

What we wanted to do and what is happening is not the same. As you can see from the picture attached from the first post, we are getting a stripe that is too wide to manipulate. So to add to the question above, does using SPI direct port manipulation actually manipulate individual LEDs or does it do the same thing as shifting out the LEDs?

Actively manipulating individual LEDs would give us greater control over the definition of the image we want to put on our spinning device.

Thank you for any information that you can provide.

does using SPI direct port manipulation actually manipulate individual LEDs or does it do the same thing as shifting out the LEDs?

Shifting the data into the shift registers is what makes the LEDs change. Shifting data in via SPI.transfer() is much faster than shifting via shiftout(), and will let you change the state of the LEDs much faster.

Now, it may be that your data is going in plenty fast the delay(300); is what makes them appear to be for so long and look so spread out. That's almost 1/3 of a second.

Thanks again for replaying,

Couple questions:

  1. I am using pin 8 of the ATMEGA 328, so how can I apply to my code the example you gave me with the second bit being the one that has to go high and low to latch the data.

  2. Do I have to change the entire sketch to direct manipulation or just the section including the arrays and changing state of the latch pin.

I attached a sketch that display the letters UCF I will appreciate if you can take a look…

UCF.ino (13.8 KB)

//Pin connected to ST_CP of 74HC595
int latchPin = 8; // move to >> 10 for SS (slave select) = RCK on '595
//Pin connected to SH_CP of 74HC595
int clockPin = 12; // >> move to 13 for SCK
////Pin connected to DS of 74HC595
int dataPin = 11;  // >> 11 for MOSI, okay as is

add SPI.begin(); into void setup() Once you do that, you no longer need to declare pins 11,12,13 for data types - the SPI library does that for you. You Do need to declare pin 10 tho.

Only change the parts you want to go fast for port direct manipulation. If using D10, then you will manipulate PORTB, bit 2.

byte latchPin = 10; pinMode (latchPin, OUTPUT); digitalWrite (latchPin, HIGH);

and in loop code: PORTB = PORTB & 0b11111011; // clear bit 2 (Low)

PORTB = PORTB | 0b00000100; // set bit 2 (High)

CrossRoads:
and in loop code:
PORTB = PORTB & 0b11111011; // clear bit 2 (Low)

PORTB = PORTB | 0b00000100; // set bit 2 (High)

An alternative of doing this that may or may not be easier to understand would be to use shifting and logical operations:

PORTB = PORTB & ~ (1 << 2);     // clear bit 2
PORTB = PORTB | (1 << 2);            // set bit 2

And this can be further abbreviated using C/C++ operators combined with =:

PORTB &= ~(1 << 2);
PORTB |= (1 << 2);

To expand on this, (1 << 2) creates 0b0000000000000100 (or 0x0002 in hex) which is an appropriate mask to set with inclusive OR instruction. The value ~ (1 << 2) creates 0b1111111111111011 (0xffffd in hex), which gives you the mask to clear bit 2 with an AND instruction.

I don’t find either one of those easier to follow, and find the C++ << thing confusing.
I find it much easier to write it as I did, and be condifdent that the compiler will make it do the right thing.

If I was more confident, I would just use

PINB = 0b00000100; // write a 1 to bit 2 to flip bit 2
// do SPI.transfers
PINB = 0b00000100; // write a 1 to bit 2 to flip bit 2

but there’s always the odd chance something else could have messed with bit 2 and then the bit is out of sync for what’s needed.

As I said, people may or may not find it easier that way. I happen to find it easier to do the shifting because the shift gives the bit number. If the offsets are expressed as bit numbers, sure I will use hex masks.

I much prefer hex masks over bit masks, because I’ve found over the years that I will often times mis-count the number of bits. Hex is better because it is a 4-to-1 reduction (and even hex is a problem in dealing with 32-bit fields).

And the compiler will generate the same code in both cases. This is purely a style issue, and there is no single right answer.

ok hello again,

I am not sure in how to used this part of the code you gave me to replace the “delay()” I was using:

void loop(){
currentMicros = micros(); // capture the ‘time’
elapsedMicros = currentMicros - nextMicros; // see how much has passed
if (elapsedMicros > duration){ // duration being 300000 for 300mS
nextMicros = nextMicros + duration; // set up for next occurrence
// do the 300mS update stuff
}
// then do other stuff that is going in
} // end loop


Furthermore I am also not sure on what type of variable I should declare :
currentMicros , elapsedMicros, currentMicros, nextMicros, and duration, so if I have this:


#include <avr/pgmspace.h>
#include <SPI.h>
//Pin connected to ST_CP of 74HC595
int latchPin = 10;
byte dataArray[3];

void setup() {
//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
digitalWrite(latchPin, HIGH);
SPI.begin();
}

void loop()
{
dataArray[0]=0b01101101;
dataArray[1]=0b10110110;
dataArray[2]=0b11011011;
PORTB=PORTB&0B11111011;
SPI.transfer(dataArray[0]);
SPI.transfer(dataArray[1]);
SPI.transfer(dataArray[2]);
PORTB=PORTB|0B00000100;
delay(400);
// }//infrared
}//void loop

where that portion of the code should go and if I need to modified.

And my last question for today will be:

if I used PROGMEN

PROGMEM prog_uchar Array_01 ={
B00000010, B10100000,
B00000010, B10101010,
B00000000,B000000
}

Will I be able to the read through the 2x2 matrix using this:


int pointer = 0;

for (int l=0; l<15; l++)
{
cell = pgm_read_byte_near(bild_01 + pointer + l);
}

what i am trying to do is to create a table with the 3026 bytes i need to cover the entire surface of the globe and to this I need to find a way of set the latch low evaluate the 3026 values and set the latch pin high

time related variables are all unsigned long.

I don't fully understand what you are doing. You have 34 shift registers, 3026 bytes, your initial code is 10 bytes and 8 clocks somehow, can you explain the whole project more fully and post a schematic?

Ok
I am using an ATMEGA328 to send data to 34 (595) shift registers pins 8, 9, and 10 for latch, data, and clock respectively.
The attachments show the way I connected everything together which is basically the same connection provided by the Arduino shift out website (shown in the first post also).
What I have now is shown in the code below which is displaying a stripe to wide to manipulate to display more defined images.
When I display a single sequence using the 34 register, I display a complete stripe of about 3 inches wide. Using the code I have now that will be accomplished by having:
dataArrayRegOne[0] = 0x92; --------- all the way through until ---------dataArrayRegThirtyFour[0] = 0x92;

However, I only need 12 sequences to create 12 stripes and cover the surface of the sphere.
The ring has 281 mm, so after doing the math I know I need 89 sequences (stripes) to cover the surface of the sphere and be able to display the more defined images I need.
When I said byte I meant data byte for example dataArrayRegOne[0] = 0x92 // 0010 1001, so since each register needs a byte and I have 34 times the 89 sequences I need that gives me 3026 data bytes I need to send to the shift register.
I was wondering if I can used this to build a table of values
PROGMEM prog_uchar Array_01 ={
B00000010, B10100000,
B00000010, B10101010,
B00000000,B000000
}
and put in flash like is depicted, but I am not sure in what way I can retrieve them and put them in this part of the code you gave me:
SPI.transfer(dataArray[0]);
I was thinking in using some like this to do it, but I am not sure:
for (int l=0; l<columns; l++)
{
cell = pgm_read_byte_near(bild_01 + pointer + l);
}
Lastly, how do I use the code you gave me to replace the delay. Does it go before or after the latch pin goes high? Do I have to add anything to it?
Once again thank you so much for your help!!!

Some pictures

IMG_4783[2].JPG|3264x2448

IMG_4966[1].JPG|3264x2448

this is the actual code I was going to use for the 89 sequences

//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;
int pwm = 9;
char letter;

//holders for infromation you’re going to pass to shifting function
byte dataOne;
byte dataTwo;
byte dataThree;
byte dataFour;
byte dataFive;
byte dataSix;
byte dataSeven;
byte dataEight;
byte dataNine;
byte dataTen;
.
.
.

byte dataThirtyOne;
byte dataThirtyTwo;
byte dataThirtyThree;
byte dataThirtyFour;
.
.
.

byte dataArrayRegThirtyTwo[90];
byte dataArrayRegThirtyThree[90];
byte dataArrayRegThirtyFour[90];

void setup() {
//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
Serial.begin(9600);
}

void loop() {
dataArrayRegOne[0] = 0x92; //01001001 (6D)10110110
dataArrayRegOne[1] = 0x49; //10010010 (B6)01101101
.
.
.

dataArrayRegOne[88] = 0x49; //11011011
dataArrayRegOne[89] = 0x24; //11011011

.
.
.
.

dataArrayRegThirtyFour[0] = 0x92; //10110110
dataArrayRegThirtyFour[1] = 0x49; //01101101
dataArrayRegThirtyFour[2] = 0x24; //11011011

.
.
.
dataArrayRegThirtyFour[31] = 0xB6; //01101101
dataArrayRegThirtyFour[32] = 0xDB; //11011011
dataArrayRegThirtyFour[33] = 0x6D; //10110110
dataArrayRegThirtyFour[34] = 0xB6; //01101101
dataArrayRegThirtyFour[35] = 0xDB; //11011011
dataArrayRegThirtyFour[36] = 0x6D; //10110110
dataArrayRegThirtyFour[37] = 0xB6; //01101101
dataArrayRegThirtyFour[38] = 0xDB; //11011011
dataArrayRegThirtyFour[39] = 0x6D; //10110110
dataArrayRegThirtyFour[40] = 0xB6; //01101101
dataArrayRegThirtyFour[41] = 0xDB; //11011011
dataArrayRegThirtyFour[42] = 0x6D; //10110110
dataArrayRegThirtyFour[43] = 0xB6; //01101101
dataArrayRegThirtyFour[44] = 0xDB; //11011011
dataArrayRegThirtyFour[45] = 0xB6; //01101101
dataArrayRegThirtyFour[46] = 0xDB; //11011011
dataArrayRegThirtyFour[47] = 0x6D; //10110110
dataArrayRegThirtyFour[48] = 0xB6; //01101101
dataArrayRegThirtyFour[49] = 0xDB; //11011011
dataArrayRegThirtyFour[50] = 0xB6; //01101101
dataArrayRegThirtyFour[51] = 0xDB; //11011011
dataArrayRegThirtyFour[52] = 0x6D; //10110110
dataArrayRegThirtyFour[53] = 0xB6; //01101101
dataArrayRegThirtyFour[54] = 0xDB; //11011011
dataArrayRegThirtyFour[55] = 0x6D; //10110110
dataArrayRegThirtyFour[56] = 0xB6; //01101101
dataArrayRegThirtyFour[57] = 0xDB; //11011011
dataArrayRegThirtyFour[58] = 0x6D; //10110110
dataArrayRegThirtyFour[59] = 0xB6; //01101101
dataArrayRegThirtyFour[60] = 0xDB; //11011011
dataArrayRegThirtyFour[61] = 0x6D; //10110110
dataArrayRegThirtyFour[62] = 0xB6; //01101101
dataArrayRegThirtyFour[63] = 0xDB; //11011011
dataArrayRegThirtyFour[64] = 0x6D; //10110110
dataArrayRegThirtyFour[65] = 0xB6; //01101101
dataArrayRegThirtyFour[66] = 0xDB; //11011011
dataArrayRegThirtyFour[67] = 0x6D; //10110110
dataArrayRegThirtyFour[68] = 0xB6; //01101101
dataArrayRegThirtyFour[69] = 0xDB; //11011011
dataArrayRegThirtyFour[70] = 0x6D; //10110110
dataArrayRegThirtyFour[71] = 0xB6; //01101101
dataArrayRegThirtyFour[72] = 0xDB; //11011011
dataArrayRegThirtyFour[73] = 0x6D; //10110110
dataArrayRegThirtyFour[74] = 0xB6; //01101101
dataArrayRegThirtyFour[75] = 0xDB; //11011011
dataArrayRegThirtyFour[76] = 0x6D; //10110110
dataArrayRegThirtyFour[77] = 0xB6; //01101101
dataArrayRegThirtyFour[78] = 0xDB; //11011011
dataArrayRegThirtyFour[79] = 0x6D; //10110110
dataArrayRegThirtyFour[80] = 0xB6; //01101101
dataArrayRegThirtyFour[81] = 0xDB; //11011011
dataArrayRegThirtyFour[82] = 0x6D; //10110110
dataArrayRegThirtyFour[83] = 0xB6; //01101101
dataArrayRegThirtyFour[84] = 0xDB; //11011011
dataArrayRegThirtyFour[85] = 0xB6; //01101101
dataArrayRegThirtyFour[86] = 0xDB; //11011011
dataArrayRegThirtyFour[87] = 0x6D; //10110110
dataArrayRegThirtyFour[88] = 0xB6; //01101101
dataArrayRegThirtyFour[89] = 0xDB; //11011011

//while(Serial.available()>0){
// letter= Serial.read();
// if(letter==‘P’){
// for(int k=0; k<3; k++){// repeat sequence n times
for (int j = 0; j < 90; j++) {//shift out
//load the light sequence you want from array
dataOne = dataArrayRegOne[j];
dataTwo = dataArrayRegTwo[j];
dataThree = dataArrayRegThree[j];
dataFour = dataArrayRegFour[j];
dataFive = dataArrayRegFive[j];
dataSix = dataArrayRegSix[j];
dataSeven = dataArrayRegSeven[j];
dataEight = dataArrayRegEight[j];
dataNine = dataArrayRegNine[j];
dataTen = dataArrayRegTen[j];
dataEleven = dataArrayRegEleven[j];
dataTwelve = dataArrayRegTwelve[j];
dataThirteen = dataArrayRegThirteen[j];
dataFourteen = dataArrayRegFourteen[j];
dataFifteen = dataArrayRegFifteen[j];
dataSixteen = dataArrayRegSixteen[j];
dataSeventeen= dataArrayRegSeventeen[j];
dataEighteen = dataArrayRegEighteen[j];
dataNineteen = dataArrayRegNineteen[j];
dataTwenty = dataArrayRegTwenty[j];
dataTwentyOne = dataArrayRegTwentyOne[j];
dataTwentyTwo = dataArrayRegTwentyTwo[j];
dataTwentyThree = dataArrayRegTwentyThree[j];
dataTwentyFour = dataArrayRegTwentyFour[j];
dataTwentyFive = dataArrayRegTwentyFive[j];
dataTwentySix = dataArrayRegTwentySix[j];
dataTwentySeven = dataArrayRegTwentySeven[j];
dataTwentyEight = dataArrayRegTwentyEight[j];
dataTwentyNine = dataArrayRegTwentyNine[j];
dataThirty = dataArrayRegThirty[j];
dataThirtyOne = dataArrayRegThirtyOne[j];
dataThirtyTwo = dataArrayRegThirtyTwo[j];
dataThirtyThree = dataArrayRegThirtyThree[j];
dataThirtyFour = dataArrayRegThirtyFour[j];

//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, 0);
//move 'em out
shiftOut(dataPin, clockPin, dataThirtyFour);
shiftOut(dataPin, clockPin, dataThirtyThree);
shiftOut(dataPin, clockPin, dataThirtyTwo);
shiftOut(dataPin, clockPin, dataThirtyOne);
shiftOut(dataPin, clockPin, dataThirty);
shiftOut(dataPin, clockPin, dataTwentyNine);
shiftOut(dataPin, clockPin, dataTwentyEight);
shiftOut(dataPin, clockPin, dataTwentySeven);
shiftOut(dataPin, clockPin, dataTwentySix);
shiftOut(dataPin, clockPin, dataTwentyFive);
shiftOut(dataPin, clockPin, dataTwentyFour);
shiftOut(dataPin, clockPin, dataTwentyThree);
shiftOut(dataPin, clockPin, dataTwentyTwo);
shiftOut(dataPin, clockPin, dataTwentyOne);
shiftOut(dataPin, clockPin, dataTwenty);
shiftOut(dataPin, clockPin, dataNineteen);
shiftOut(dataPin, clockPin, dataEighteen);
shiftOut(dataPin, clockPin, dataSeventeen);
shiftOut(dataPin, clockPin, dataSixteen);
shiftOut(dataPin, clockPin, dataFifteen);
shiftOut(dataPin, clockPin, dataFourteen);
shiftOut(dataPin, clockPin, dataThirteen);
shiftOut(dataPin, clockPin, dataTwelve);
shiftOut(dataPin, clockPin, dataEleven);
shiftOut(dataPin, clockPin, dataTen);
shiftOut(dataPin, clockPin, dataNine);
shiftOut(dataPin, clockPin, dataEight);
shiftOut(dataPin, clockPin, dataSeven);
shiftOut(dataPin, clockPin, dataSix);
shiftOut(dataPin, clockPin, dataFive);
shiftOut(dataPin, clockPin, dataFour);
shiftOut(dataPin, clockPin, dataThree);
shiftOut(dataPin, clockPin, dataTwo);
shiftOut(dataPin, clockPin, dataOne);

//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, 1);
delay(1000);
}//shift out
// }//repeat sequence n times
// }//if serial read
// }//while.Serial

}//void loop

// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low

//internal function setup
int i=0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);

//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);

//for each bit in the byte myDataOut?
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %0000 0001 or “1” will go through such
//that it will be pin Q0 that lights.
for (i=0; i>=0; i–) {
digitalWrite(myClockPin, 0);

//if the value passed to myDataOut and a bitmask result
// true then… so if we are at i=6 and our value is
// %1101 0100 it would the code compares it to %0100 0000
// and proceeds to set pinState to 1.
if ( myDataOut & (1<<i) ) {
pinState= 1;
}
else {
pinState= 0;
}

//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
}

//stop shifting
digitalWrite(myClockPin, 0);
}

Wow - okay, I'll certainly give you an A+ for valiant effort! I think it could be simplified a lot.

Put all your data in an array in progmem:

// define data, put in Flash memory
const byte PROGMEM dataArray[] = {
0x00, 0x01, 0x02,0x03,0x04,0x05, ... total of 34 bytes, // row 0
0x00, 0x01, 0x02,0x03,0x04,0x05,... total of 34 bytes, // row 1
0x00, 0x01, 0x02,0x03,0x04,0x05, ... total of 34 bytes, // row 2
0x00, 0x01, 0x02,0x03,0x04,0x05, ... total of 34 bytes, // row 3 
:
:
0x00, 0x01, 0x02,0x03,0x04,0x05, ... total of 34 bytes, // row 87
0x00, 0x01, 0x02,0x03,0x04,0x05, ... total of 34 bytes, // row 88 - 89 rows total
};

Then shift out the bytes one row at a time using an index to keep track of where you are and blink without delay style timing to keep track of how long to display the data - it will take a maybe 40-50 microSeconds to do the SPI.transfers, so you can set the duration accordingly. Use direct port manipulation instead of digitalWrite to make the csPin changes faster also. The index will track which row of the dataArray you are sending out.

void loop(){
currentTime = micros();
elapsedTime = currentTime - nextTime;
if (elapsedTime >= duration){
nextTime = nextTime + duration;
indexCount = indexCount +1;
if (indexCount == 89){indexCount = 0;}
digitalWrite(csPin, LOW);
SPI.transfer(dataArray[(indexCount * 34) +0]); // so 0,1,2,3 ... up to  31,32,33
SPI.transfer(dataArray[(indexCount * 34) +1]); // then 34,35,36, ... up to  65,66,67 
SPI.transfer(dataArray[(indexCount * 34) +2]); // then 68,69,70 ... up to 97,98,99 
SPI.transfer(dataArray[(indexCount * 34) +3]);
:
:
SPI.transfer(dataArray[(indexCount * 34) +32]);
SPI.transfer(dataArray[(indexCount * 34) +33]);
digitalWrite(csPin, HIGH);
} // end time check
} // end loop

Thank you CrossRoads, you have been a lot of help.

The code that you sent over previously has been really helpful but the problem is when we try to implement it using an arduino and 1 shift register with 3 leds just for testing.

We are having a problem with trying to use the SPI.transfer(dataArray[j]) in a for loop. The loop does not go through the iteration parameters that we set up and instead only makes the LEDs blink the first value. here is the code:

#include <avr/pgmspace.h>
#include <SPI.h>
//Pin connected to ST_CP of 74HC595
int latchPin = 10;
int i= 0;
int indexCount;

const byte PROGMEM dataArray[] = {0xB6,0x6D,0xDB};  



void setup(){
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  digitalWrite(latchPin, HIGH);
  SPI.begin();
}
void loop(){

 
for (i=0; i<3; i++) {
  PORTB=PORTB&0B11111011;
  SPI.transfer(dataArray[i]);
  PORTB=PORTB|0B00000100;
 delay(1000);

}

}

we really appreciate the help.

disregard the last question, we got it to work :slight_smile:

What'd you do different to make it work?