Go Down

Topic: Shift registers and LED's (Read 11103 times) previous topic - next topic

CrossRoads

There is no reason for you to change this and this:

Code: [Select]

byte cathodePins[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};  // used to turn on 1 cathode at a time


Code: [Select]

void loop(){

timeNow = millis(); // capture the current 'time'
if ((timeNow - previousTime)>= elapsedTime){  // display refresh time?
previousTime = previousTime + elapsedTime; //setup for next pass

// keep track of which column is being written
anodeColumn = anodeColumn+1;
if (anodeColumn == 8){anodeColumn = 0;}  // reset after going 0,1,2,3,4,5,6,7 >> 0

// turn off current cathode
digitalWrite (SScathodes, LOW);
SPI.transfer(0); // 0 = all cathode off >> assumes HC595 driving base of NPN transistor or ULN2803
digitalWrite (SScathodes, HIGH);

// shift out next set of anodes
digitalWrite (SSanodes, LOW);
SPI.transfer(dataArray[anodeColumn]); // read data from the array and send it out
digitalWrite (SSanodes, HIGH);

// turn the next cathode on
digitalWrite (SScathodes, LOW);
SPI.transfer(cathodePins[anodeColumn]); // 0 = all cathode off >> assumes HC595 driving base of NPN transistor or ULN2803
digitalWrite (SScathodes, HIGH);

} // end of time check


All you should be changing is the data in here:
dataArray[]= {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; 

Do whatever you're going to do that array, the code at the beginning of void loop() will then display it.
DO NOT turn on two cathodes at once.

If you want multiple anodes in a Row to be on, then you have to set the same bit in the anode array:

cccccccc
76543210

10000000
01000000
00111000
00010000
00001000
00000111
00000010
00000001

and rotate it 90 degrees so the code can recognize it:
dataArray[7] = B10000000  column 7
dataArray[6] = B01000000  column 6
dataArray[5] = B00111000  column 5
dataArray[4] = B00010000  column 4
dataArray[3] = B00001000  column 3
dataArray[2] = B00000111  column 2
dataArray[1] = B00000010  column 1
dataArray[0] = B00000001  column 0
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.

Pedro147


I am a bit slow on the uptake sometimes   8)  but I think that maybe now I am getting it.
I should leave the code in byte cathodePins as;

{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};   or

B10000000, B01000000, B00100000, B00010000, B00001000, B00000100, B00000010, B00000001 

Seeing as I will be coding the dataArray in Binary.

This is because the basic principle of multiplexing is POV where only one LED is on at any given time and this code "sweeps" through the cathodes sequentially one at a time and then repeats, the individual switching of the LED's being  controlled by the anodes.

So the way I was coding the anodes via the dataArray was right but I was mistakenly switching on more than one cathode at a time which will damage the IC in the Arduino.

Does it sound like I now have a better understanding or am I still kidding myself. Thanks Pedro

http://www.pedroduino.com

CrossRoads

Almost -
"This is because the basic principle of multiplexing is POV where only one LED is on at any given time "
The POV we have going turns one whole column at a time, up to 8 LEDs. That's why we use the ULN2803, or TPIC6B595, for the cathodes.

If you want a whole row to appear on, then you leave the same anode on, and the action of quickly turning the cathodes on one by one fools and POV makes it look like the whole row is on.
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.

Pedro147

#33
Aug 12, 2012, 11:18 am Last Edit: Aug 12, 2012, 02:36 pm by Pedro147 Reason: 1
I will just have to think about that for a short while. Just when I think I understand…
I shoot myself down in flames  :D
http://www.pedroduino.com

Pedro147

#34
Aug 12, 2012, 01:44 pm Last Edit: Aug 12, 2012, 02:43 pm by Pedro147 Reason: 1
I realise that I may be labouring over this point, but I dislike thinking that I understand a process when I do not. So….
What is happening is that the ULN2803 is supplying ground to each column one after the other. It is being controlled by the cathode shift register as it shifts out a byte of data with one bit a digital one and the other seven bits zero's. The bit that is digital one changes sequentially from the first position in the byte to the last position in the byte.  The anode shift register shifts out it's byte of data determining which row or rows is supplied power. Therefore we could have a situation where more than one LED is illuminated at the same time (from one to eight LED's)
This differs from multiplexing because in that situation power and ground is only supplied to one LED at a time.
Am I any closer to enlightenment, Pedro?
http://www.pedroduino.com

CrossRoads

#35
Aug 13, 2012, 08:26 am Last Edit: Aug 13, 2012, 08:28 am by CrossRoads Reason: 1
Soooo close!  Who says we're limited to multiplexing just 1 bit?  Lets multiplex 8 bits!

When an anode is driven, all the anodes in that row are driven. As only 1 cathode is turned on, only LED in that 1 column is turned on.
To make things efficient, all 8 anodes are driven together - but still just 1 cathode, so only 1 column is turned on.

This makes the multiplexing faster. Up to 8 LEDs are switched at a time, versus just 1 LED. So 8 cathode cycles, 64 LEDs.

It is also quicker - read a byte from memory, write the byte to the anodes, turn on a column. Repeat 8 times. Hardware SPI used to shift out the bytes, very fast.
Compare to read a byte from memory, mask off the 7 non-driven anode bits, write the byte to the anodes, turn on a cathode. Bigger software effort to pick off the one bit to be made high from the byte each time. Repeat 64 times.

So just the Repeat 8 times vs Repeat 64 times is a huge speed advantage.

Downside to 8 bits: a part like ULN2803 is needed.
Upside: Brighter display. Faster updates. Easier software. Win-Win-Win.

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.

Pedro147

How does that saying go? So close yet so far... I'll just ruminate on that information for a while.
I'm determined to get my head around this.   8)
http://www.pedroduino.com

Enviux

I have a quick question as a noob to the 74HC595 Shift registers I am working on shifting out pins for an LED matrix and was just getting started when I noticed that my Pin Q0 (parallel data output 0) pin 15 is putting out a lot more voltage than the other 7 pins.

Here is the information to reconstruct what I have done on a bread board:

I have it hooked up to my Arduino Uno and Shift Register (NXP 74HC595N) like the image in step 2 of Example 1 of the Serial to Parallel Shift Out description found at this page http://www.arduino.cc/en/Tutorial/ShiftOut

Except my power is connected to Arduino 3.3V and I am using DS 595 pin 14 to Arduino data pin 9, SHCP 595 pin 11 to Arduino clock pin 10, and 595 STCP pin 12 to Arduino latch pin 11

The code running is designed to turn all pins on and is as follows:
Code: [Select]


int latchPin = 11;             //595 pin 12
int clockPin = 10;          //595 pin 11
int dataPin = 9;           //595 pin 14
//595 pin 16 has 5VDC
//595 pin 8 has GND

void setup() {
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
   digitalWrite(latchPin, HIGH);
   delay(5000);
}




Now that I have that out of the way... I plug in the  Arduino to a 12 volt source and metered each of the parallel pins of the register 1-7, 15. I get about 0.045 from each pin until I get to number 15 which shows 0.991. I first noticed the issue when trying to light a small string of leds like in the example and one of the leds was much brighter than the others. I have tried two different shift registers with the same results and can not find any documentation so far that points to a difference between 595 pin 15 versus the other 595 1-7 pins.

Like I said I am new to this and could be missing something obvious.

CrossRoads

http://www.nxp.com/documents/data_sheet/74HC_HCT595.pdf

First thing: If you have a cap on pin 12, remove it. That is incorrect. We have asked to have that corrected numerous times. It can only damage the Arduino output pin it is connected to.

You have Arduino uC powered at 5V?
So it has 0 to 5V outputs?

You have 74HC595 powered at 3.3V?
Its inputs should be in the range of -0.5V to +3.8V:
VIn < -0.5V or VIn > VCC + 0.5V
So you have a problem there potentially.

The Arduino also has limited current capability at 3.3V.  You could be seeing that with all current going into the first LED and the rest being underpowered.

What do you have for current limit resistors between its output pins, LEDs, and Gnd?
Do you have HC595 pin 13, Output Enable, connected to Gnd?
Do you have HC595 pin 10, Master Clear, connected to pin 16?
Do you have a 0.1uF cap from pin 16 to Gnd?
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.

Enviux

OK, like I said I am new, and I made a noob mistake. Thanks CrossRoads. You didn't mention it but in checking my board against your various thoughts I found that my GRD pin 8 was not in fact grounded. I have corrected the board and now recieve 0.12 V on 1-7,and 15. Thanks!

I am sure I will have a few more questions as I work through my new project of building an 16x16 RGB LED matrix using PWM. Thanks for the quick response.

CrossRoads

Ok. Please post your questions as a new thread.
You can start it by looking at TLC5940 and WS2803 for PWM controllers for LEDs.
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.

Pedro147

I have been looking at the SPI code you wrote that I have been using on my matrix  to display static characters, and even though I admit I still don't fully understand the intricacies of the cathode and anode switching in this circuit, I understand that all this i.e using SPI for data transmission and the ULN2803 for cathode sinking, is a very fast and efficient way of displaying on LED matrixes. I would still like to display some scolling text and although I think I understand the basic concept the actual implementation has me totally baffled. To be honest in desparation I found some other examples on the internet of how to scroll text using the two shift registers but no SPI and although they worked they were very inefficient  taking up large amounts of memory to do relatively basic tasks.

I  think that I previously said that if I can look at some code that performs the basic function of what I am after (scrolling text) it is easier for me to modify it's output and thus learn to understand a little more of how it works. Would it be possible for you to show me how to incorporate the following arrays into the code to scroll PEDRO"

B00000000, B00111000, B00100100, B00100100, B00111000, B00100000, B00100000, B00000000  //P

B00000000, B00111100, B00100000, B00111000, B00111000, B00100000, B00111100,  B00000000  //E

B00000000, B00111000, B00100100, B00100100, B00100100, B00100100, B00111000, B00000000   //D

B00000000, B00111000, B00100100, B00100100, B00111000, B00101000, B00100100, B00000000   //R

B00000000, B00011000, B00100100, B00100100, B00100100, B00100100, B00011000, B00000000   //O

I hope you do not think that I am lazy ...just very challanged by all this   8)

Thanks again if you can help, Pedro.
http://www.pedroduino.com

CrossRoads

#42
Aug 26, 2012, 08:01 am Last Edit: Aug 26, 2012, 08:03 am by CrossRoads Reason: 1
byte letterP[8] = {B00000000, B00111000, B00100100, B00100100, B00111000, B00100000, B00100000, B00000000 }; //P
byte letterE[8] = {B00000000, B00111100, B00100000, B00111000, B00111000, B00100000, B00111100,  B00000000 };  //E
byte letterD[8] = {B00000000, B00111000, B00100100, B00100100, B00100100, B00100100, B00111000, B00000000 };   //D
byte letterR[8] = {B00000000, B00111000, B00100100, B00100100, B00111000, B00101000, B00100100, B00000000 };   //R
byte letterO[8] = {B00000000, B00011000, B00100100, B00100100, B00100100, B00100100, B00011000, B00000000 };   //0

P            E
00000000 00000000
00000000 00000000
01111110 01111110
01001000 01011010
01001000 01011010
00110000 01000010
00000000 00000000
00000000 00000000

(These might need rotating 90 degrees counterclockwise)

You have code that does SPI.transfer's with data from displayArray[] every 1mS or something, yes?
So we'll just move data thru that array.

Make a 40 letter storage array:
Code: [Select]

displayStore[0] = letterP[0];
displayStore[1] = letterP[1];
displayStore[2] = letterP[2];
displayStore[3] = letterP[3];
displayStore[4] = letterP[4];
displayStore[5] = letterP[5];
displayStore[6] = letterP[6];
displayStore[7] = letterP[7];

displayStore[8] = letterE[0];
displayStore[9] = letterE[1];
displayStore[10] = letterE[2];
displayStore[11] = letterE[3];
displayStore[12] = letterE[4];
displayStore[13] = letterE[5];
displayStore[14] = letterE[6];
displayStore[15] = letterE[7];

displayStore[16] = letterD[0];
displayStore[17] = letterD[1];
displayStore[18] = letterD[2];
displayStore[19] = letterD[3];
displayStore[20] = letterD[4];
displayStore[21] = letterD[5];
displayStore[22] = letterD[6];
displayStore[23] = letterD[7];

displayStore[24] = letterR[0];
displayStore[25] = letterR[1];
displayStore[26] = letterR[2];
displayStore[27] = letterR[3];
displayStore[28] = letterR[4];
displayStore[29] = letterR[5];
displayStore[30] = letterR[6];
displayStore[31] = letterR[7];

displayStore[32] = letterO[0];
displayStore[33] = letterO[1];
displayStore[34] = letterO[2];
displayStore[35] = letterO[3];
displayStore[36] = letterO[4];
displayStore[37] = letterO[5];
displayStore[38] = letterO[6];
displayStore[39] = letterO[7];

displayStore[40] = 0;
displayStore[41] = 0;
displayStore[42] = 0;
displayStore[43] = 0;
displayStore[44] = 0;
displayStore[45] = 0;
displayStore[46] = 0;
displayStore[47] = 0;


And now every 1/2 second we'll move data from displayStore into displayArray to be shifted out:
Code: [Select]

currentStore = millis();
if (currentStore - previousStore >= elapsedStore){
previousStore = previous + elapsedStore;
storePointer = storePointer +1;
 if (storePointer == 41){storePointer = 0;} // reset to start of storage
//loop thru the 8 columns
 for (arrayPointer = 0; arrayPointer <8; arrayPointer = arrayPointer+1){
// and update the displayArray
 displayArray[arrayPointer] = storeArray[storePointer +arrayPointer]; // so [0] = storePointer + 0, [1] = sP +1 ...
 }
}
// now on next 1mS interval, the new data will get shifted out

There's better ways to do this, with the letter definitions being stored in program memory and accessed from there, but this gives you the basics of having an array that that gets put into the shift registers, and updating that array from somewhere else:
P         E         D         R        O         blank...
123456712345671234567123456712345671234567
|          |  show these 8
|          | then 1/2 second later these 8
 |          | then 1/2 second later these 8
  |          | and so on every 1/2 second
                                                    |         | and after these go back to the beginning
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.

Pedro147

I know that to you guys this is all second nature, but please humour me 

These arrays are for each letter (P,E,D,R, and O)

byte letterP[8] = {B00000000, B00111000, B00100100, B00100100, B00111000, B00100000, B00100000, B00000000 }; //P

The  displayStore[0] = letterP[0]; to  displayStore[8] = letterP[8];
allow that letter "P" to move across the display followed by  the E, D, R, AND O.

The  "displayStore into displayArray" code  basically just tell all this how and when to happen. I rellise that this is possibly the most inept description possible but I am at my limit of understanding here  (I do come from convict stock  8) )

To make your work here of use to me how do I incorporate it into the code that I am currently using?  Thanks Pedro.
http://www.pedroduino.com

CrossRoads

"The  "displayStore into displayArray" code  basically just tell all this how and when to happen."
Exactly. Its like having a buffer that the world sees, and you are deciding when to change that buffer.

Lets see the code you are currently using.

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.

Go Up