PDA

View Full Version : Help with 74HC595 8-bit shift register with latch.



mynet43
01-08-2009, 10:35 AM
I'm trying to help someone on the forum drive this chip from a prop.

The problem is that they have the chip and I don't have one to test with.

They're a relative newby to the prop so I wrote the following driver.

They're using it to drive a set of 8 LED's.

Apparently it almost works. It latches the values for about a second and then
drops the lights and bit 0 flickers, as best as I can understand the description from long distance.

Here's the driver code I wrote. Would someone please take a look at it and let me know if you
spot something? If you have a chip to debug it (or a working driver), that would be even better:)

Thanks for your help.

Jim




'' ************************************************** ****************************
'' * "HC595.spin" 74HC595 SPIN Object *
'' * coded by Jim -- 12/31/08 -- Happy New Year! *
'' * Version 1.0 *
'' ************************************************** ****************************
''
'' Calling sequence
'' OBJ
'' SReg : "HC595"
''
'' code segment
'' SReg.InitSer595 ' to initialize driver
'' more code
'' DataByte := toSend ' set up data to send to chip
'' SReg.WriteSer595(DataByte) ' send data to chip
'' more code
''

CON
_PinHigh = 1
_PinLow = 0

CLK = 0 ' pin number of CLK pin on chip (AKA SCK)
SER = 1 ' pin number of SER pin on chip
CLR = 2 ' pin number of SCLR pin on chip
RCK = 3 ' pin number of RCK pin on chip
GPN = 4 ' pin number of G pin on chip

VAR
long bitout, databyte

PUB InitSer595 ' initialize 74HC595 for startup

' set the control lines as outputs
dira[CLK] ~~
dira[SER] ~~
dira[CLR] ~~
dira[RCK] ~~
dira[GPN] ~~

outa[CLK] := _PinLow ' init main clock line to low
outa[RCK] := _PinLow ' init latch clock line to low


outa[GPN] := _PinHigh ' set outputs to 3-state
outa[CLR] := _PinLow ' set to clear register on chip
outa[GPN] := _PinLow ' turn on the chip and clear pins
outa[CLR] := _PinHigh ' return CLR pin to high after clear


PUB WriteSer595(Data) ' Data is long with 8 bits of data in bits 7 - 0
' Write 8 bits of data. Data byte is output MSB first.

databyte := Data ' transfer to working storage

repeat 8 ' shift out 8 bits
bitout := databyte & %1000_0000 ' take hi bit from byte -> bitout bit 7
bitout >>= 7 ' shift to bit zero for output

databyte <<= 1 ' shift data left 1 bit for next loop

outa[SER] := bitout ' shift out high bit to serial pin (0 or 1)

outa[CLK] := _PinHigh ' toggle the clock pin to shift bit out

outa[CLK] := _PinLow ' high then low to cycle the clock

outa[RCK] := _PinHigh ' toggle the RCK pin to latch the output

outa[RCK] := _PinLow ' high then low to cycle the clock

Peter Jakacki
01-08-2009, 11:11 AM
You can use bitwise reverse on the low order 8-bits to simplify the code.
No need to have a databyte variable, just work straight off the input parameter
No need to have a bitout variable either, just use the data parameter (lsb)

The problem sounds more like a hardware problem, a poor supply, no decoupling, glitch on the clock or something like that.

*Peter*

Peter Jakacki
01-08-2009, 11:18 AM
Here's a quick suggestion to improving the code although your version looks functional.

*Peter*



'' ************************************************** ****************************
'' * "HC595.spin" 74HC595 SPIN Object *
'' * coded by Jim -- 12/31/08 -- Happy New Year! *
'' * Version 1.0 *
'' ************************************************** ****************************
''
'' Calling sequence
'' OBJ
'' SReg : "HC595"
''
'' code segment
'' SReg.InitSer595 ' to initialize driver
'' more code
'' DataByte := toSend ' set up data to send to chip
'' SReg.WriteSer595(DataByte) ' send data to chip
'' more code
''

CON
_PinHigh = 1
_PinLow = 0

CLK = 0 ' pin number of CLK pin on chip (AKA SCK)
SER = 1 ' pin number of SER pin on chip
CLR = 2 ' pin number of SCLR pin on chip
RCK = 3 ' pin number of RCK pin on chip
GPN = 4 ' pin number of G pin on chip

PUB InitSer595 ' initialize 74HC595 for startup
' set output register before pin becomes an output (avoids glitches)
outa[GPN] := _PinHigh ' set outputs to 3-state
outa[CLR] := _PinLow ' set to clear register on chip
outa[RCK] := _PinLow ' init latch clock line to low
outa[CLK] := _PinLow ' init main clock line to low

' set the control lines as outputs
dira[CLK] ~~
dira[SER] ~~
dira[CLR] ~~
dira[RCK] ~~
dira[GPN] ~~

outa[GPN]~ ' turn on the chip and clear pins
outa[CLR]~~ ' return CLR pin to high after clear


PUB WriteSer595(Data) ' Data is long with 8 bits of data in bits 7 - 0
' Write 8 bits of data. Data byte is output MSB first.
Data ><= 8 ' bitwise reverse the lsbs
repeat 8 ' shift out 8 bits
outa[SER] := Data ' shift out next bit (bit0) to serial pin (0 or 1)
outa[CLK] ~~ ' toggle the clock pin to shift bit out
outa[CLK] ~ ' high then low to cycle the clock
Data >>= 1 'next bit
outa[RCK]~~ ' toggle the RCK pin to latch the output
outa[RCK]~ ' high then low to cycle the clock




