Go Down

Topic: Shift Registers - shifting in an array of bits (Read 5447 times) previous topic - next topic

gohangaslami

I am trying to control a dual-color 8x80 LED display.
I have 10 8x8 (common anode) LED matrices and i plan to run the columns with 10 74HC595 shift registers (and the 16 rows [8 red, 8 green] with 2 more shift registers)

The way my code currently works, it has stored a 2-dimensional array of bits representing which LEDs should be on and off. so if it were displaying a checkerboard pattern, the array would look like this:

bit MyArray[8][80]=
{
{1,0,1,0,1,0,1,0,1,0,1...},
{0,1,0,1,0,1,0,1,0,1,0...},
{1,0,1,0,1,0,1,0,1,0,1...},
{0,1,0,1,0,1,0,1,0,1,0...},
{1,0,1,0,1,0,1,0,1,0,1...},
{0,1,0,1,0,1,0,1,0,1,0...},
{1,0,1,0,1,0,1,0,1,0,1...},
{0,1,0,1,0,1,0,1,0,1,0...}
};

How do i send each row to the shift registers? using ShiftOut, i could only find how to send 8 bits at a time in Decimal or Hex. I'm looking for a simple way to just send the binary.

is there a way to do something like this:
For int x = 80 to 1 x--
  ShiftOut(DataPin, ClockPin, MyArray[row]

  • next x

    any suggestions on how to do this, or other project help in general would be greatly appreciated.

cmagagna

#1
Jan 18, 2012, 01:05 am Last Edit: Jan 18, 2012, 01:07 am by Chris Magagna Reason: 1
I can think of three ways:

1. Instead of ShiftOut sending a byte at a time, write your own code that flips the pins yourself:

Code: [Select]
For int x = 80 x to 1 x--
 digitalWrite(ClockPin, HIGH);
 digitalWrite(DataPin, MyArray[row]);
 digitalWrite(ClockPin, LOW);
next x


2. Walk your array in 2 loops, an outer loop that increments / decrements 8 at a time, and an inner loop that moves bit by bit and builds a byte. When the inner loop's done, ShiftOut() it like normal.

3. Instead of storing your array data as bytes of bits store it as bytes of bytes

MyArray[8][10] = {
{B1010101010, B1010101010 ...}
etc.
}

Good luck!

pYro_65

The smallest addressable memory size is 1 byte, you cannot have an array of bits.
I have an implementation that will allow shifting any amount of bits,
here is the post.
http://arduino.cc/forum/index.php/topic,83907.msg637427.html#msg637427

If you aren't sure on what to do I can help you set it up
Forum Mod anyone?
https://arduino.land/Moduino/

gohangaslami

pYro65: The array in my code is actually of type Int, just described it as bit because i'm only using 1s and 0s (is there a more efficient, equally easy, way to do this?)

Chris Magagna: I'm leaning towards option 1 because of its ease of implementation, though this sort of manual bit-bang approach doesn't seem very efficient (like nearly all of my code)

Maybe it would help if i described in more detail what i'm trying to do:
This display will be used as a scrolling marquee. I already wrote programs running on my computer to scrape stock prices from the internet, then convert that into a 2-dimensional array of 1s and 0s that is 8 'pixels' high and about 300 'pixels' long (it varies depending on how many stocks, what the prices are, etc).
[technically, it creates 2 arrays of this size, one for the red LEDs and one for the green LEDs. Stock ticker symbols will be displayed in orange (green and red), prices up that day will be green and prices down will be red]

my plan is to send this array to an arduino every 10 min and have it scrolled across my display. as the display is only 80 LEDs long, it will have to scroll through the 300 column text.
because this means displaying columns 1-80, then 2-81, then 3-83 etc. i don't think storing the 80 bits as 10 bytes will work.

If i manually flip the bits for 10 shift registers, and then have to repeat 16 times to pulse all of the rows (8 red, 8 green), will the 16mhz of the arduino be fast enough for persistence of vision to make it look solid?

I'm still very new to electronics. Any and all critiques, suggestions, advice, and help is welcome

cmagagna

#4
Jan 18, 2012, 06:08 am Last Edit: Jan 18, 2012, 06:10 am by Chris Magagna Reason: 1
Sounds cool. How much have you already built and / or programmed? I may have some ideas...

PS - no problem at all on getting a 16 MHz arduino to run 8 groups of LEDs fast enough for POV to prevent flicker.

CrossRoads

Well, its really more like 16 groups with the dual color, no?
8 x 80 x 2 = 1280 bytes of RAM representing the state of the display, out of 2048 available in a '328.
So  you're going to have the 2 side shift register output data while the bottom shift registers walk a 0 along to turn 1 column on at a time?
The bottom shift registers have to be able to sink 8 LEDs worth of current, 74HC595 is not up to that, only for 6-8 mA, certainly not 160mA (20mA/LED).
Part like TPIC6B595 would be more capable. TI.com for datasheet, parts available from avnet.com

You would only have Red or Green displayed with an 8x8 version of a part  like this?
http://www.mpja.com/download/16784op.pdf
I would write a loop that shifts a 0 into cathode 1 which is connected to the Red & Green cathodes for column, then turns on the anodes with the Red or Green data for column 1. Turn off column 1. Clock the bottom shift register once to move the 0 to then column, then turn on the anodes for column2. Then off.
Repeat.
Code: [Select]

// PSEUDO CODE
byte red_data[80];
byte green_date [80];
void setup(){
//turn off the cathodes
digitalWrite (SS, LOW);  // latch clock for anode shift register
SPI.transfer(red_data[x]);
SPI.transfer(green_data[x]);
digitalWrite (SS HIGH);  // now red/green data is on the anodes
// clear the cathode_drivers out
digitalWrite (cathode_pin , HIGH); // assumes 1 =  HIIGH = Off
digitalWrite (cathode_clock, LOW);
for (x = 0 to 79){
// 80 clocks, puts 1 at all outputs
digitalWrite(cathode_clock, HIGH);
digitalWrite (cathode_clock, LOW);
}

cathode_data = 0;
void loop(){
for (x=0 to 79){
digitalWrite (SS, LOW);  // latch clock for anode shift register
SPI.transfer(red_data[x]);
SPI.transfer(green_data[x]);
digitalWrite (SS HIGH);  // now red/green data is on the anodes
digitalWrite(cathode_clock, HIGH); // first time in the for:next loop, clocks 0 into shift register 0
digitalWrite (cathode_clock, LOW);
digitalWrite(cathode_data, HIGH);  // and then a 1 after that
} //end for 0-79

//when ready to move data along one column:
// udpate array data, move everything along 1
for (x=0 to 79){
red_data[x+1] = red_data[x]
green_date[x+1] = green_data[x]
}
red_data[0] = red_data[80];  //for the wrap around!
green_date[0] = red_data[80];   // or load up with new data


cathode_data = 0;  // get ready for next pass thru
} // end void loop
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

gohangaslami

Haven't started building any of it.
just got in all of the parts and built a test rig for the LED matrices.

Already wrote a stock price scraper that looks at yahoo finance, checks the prices and movements of the stocks in a portfolio, and creates a text string (ie: "F 23.20 +.27   HOG 46.50 -.11   PG 102.88 +1.01") and stores it locally.
Also wrote a program that picks up this file, and converts it into a matrix of 1s and 0s and stores that to be sent to the arduino. this is being re-written. i'm thinking it would be easier to only make 1 array and have 4 states instead of just using 1s and 0s. Because this is being stored as Integers anyway, 0 would be off, 1 would be green, 2 would be red, and 3 would be red and green.
then on the arduino, i can do something like this:

int CompleteMessage[8][300]
int MyArray[8][80]
assign 80 columns of CompleteMessage to MyArray

Loop:
'pulse the red LEDs for each of the 8 rows 
   for int RedRows = 1 to 8 RedRows++
      for int Columns = 80 to 1 Columns--
         if MyArray[RedRows][Columns]=2 or 3 then send a 1 to shift register, else send a 0
      next Columns
      Pulse on row RedRows (rows 1 to 8 control the red LEDs)
   next RedRows

'pulse the green LEDs for each of the 8 rows 
   for int GreenRows = 1 to 8 GreenRows++
      for int Columns = 80 to 1 Columns--
         if MyArray[GreenRows][Columns]=1 or 3 then send a 1 to shift register, else send a 0
      next Columns
      pulse on row GreenRows+8 (rows 7 to 16 control the green LEDs)
   next GreenRows

   check if enough time has passed, if it has then
   move over one "pixel" on the message (ie. assign rows 2 to 81 of CompleteMessage to MyArray)
end loop


that last function that assigns 80 columns of a larger array and moves over one space every iteration (and goes back to the beginning when it reaches the end) has already been written. i thought it would be much easier than it was. if anyone knows an easier way to do this, please let me know. here's how i did it:
Code: [Select]

void move()//assign the the values for 80 colums of "CompleteMessage" to array "MyArray" (which can only hold 80 colums)
{
nowposition = startposition;//both variables start at 0, startposition tracks the first column that should be transfered to array "MyArray"
for(int y=0;y<80;y++)//for loop for columns of the message
for(int x=0;x<8;x++)//for loop for rows of the message
{
if (y+nowposition==messageLength)//if you have reached the end of the message
{
nowposition=0-y;//go back to the beginning of the message
}
MyArray[x][y]=CompleteMessage[x][nowposition+y];//assign this pixel of the message to the array "MyArray"
}
startposition++;//the next time this function runs, it will start one column over (thus scrolling through the text)
if (startposition>=messageLength)//once the start position reaches the end of message, move it back to the start
{
startposition=0;
}
}

gohangaslami

CrossRoads: Correct that the shift registers can only supply about 10ma/LED if all 8 are on at once. I had planned on running them on only 10ma (the 595s are rated for 35ma/pin and a max of 75ma total. i'm assuming 80ma for a fraction of a sec won't kill them)
as for sinking the current, i'm using 2 more 595's driving N-MOSFETs on the 16 rows (8 red, 8 green)

I only sort of understand your suggestion, pulsing the 80 columns instead of the 16 rows.
the problem then becomes 1 pin on a shift register must drive up to 16 LEDs (or only 8 if i pulse the red and green separately). i suppose this could be solved with 80 more transistors.

CrossRoads

You're gonna smoke your parts:
35/pin and 70/vcc or ground pin are absolute maximums. Further:

"Stresses beyond those listed under absolute maximum ratings may cause permanent damage to the device. These are stress ratings
only, and functional operation of the device at these or any other conditions beyond those indicated under recommended operating
conditions is not implied. Exposure to absolute-maximum-rated conditions for extended periods may affect device reliability."

You should P Mosfets sourcing current to the anodes, not N channel.
If you need both red/green on at same, then  yeah, more sink current capability needed.
I don't see how you could scroll otherwise - you'd need to source current for all 80 (or 160) LEDs at one time and turn on all 80 cathode drivers at once?

So I suggest instead - 1 cathode, pulse column on/off with anode data.  next cathode, pulse column on/off with anode data.
Then anode driver doesn't need to be high current. Cathode only relatively high (16 LEDs ~ 10mA = 160mA). And you don't have to shift out 10 cathode bytes every time, just 1 clock pulse needed to move the On cathode down the line.   Will help your refresh rate a lot. 2 SPI writes for the anodes, clock pulse, 500uS delay for viewability => 24 frame/second refresh rate. (1/24 = 42mS, /80 = 500uS on time/column).
Don't need 80 transistors, just a better shift register. Look at the TPIC6B595 at www.ti.com.
http://www.ti.com/product/tpic6b595
150mA continuous, up to 1A depending on how long its pulsed on for.
Can do the pulsing  by turning anodes on/off, or cathode driver on/off via output enable.

Might even be  a Toggle bit command that can do it fast for you versus clunky digitalWrite high & low like I showed.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

gohangaslami

So i realized that because of the maximum width of letters and space between letters, i don't think it is possible for more than 5 out of 8 consecutive LEDs to be on at any given time. this means that the 74hc595s would work the way i imagined...
that being said, I think you convinced me of the benefits of doing it your way anyway. the only real downside is the additional expense. 10 TPIC6B595's are going to run over $20 whereas the 74HC595s (which i already have dozens of) are 1/10 the price.

Go Up