Showing posts with label shift register. Show all posts
Showing posts with label shift register. Show all posts

Thursday, July 12, 2012

How a shift register works

This was a quick-and-dirty project just to understand how our shift registers from Farnell work. The block diagram on the datasheet makes things pretty simple, but we still need to make sure we're toggling the right lines to "flush" the data into the device:


From this block diagram, we can see that any data clocked into the shift register is held in a buffer, and only transferred onto the output pins when the RCK line is toggled (in this case, according to the "truth table" from low to high)


So we built a quick usb device (for getting data quickly from our PC to the end device) using a PIC 18F255 microcontroller and used it to clock data in/out of the shift register. The PIC was connected to our SMT LED breakout board as follows:

PORTB.5 -> serial clock in (SCLK)
PORTB.4 -> register clock (RCLK)
PORTB.3 -> serial data in (SI)



The layout/PDF for the breakout board is here:
SOIC-to-DIP breakout With Leds (for shift register)


(don't forget that this is for SMT components, not through-hole, so the final etched board will be mirrored. That's why PIN1 is marked on the top right, not top left, and Vcc- pin16 - is top left. You'll need to use your imagination to "flip" this and get the pins in the right place!)

A shift register is quite easy to work with, but until you actually get your hands on one and make it work, it can be difficult to fully appreciate what's needed. A shift register can be used in a variety of ways, you can tie the clock lines together (to save pins) but that only adds to the complexity. You can daisy-chain the registers, by enabling the output line and have one SR feed the next in a chain and so on.

We're going to concentrate on simply getting serial data into the device, and displaying it on a sequence of LEDs. This project will form the basis for future projects by reducing the pin-count needed to individually control lots of separate LEDs. Having learned from the word clock in November, we're sticking to surface mount LEDs this time - no way are we going to be spending hours and hours drilling hundreds of holes again!

(this board was made up with solder paste and a cheap nasty "fire-starter" soldering iron from Farnell. Hence the scorched traces and missing pin header where the connect-to-ground jumper burned away and had to be fixed with a bit of spare wire!)

With the shift register hooked up to the PIC microcontroller, we dropped some simple code onto the PIC and wrote a quick VB app to send data to the PIC. The PIC simply takes a single byte value and sends it to the shift register in the following sequence:


Here's the Oshonsoft Basic code for our PIC:
Define CLOCK_FREQUENCY = 20
Define CONFIG1L = 0x24
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x38
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x03
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

UsbSetVendorId 0x1234
UsbSetProductId 0x1234
UsbSetVersionNumber 0x1122
UsbSetManufacturerString "Nerd Club"
UsbSetProductString "Generic USB HID Device"
UsbSetSerialNumberString "1111111111"
UsbOnIoInGosub input_report_before_sending
UsbOnIoOutGosub output_report_received
UsbOnFtInGosub feature_report_before_sending
UsbOnFtOutGosub feature_report_received

AllDigital
Dim i As Byte
Dim pattern As Byte

Symbol rclk = PORTB.4
Symbol sclk = PORTB.5
Symbol si = PORTB.3

UsbStart
i = 0
pattern = 255

loop:
     UsbService

     If i = 0 Then
          Gosub senddata
          i = 1
     Endif
Goto loop

End



senddata:
     'prepare the shift register "flush" pin
     Low rclk

     'send data to the shift register
     If pattern.0 = 1 Then High si Else Low si
     Gosub toggleserialclock

     If pattern.1 = 1 Then High si Else Low si
     Gosub toggleserialclock

     If pattern.2 = 1 Then High si Else Low si
     Gosub toggleserialclock

     If pattern.3 = 1 Then High si Else Low si
     Gosub toggleserialclock

     If pattern.4 = 1 Then High si Else Low si
     Gosub toggleserialclock

     If pattern.5 = 1 Then High si Else Low si
     Gosub toggleserialclock

     If pattern.6 = 1 Then High si Else Low si
     Gosub toggleserialclock

     If pattern.7 = 1 Then High si Else Low si
     Gosub toggleserialclock
          
     'flush the shift data onto the output pins
     High rclk

Return



toggleserialclock:
     Low sclk
     WaitUs 50
     High sclk
Return



feature_report_received:
Return



feature_report_before_sending:
Return



output_report_received:
     pattern = UsbIoBuffer(0)
     Gosub senddata
Return



input_report_before_sending:
Return

The idea is that we'll send a byte value to our PIC controller board (via usb) which it will then clock into the shift register. It's important to note that we've only used six of the possible eight output pins on the shift register. So the first and last bits (mapped to pins 7 and 15 on the shift register) aren't actually connected to an LED. Any data value sent will be displayed as X 1 1 1 1 1 1 X

To see this in action, we can send the byte value 47 to the PIC.
In binary, this is represented by 0 0 1 0 1 1 1 1
Since our board is ignoring the first and last bits (why didn't we just connect them up to make explaining this a bit easier?!) this gives the LED lighting sequence X 0 1 0 1 1 1 X

Instead of just typing random numbers, converting to binary and comparing the results, we built a simple VB app to generate a byte value and send it to the PIC microcontroller:



Although focus isn't brilliant you should be able to see that by clicking the onscreen LEDs, the VB app is generating a byte value (from a binary representation of the LED states). This value is sent to the PIC, which turns the byte value back into a series of bits, which are then transmitted to the shift register, one bit at a time.

We set the value of the serial input line to match the value of the first "bit" in our byte value (either on/high or off/low) then toggle the serial clock line. This pushes the first bit into the shift register. When then set the serial line to match the second bit (either on/high or off/low) and toggle the serial clock line again. This pushes the first bit along Ishifts it) and pushes the second bit into the register.
After doing this eight times, our shift register contains the byte value we sent over a single serial data line. To get the value to display by lighting our LEDs, we need a low-to-high transistion on the RCLK pin. Until this pin goes high, the data sent to the shift register sits in the "top part" and doesn't actually affect the output pins. When the RCLK pin goes high, the value in the shift part of the register is "flushed" into the latching register which controls the output pins QA-QH (and the sequence of LEDs changes)


Btw - it turns out that we did indeed mount the shift registers the correct way around on our little breakout board, despite not finding a pin1 marker on the casing. If anyone else is using these 74HC595 SOIC shift registers, they should be mounted, rotated 90 degrees to the right and pin1 is the top-left-most pin as per the datasheet!


Wednesday, July 11, 2012

SOIC/SOP to DIP breakout board

We recently bought some shift registers from Farnell but being SMT they're not easy to use on a breadboard /prototyping system so we knocked up a simple breakout board for them. These boards should suffice for any SOIC device, to make it suitable for plugging into a breadboard.

Interestingly, the parts are listed as SOP-sized but in ExpressPCB there were no component layouts for SOP. We chose SOIC instead and the layout was a perfect match. So is SOP and SOIC the same layout? The jury's still out on that one.

In the meantime, here's our breakout board layout.
Don't forget to download and print from Adobe Acrobat Reader, not directly from Google Chrome!


Soic Breakout 16 Pin

Wednesday, December 14, 2011

Serial-to-parallel LCD display driver

Amazingly we managed to get a working serial character LCD in under an hour today!
Just followed the schematics at http://embedded-lab.com/blog/?p=30 and converted the code example they gave into Oshonsoft Basic. Fired it up and there we go - a blinking "Hello World!" message using just three pins on the microcontroller.



The only real issue we had was that the contrast isn't brilliant; instead of a 10K linear pot, we've gone and used the first potentiometer that was to hand (a 1M logarithmic pot!)


If, like us here at Nerd Towers,  you're an Oshonsoft fan, here's the code listing to get everything working:

AllDigital
Config PORTC = Output

configuration:
       Symbol enablepin = PORTC.0
       Symbol clockpin = PORTC.1
       Symbol datapin = PORTC.2
     
declarations:
       Dim i As Byte
       Dim lcdi As Byte
       Dim lcdbyte As Byte
       Dim lcdbytetosend As Byte
       Dim rs As Bit
       Dim flag As Byte
       Dim mask As Byte
     
init:
       Gosub initialiselcd
     
loop:
       lcdbytetosend = 32
       Gosub writelcddata
       lcdbytetosend = "H"
       Gosub writelcddata
       lcdbytetosend = "e"
       Gosub writelcddata
       lcdbytetosend = "l"
       Gosub writelcddata
       lcdbytetosend = "l"
       Gosub writelcddata
       lcdbytetosend = "o"
       Gosub writelcddata
       lcdbytetosend = 32
       Gosub writelcddata
       lcdbytetosend = "W"
       Gosub writelcddata
       lcdbytetosend = "o"
       Gosub writelcddata
       lcdbytetosend = "r"
       Gosub writelcddata
       lcdbytetosend = "l"
       Gosub writelcddata
       lcdbytetosend = "d"
       Gosub writelcddata
       lcdbytetosend = "!"
       Gosub writelcddata
     
       WaitMs 4000
       lcdbytetosend = 0x01 'clear screen
       Gosub writelcdcommand
     
       WaitMs 2000

Goto loop
End


writelcdnibble:
       Low enablepin
       Low clockpin
       If rs = 1 Then High datapin Else Low datapin

       Gosub toggleclockpin
     
       'shift in 4 bits
       mask = 8
       For lcdi = 1 To 4
              flag = lcdbyte And mask
              If flag = 0 Then Low datapin Else High datapin
              Gosub toggleclockpin
              mask = ShiftRight(mask, 1)
       Next lcdi
            
       'now strobe the clock one more time because ST+SC are tied
       Gosub toggleclockpin

       'toggle the enable pin to "flush" the data into the lcd
       Low datapin
       High enablepin
       Low enablepin
     
Return



toggleclockpin:
       'toggle the clock pin
       High clockpin
       Low clockpin
Return



writelcddata:
       rs = 1
       Gosub senddata
Return



writelcdcommand:
       rs = 0
       Gosub senddata
Return



senddata:
       lcdbyte = ShiftRight(lcdbytetosend, 4)
       Gosub writelcdnibble
       lcdbyte = lcdbytetosend And 15
       Gosub writelcdnibble
Return



initialiselcd:
       For i = 1 To 3
              WaitMs 50
              lcdbytetosend = 0x20
              Gosub writelcdcommand
       Next i
     
       WaitMs 50
       lcdbytetosend = 0x28 '4 bits, 2 lines, 5x7 font
       Gosub writelcdcommand
     
       WaitMs 50
       lcdbytetosend = 0x0c 'display on, no cursors
       Gosub writelcdcommand
     
       WaitMs 50
       lcdbytetosend = 0x06 'entry mode auto-increment
       Gosub writelcdcommand
     
       WaitMs 50
       lcdbytetosend = 0x01 'clear screen
       Gosub writelcdcommand
     
Return

Serial-to-parallel character LCD communication

We're getting close to hooking up all the component parts and testing our Blood Bowl game board. The master chip uses UART/serial to talk to the slave, so we've no easy means of talking to the master chip (in a lot of our 18F-based development we usually hook the chip up to a PC using USB to read data directly from the registers - even if USB won't be used in the final design - but this won't be possible in this case, since we can't run UART and USB together)

Since our game board will include two LCD character displays, we figured we could hook those up and use them to write out debug information during testing. In an attempt to keep as many pins free on our master chip, we're looking at converting an HD44780 parallel display into a serial LCD as in this article:
http://embedded-lab.com/blog/?p=30


So before we go plugging everything together and spending hours wondering why things aren't quite working properly, we're going to make a separate project which concentrates on just displaying the information we want on a 3-wire serial LCD (in our final project we'll be using two 20x4 character displays, one green, one blue. But they're on Santa's Xmas Wishlist and not likely to arrive before the big day, so we'll try things out with an old 2x16 that's lying around in the toolbox).