P.S. just edited the code again to use the shortform bitset operators ~~ and ~

mynet43
01-08-2009, 12:09 PM
Thanks for the suggestions. They look good.

I wrote the thing in about 15 minutes, too lazy to look up a couple of things:)

It looks like you were right the first time, hardware problem...

Either that or we were clocking the signals out too fast for the chip.

It seems to be working now.

Thanks for looking at it.

Jim

mynet43
01-08-2009, 12:23 PM
Does anyone know off-hand what the pulse width is when you cycle a pin in SPIN?




outa[CLK] ~~ ' toggle the clock pin to shift bit out
outa[CLK] ~ ' high then low to cycle the clock




I'm not sure how many clock cycles the outa[ ] instruction takes.

StefanL38
01-08-2009, 03:50 PM
Hello,

take a look into the datasheet the minimum pulsewidth depends on the supply-voltage longest pulsewidth at 2V
a little less than 0.1 microseconds on higher voltages even faster.

I have coded a 595 in assembler with almost no delays and it is working
so coded in SPIN the pulsewidth is far long enough for proper switching

again in the datasheet you can see that the clocks are triggered on the LOW-HIGH-transistion
you code does it the opposite way HIGH-LOW so as a quick guess the flickering of LED 0 is because
bit 0 is shifted/latched if the NEXT cycle begins

So the toogling of the clocks has to vice versa



' toggle the clock pin to shift bit out
outa[CLK] ~ 'set Pin LOW to prepare transition
outa[CLK] ~~ 'pin HIGH: the LOW-HIGH-transition triggers the clock





best regards

Stefan

Peter Jakacki
01-08-2009, 04:11 PM
@mynet43: Spin isn't very fast for this bit-bashing so expect a minimum pulse width of around several microseconds. However the edges are the same as they would be even if the pulse was much faster or slower. If the hardware is roughly made it will pay to add a 100pf capacitor to the clock line to desensitize it (and of course a 0.1uF cap across the chip's power and ground).

@stefanl38: The toggling that mynet does changes the data bit then it takes the clock high (from previous low) and then low again. But since the clock is low-to-high sensitive it doesn't matter whether it is low then high-low or high then low-high.

*Peter*

Leon
01-08-2009, 06:02 PM
It's actually SPI-compatible, so the SPI object should work (I think there is one). I use a 74HC595 on a little PCB with LEDs on the outputs to test SPI interfaces.

Leon

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Amateur radio callsign: G1HSM
Suzuki SV1000S motorcycle

Leon
01-08-2009, 06:04 PM
The 74HC595 is SPI-compatible, so the SPI object should work (I think there is one). I use one on a little PCB with LEDs on the outputs to test SPI interfaces.

Leon

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Amateur radio callsign: G1HSM
Suzuki SV1000S motorcycle

mynet43
01-08-2009, 10:07 PM
Wow!

Thanks everyone for the great responses, they really help.

I'm going to have to go back and read the thread again. There was a question about the direction of my clock transitions.

I first set the data line and then set the clock high. This should cause a low to high transition, which I'm pretty sure is right. Let me know if I missed something.

I'm glad to hear that someone coded it in assembly. That makes me think the code should work.

Remember, I'm doing this long distance, I'm in CA and he's in PA (with the HC595). I'll have him check for caps and to make sure the lines aren't too long.

Thanks again for the great feedback!

Jim

Leon
01-08-2009, 10:17 PM
Everything you need is in the HC595 data sheet, just follow the timing diagrams. I'd buy a couple of chips and wire them up, it'll make things much easier.

Leon

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Amateur radio callsign: G1HSM
Suzuki SV1000S motorcycle

danthony
01-08-2009, 11:37 PM
How do you modify jim or peter;s code to talk to many 74hc's strung in a row? I tried the obvious on the repeats, but it did not work. Any ideas?

StefanL38
01-08-2009, 11:45 PM
hello danthony,

take a look into the datasheet

pin 9 of the 595 is the serial data OUTput called Qh

you simply connect Qh of 595 no 1 with serial data INput of 595 no 2, etc, etc, etc

shiftclock and latch are parallel
you trigger the latch ONLY at the end of shifting ALL 32, 48, or whatever amount of bits

that's all

best regards

Stefan

Post Edited (StefanL38) : 1/8/2009 3:52:01 PM GMT

danthony
01-09-2009, 01:08 AM
Stefan-
This is mynets code and I can get to work with one chip. I do not see the clk~~, clk~ code to modify as in your earlier post.
I tried what you said with the qh to serial in of #2 but nothing. Here is the code I have working for 1 chip.

'' ************************************************** ****************************

PUB WriteSer595(Data) ' Data is long with 8 bits of data in bits 7 - 0
' Write 8 bits of data. Data byte is output MSB first.

databyte := Data ' transfer to working storage
repeat 8 ' shift out 8 bits
bitout := databyte & %1000_0000 ' take hi bit from byte -> bitout bit 7
bitout >>= 7 ' shift to bit zero for output
databyte <<= 1 ' shift data left 1 bit for next loop
outa[SER] := bitout ' shift out high bit to serial pin (0 or 1)
outa[CLK] := _PinHigh ' toggle the clock pin to shift bit out
outa[CLK] := _PinLow ' high then low to cycle the clock
outa[RCK] := _PinHigh ' toggle the RCK pin to latch the output
outa[RCK] := _PinLow ' high then low to cycle the clock




Thanks
Don

danthony
01-09-2009, 01:53 AM
forget it Stefan, I got it.

Thanks,
Don