This tutorial shows you how to control 16 LEDs with just 3 control lines. We do this by daisy chaining 74HC595 shift registers
The 74HC595 shift register has an 8 bit storage register and an 8 bit shift register. Data is written to the shift register serially, then latched onto the storage register. The storage register then controls 8 output lines.
The figure below shows the 74HC595 pinout.
Pin 14 (DS) is the Data pin. On some datasheets it is referred to as “SER”.
When pin 11 (SH_CP or SRCLK on some datasheets) goes from Low to High the value of DS is stored into the shift register and the existing values of the register are shifted to make room for the new bit.
Pin 12 (ST_CP or RCLK on some datasheets) is held low whilst data is being written to the shift register. When it goes High the values of the shift register are latched to the storage register which are then outputted to pins Q0-Q7.
The timing diagram below demonstrates how you would set the Q0-Q7 output pins to 11000011, assuming starting values of 00000000.
The circuit we are building is showed below, followed by the build steps
We will start with an Atmega8 breadboard circuit which we have used for many of our other tutorials. We add 2 extra breadboards and route power to these.
We add the Shift Register and connect it to +5V and Ground.
We now run the following control lines between the microcontroller and Shift Register
- PC0 to DS
- PC1 to ST_CP
- Pc2 to SH_CP
These are the blue wires shown below.
Next we connect up the LEDs and resistors. I used 510 Ohm resistors, but a range of other sizes are acceptable. ohmslawcalculator.com has a great LED Resistor Calculator that you can use.
To demonstrate the circuit, I wrote a small bit of code which produces a knight rider pattern on the 8 LEDs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | #include <avr/io.h> #include <util/delay.h> #define DS_PORT PORTC #define DS_PIN 0 #define ST_CP_PORT PORTC #define ST_CP_PIN 1 #define SH_CP_PORT PORTC #define SH_CP_PIN 2 #define DS_low() DS_PORT&=~_BV(DS_PIN) #define DS_high() DS_PORT|=_BV(DS_PIN) #define ST_CP_low() ST_CP_PORT&=~_BV(ST_CP_PIN) #define ST_CP_high() ST_CP_PORT|=_BV(ST_CP_PIN) #define SH_CP_low() SH_CP_PORT&=~_BV(SH_CP_PIN) #define SH_CP_high() SH_CP_PORT|=_BV(SH_CP_PIN) //Define functions //====================== void ioinit(void); void output_led_state(unsigned char __led_state); //====================== int main (void) { ioinit(); //Setup IO pins and defaults while(1) { /* Output a knight rider pattern 10000000 01000000 00100000 00010000 00001000 00000100 00000010 00000001 00000010 00000100 00001000 00010000 00100000 01000000 */ for (int i=7;i>=0;i--) { output_led_state(_BV(i)); _delay_ms(100); } for (int i=1;i<7;i++) { output_led_state(_BV(i)); _delay_ms(100); } } } void ioinit (void) { DDRC = 0b00000111; //1 = output, 0 = input PORTC = 0b00000000; } void output_led_state(unsigned char __led_state) { SH_CP_low(); ST_CP_low(); for (int i=0;i<8;i++) { if (bit_is_set(__led_state, i)) DS_high(); else DS_low(); SH_CP_high(); SH_CP_low(); } ST_CP_high(); } |
This is all very impressive, but didn’t I say we were controlling 16 LEDs? To do this we need to add another 74HC595 shift register, more LEDs, more resistors and more orange and blue wires.
We use the Q7’ pin to daisy chain the shift registers together.
The modified circuit is shown below.
To code to produce the 16 LED knight rider pattern is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | #include <avr/io.h> #include <util/delay.h> #define DS_PORT PORTC #define DS_PIN 0 #define ST_CP_PORT PORTC #define ST_CP_PIN 1 #define SH_CP_PORT PORTC #define SH_CP_PIN 2 #define DS_low() DS_PORT&=~_BV(DS_PIN) #define DS_high() DS_PORT|=_BV(DS_PIN) #define ST_CP_low() ST_CP_PORT&=~_BV(ST_CP_PIN) #define ST_CP_high() ST_CP_PORT|=_BV(ST_CP_PIN) #define SH_CP_low() SH_CP_PORT&=~_BV(SH_CP_PIN) #define SH_CP_high() SH_CP_PORT|=_BV(SH_CP_PIN) //Define functions //=============================================== void ioinit(void); void output_led_state(unsigned int __led_state); //=============================================== int main (void) { ioinit(); //Setup IO pins and defaults while(1) { // Output a knight rider pattern for (int i=15;i>=0;i--) { output_led_state(_BV(i)); _delay_ms(50); } for (int i=1;i<15;i++) { output_led_state(_BV(i)); _delay_ms(50); } } } void ioinit (void) { DDRC = 0b00000111; //1 = output, 0 = input PORTC = 0b00000000; } void output_led_state(unsigned int __led_state) { SH_CP_low(); ST_CP_low(); for (int i=0;i<16;i++) { if ((_BV(i) & __led_state) == _BV(i)) //bit_is_set doesn’t work on unsigned int so we do this instead DS_high(); else DS_low(); SH_CP_high(); SH_CP_low(); } ST_CP_high(); } |
We just stopped at 16 LEDs, but we can continue daisy chaining more shift registers. This technique is not just limited to LEDs of course and we can use it to multiply output ports to drive many other kinds of devices.
One word of warning regarding this technique. When you power on the circuit, the output lines are set to some arbitrary value. Now it takes less than a microsecond to set them to your desired values, but for some circuits this may cause problems. In that case you can use to MR and OE pins to reset the storage registers.
Wondering what program you compiled with because it would not work with emacs. nice tutorial though. Thank
Compile with GCC and AVR libc as part of winAVR
it woude great if you have some tutorial how to program and compile using winAVR.
Does this help? http://www.protostack.com/blog/2009/08/atmega8-breadboard-circuit-part-3-of-3-the-firmware/
i have the same setup but i have some problem whit code. becouse im new to microcontrolers and code i use thet code in your tutorial but winAVR, codeblocks, mikroc shows errors. i check many times if i type corect.
I have a Netduino Board and I have created this circuit. It works well for one shift register, but I do not know what to do to tell it to use the second one. Can someone tell me what I a missing? What is the programming code that signals it to use the second shift register.
Woody
this tutorial is great. can u give schematic and program to write and display name on 8*80 LED matrix.
This tutorial has helped me so much. What program did you design the schematics in? They look gorgeous
Microsoft Visio
What program did you use for the drawing part?
My GCC compiler does not like:
#define DS_low() DS_PORT&=~_BV(DS_PIN)
What is the DS_PORT& supposed to be?
I am sure this comes from the web posting!
Thanks
Ralph
DS_PORT is defined on line 5 (#define DS_PORT PORTC).
The &= is a compound operator (see http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B). Using the the &= operator is equivalent to
#define DS_low() DS_PORT=DS_PORT&~_BV(DS_PIN)
Also, there was a problem with the web posting where it was showing “&” instead of “&”. That is now fixed.
Daniel.
Yeah thanks it was coming across as \&\a\m\p\; but for the actual code wanted to be just\&.
I got both the 8 and 16 led display to work, thank you.
Now how about 4 shift registers what do I need to do for that?
And then how about doing patterns?
I need to do things like 00001111111111111111000011111111 and various other patterns.
Thanks great tutorial, it got me started, and worked first time after minor corrections to the for syntax.
Ralph
Hi,
I like the tutorial. I wish your sample bit pattern weren’t symmetrical so it would show which bit went to Q0 and which went to Q7. I assume first in goes to Q7, and last to Q0, right?
Steve
Hi,
i get this error while trying to run the code for 8 LED. I hope somebody can help me with something as i’m very new to this programming world. thanks in advance
main.c: In function ‘main’ :
main.c:50:11: error: stray ‘\226’ in program
main.c:50:11: warning: statement with no effect
make: ***[main.o] Error 1
Looks like you might have a bad character ‘â’ in main.c. This might be a copy/paste issue between different encodings. Does your code look identical to the example?
yes, it is very identical. i think it look totally the same. there are no bad character in the code but the error still exist.
oh.. great tutorial
Thank you
@10
I would also like to know the what program you used to draw the circuits diagrams
great tutorial!!!
Mcrosoft Visio
i was wondering if you could change it to be a parallel 74hc595 setup instead of a daisy chain by giving the digital in pins on both registers it’s own pin on the micro controller? also when you daisy chain it do you write as if there are two chips with 8 pins each or do you write as if there is 1 chip with 16 pins? like would it be two sets of 10010011 or would it be 1001001101001001? i seek wisdom in these matters…
great tutorial. thank you very much.
But one thing is not clear to me. If you can help me with your command (_BV(i) & __led_state).
good tutorials its of great help for beginners.
Thanking you for the reading good article for the control the LEDs in a row. How can I make this program in the Visual Basic. The C language is not as popular as Visual Basic. I think VB can do this job better.
Hi,
A nice article about how this shift register works. Now I know how that works!
I have a question about the example you work with.
While reading the NXP datasheet of the 74hc595 I noticed that the maximum current
for the unit is 70mA and 35mA per pin.
That indicates that it can only drive up to 3 leds (20mA) at the same time.
Can you enlighten me why your schema works while not burning anything to a crisp?
Thanks.
Remco
Old question, but not all of the LEDs are on at the same time.
Also, the author is using high value resistors (510 ohm) which reduces the current per-LED.
Also, it’s not uncommon for people to overdrive these 595 chips to no harmful effect. This is not warranted, but if you are willing to risk your chip you can probably get away with it within reason. There are also higher-current shift-registers you can choose from.
Where you say that you use Q7 to chain the shift registers together, that does not appear to be correct, or match your schematic. Isn’t Q7 lighting an LED, and not tied to the SER of the next shift register? Should that say pin 9 QH (NOT) to pin 14 (SER) of the next shift register?
Your code did work. My Proteus also did work and simulated 16 leds. Thanks you. But 32 leds didn’t work on Proteus, because your function ‘output_led_state()’ then I did to change the type ‘unsigned int’ to ‘unsigned long’, I tried again 32 leds, but didn’t work. Help me how to run 32 leds.
Simple and clear explanation with timing diagrams.
Thank You very much…
code for two ic’s didn’t work, replaced the last methode with this one and got it working. (channels = number of 74HC595 connected in series)
SH_CP_low();
ST_CP_low();
for (int i=0;i>=1;
SH_CP_low();
SH_CP_high();
}
ST_CP_high();
Get compile error for that one, that & is not declared and what kind of function is this?
What is type of variable is this _BV()?
I got the same error with Tor, the & is not declared.
in 16 bit LED
use this line if((_BV(i) & __led_state) == _BV(i)) instead of if ((_BV(i) & __led_state) == _BV(i)) in line 59.
this programm is very helpfull for mr. but how can we use this programe on 4 shift resistor. if we increase the count from 16 to 32 then it will not work . can u help me…. plz rply
i want this porogram to languge c for use in codvision.
can u help me.please.
I’m looking at using 10 shift registers to drive a multiplexed grid (32×16). When does proprogation become a problem? I really don’t want these 512 rgb leds to flicker. Thx! Nice presentation!
HOW TO MAKE TEXT RUNING 7 LINES 100 COLUMN WITH IC 74C595 / AT 89s 52 thanks ..
WHY ARE YOU YELLING? Aside from that, how are you going to power them?
Can you explain how the hell the daisy-chaining works? What exactly goes to the out7′ port?
Thank you very much for this great tutorial. I had some problems controlling my led matrix because output ports of the 74hc595 were acting weird. I reviewed my complete setup with your tutorial and found that I mistakenly confused ST_CP and SH_CP.
There is an art to developing a great tutorial, and you have mastered it. I wish most breadboard circuits were done as well as this. Thanks!
Hello That’s Great. I made same circuit. And my circuit has one problem. I not found it. Help me!. I get 10 led on while it’s normal working. Then i get 10 or more led on while leds are off. What’s reason of this problem.
I think it’s more led on what more current. 10 or more leds current affects my controller. Is it possible
In output_led_state(unsigned int __led_state) just use this:if ( i== _led_state) in line 59 and that’s all
Hello world, I already feel this is becoming retro in the sense that my TIA chip is not retro anymore (thats pure historic) but learning Arduino to make chipsounds 2015 is already 10 years behind so.. Well Its never too late. Or? I´ve experienced a few broken links already. Maybe Im the last man on earth trying and the first one to realize Im retro retro!
[…] to write and modify the code in C. The only guide that I’ve found to use C code is here: https://protostack.com.au/2010/05/introduction-to-74hc595-shift-register-controlling-16-leds/, but I don’t really understand whats going on when it gets to the for loop and if statement […]
[…] you don’t know how shift registers work, I recommend checking out this article. In the setup() function I used shiftOut() to check the channel jumpers, but to save […]
La explicación directa que facilitan ustedes en su pagina permite comprender el funcionamiento del 74HC595 cuando se desea hacer el control del encendido y apagado de 8 leds en una fila. ¿Cómo puedo hacer para que funcionen una secuencia de 50 leds RGB?. Desde Lima-Peru, agradezco anticipadamente por su deferente consideración a mi petición.
I have seven segment display which is 6digit and 16pin. i already have a pcb which is MG87FE52AE(8051)microcontroller by using IN74HC595AN shift ic i want to convert 16pin to 6pin. So i request you to please tell wiring connection and codes for access. Please reply me