Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Quick & Simple Shift-register Example


  • Please log in to reply
22 replies to this topic

#1 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 28 December 2010 - 01:42 AM

I was going to make a video for this, but it isn't really needed. This is just a simple shift register example use. I made a fun little class that will help all of you that like things that make sense visually.

I bought my shift register here: http://www.sparkfun.com/products/733 bu there are many different places to shop, so buy it from your favorite place.

Code:
public class ShiftRegister
    {
        private SPI _dataPort;
        private byte[] bitsStorage;
        public ShiftRegister(Cpu.Pin latch = Pins.GPIO_PIN_D10)
        {
            SPI.Configuration spiConfig = new SPI.Configuration(
                latch,
                false, // active state
                0,     // setup time
                0,     // hold time
                false, // clock idle state
                true,  // clock edge
                1000,   // clock rate
                SPI.SPI_module.SPI1);

            _dataPort = new SPI(spiConfig);
        }

        public void WriteByteArray(byte[] byteArray)
        {
            _dataPort.Write(byteArray);
        }

        public void StoreBits(string eightBits)
        {
            if (bitsStorage == null)
                bitsStorage = new byte[1]; // Start the storage
            else
            {
                byte[] temp = bitsStorage; // save it temporarily
                bitsStorage = new byte[bitsStorage.Length + 1]; // make room for another eight bits

                for (int i = 0; i < temp.Length; i++)
                    bitsStorage[i] = temp[i];
            }

            while (eightBits.Length < 8)
                eightBits = "0" + eightBits;

            byte data = 0x00;
            char[] chars = eightBits.Substring(0, 8).ToCharArray();

            for (int i = 0; i < 8; i++)
                data += (byte)((chars[System.Math.Abs(i - 7)] == '1') ? System.Math.Pow(2, i) : 0);

            bitsStorage[bitsStorage.Length-1] = data;
        }

        public void SendBits(bool eraseAfterSend = true)
        {
            WriteByteArray(bitsStorage); // send sotred bits

            if (eraseAfterSend)
                bitsStorage = null; // erase all the stored bits if told to.
        }
    }

The new and improved bit writting system is now designed to work with multiple shift registers. Although it is nice for me because I like binary and stuff... its not the way to go if you're looking for speed. Its best to use the WriteByteArray(byte[] byteArray) method instead.

If you don't have the time or brain power (like me ;) ) to memorize/learn bits to bytes to hex char and all that mess then use this: http://home2.paulsch...et/tools/xlate/

All off and on example:
            ShiftRegister shifty = new ShiftRegister();

            byte[] allOn = new byte[]{0xff, 0xff}; // two bytes because we got two shift registers
            byte[] allOff = new byte[]{0x00, 0x00};

            while (true)
            {
                shifty.WriteByteArray(allOn);
                Thread.Sleep(1000);
                shifty.WriteByteArray(allOff);
                Thread.Sleep(1000);
            }


Single Shift register:
Attached File  Shiftregister.png   177.05KB   443 downloads

Double shift register all the way across the breadboard (I hope you got that reference):
Attached File  doubleshiftregister.PNG   175.4KB   371 downloads
Note that there are no LEDs or other outputs on that schematic, I just wanted to keep things as neat as possible.

To make it a little more clear (hopefully):


Netduino | SR 1 | SR2
---------------------
GND | 13 | 13
GND | 8 | 8
3V3 | 16 | 16
3V3 | 10 | 10
10 | 12 | 12
13 | 11 | 11
14 | 14 | X
X | 9 | 14


Datasheet for the shift register I am using: http://www.sparkfun....C/SN74HC595.pdf

#2 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 28 December 2010 - 01:52 AM

Thanks, Omar, I was just getting ready to try out my shift registers.

#3 bill.french

bill.french

    Advanced Member

  • Members
  • PipPipPip
  • 260 posts
  • LocationPrinceton, NJ

Posted 28 December 2010 - 01:56 AM

Also: I think your diagram needs a ground connection on pin 8.

#4 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 28 December 2010 - 02:01 AM

Also: I think your diagram needs a ground connection on pin 8.


Aha! How silly of me, nice catch ;) I'll fix that in a sec...
fixed
thanks again

#5 Charles

Charles

    Advanced Member

  • Members
  • PipPipPip
  • 192 posts

Posted 29 December 2010 - 02:01 AM

Did you notice that number 2 up there in the code? Thats my old sad binary joke :) . You can replace it with a 0, but the method I made will treat everything as 0 if it isn't 1.


In other words, everybody is somebody unless they are nobody. B)

#6 Charles

Charles

    Advanced Member

  • Members
  • PipPipPip
  • 192 posts

Posted 29 December 2010 - 02:03 AM

I really appreciate this code! I have a couple shift registers on the shelf I keep wanting to play with, but just haven't gotten to it. Now the big question... How do I alter this to support multiple units using SPI addressing?

#7 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 29 December 2010 - 02:41 AM

I really appreciate this code! I have a couple shift registers on the shelf I keep wanting to play with, but just haven't gotten to it.

Now the big question... How do I alter this to support multiple units using SPI addressing?


Good question.... I have two of those and I'll go ahead and try to figure that out, I'll post it here when I get it.

EDIT:
There you go, let me know if that works well for you too. And if you are using more than two shift registers repeat the pattern... pin 14 gets data from pin 9 except on the first one, it gets data from the netduino. The rest is the same though, they all share the clock pin and latch pin

#8 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 29 December 2010 - 05:00 AM

In other words, everybody is somebody unless they are nobody. B)

wait shouldn't it be "everybody is nobody unless they are somebody" ? because everything is 0 (nobody) unless its a 1 (somebody) ... ? sorry to question your analogy ;)

#9 Charles

Charles

    Advanced Member

  • Members
  • PipPipPip
  • 192 posts

Posted 29 December 2010 - 04:35 PM

Grrr.... I thought about that for a few minutes and knew I would get it wrong... What can I say... Spoken languages aren't my string suit.... Err... Strong suit. :D

#10 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 29 December 2010 - 05:23 PM

Grrr....

I thought about that for a few minutes and knew I would get it wrong...

What can I say... Spoken languages aren't my string suit.... Err... Strong suit. :D

Ah there you go, nice programming joke. so did that double shift register thing work for you?

#11 liudr

liudr

    New Member

  • Members
  • Pip
  • 8 posts

Posted 30 December 2010 - 03:25 AM

Omar, Great tutorial! How did you make the nice diagram? Did you use some program?

#12 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 30 December 2010 - 03:30 AM

Omar,

Great tutorial! How did you make the nice diagram? Did you use some program?

Thanks
I used:
Fritzing - http://fritzing.org/ . I imagine its not the best one out there, but it works and its free.
Also go here: http://forums.netdui...p?showtopic=188 to get the netduinos for the program. Those were made by CW2, he did a wonderful job!

#13 NoWheels

NoWheels

    New Member

  • Members
  • Pip
  • 1 posts
  • LocationVirginia

Posted 04 May 2011 - 09:32 PM

it looks like you missed defining bitsStorage. did i miss something?

#14 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 05 May 2011 - 02:03 PM

it looks like you missed defining bitsStorage. did i miss something?

ah good catch! its fixed now. thanks

#15 Charles

Charles

    Advanced Member

  • Members
  • PipPipPip
  • 192 posts

Posted 02 March 2012 - 06:00 AM

I looked over this example and now that I'm starting to really get into shift registers, it seems overly complex. All the math calls seem inefficient. I just threw this together and haven't tested it, but is there any reason something like this wouldn't work for outputting to shift registers?

/*
 * This assumes that there is a bool array (pinState) present with 24 elements.
 * Each one represents a pin state in an easy-to-access format.
 *
 */

// Create and initialize byte storage.
byte[] bitStorage = new byte[3]; // For controlling 3 shift registers.

// Byte value temporary holder.
int eightBitsAsInt;

// Populate the byte storage.
for (int position = 0; position < 3; position++)
{
    // Empty the byte value holder.
    eightBitsAsInt = 0;

    // Build the byte's new value.
    if (pinState[position * 8]) eightBitsAsInt += 1;
    if (pinState[(position * 8) + 1]) eightBitsAsInt += 2;
    if (pinState[(position * 8) + 2]) eightBitsAsInt += 4;
    if (pinState[(position * 8) + 3]) eightBitsAsInt += 8;
    if (pinState[(position * 8) + 4]) eightBitsAsInt += 16;
    if (pinState[(position * 8) + 5]) eightBitsAsInt += 32;
    if (pinState[(position * 8) + 6]) eightBitsAsInt += 64;
    if (pinState[(position * 8) + 7]) eightBitsAsInt += 128;

    // Store it in the byte.
    bitStorage[position] = (byte)eightBitsAsInt;
}

// Write the bytes out to the shift registers.
_dataPort.Write(bitStorage);


#16 Charles

Charles

    Advanced Member

  • Members
  • PipPipPip
  • 192 posts

Posted 06 March 2012 - 04:53 AM

Any comments here?

#17 Daniel Minnaar

Daniel Minnaar

    Advanced Member

  • Members
  • PipPipPip
  • 46 posts
  • LocationJohannesburg, South Africa

Posted 06 March 2012 - 07:53 AM

Can someone please explain to me what bitshift registers are used for, in an easy-to-understand way? I've read the article on Wikipedia but I don't really understand it yet. As far as I can tell, you use it to get more IO's or something?

#18 Nevyn

Nevyn

    Advanced Member

  • Members
  • PipPipPip
  • 1072 posts
  • LocationNorth Yorkshire, UK

Posted 06 March 2012 - 12:35 PM

Can someone please explain to me what bitshift registers are used for, in an easy-to-understand way? I've read the article on Wikipedia but I don't really understand it yet.

As far as I can tell, you use it to get more IO's or something?

They allow you to convert serial output (from the MCU) to parallel output (say the 74595 chip) or parallel to serial (say the 74165).

So the brief answer is IO expansion. You only use three pins on the microcontroller and expand this to the number of inputs / outputs you need (given the limitations on the chip).

Take a single 74HC595. To talk to this you need a clock, the data line and the chip select. If you send 8 bits of serial data to the chip you will get 8 data bits output. You can also cascade these together. So by connecting two 74595's together you can output 16 bits whilst still using only the same three lines.

If memory serves, the 74165 does the reverse, converting 8 inputs per chip into data which can be read serially.

Hope this helps,
Mark

To be or not to be = 0xFF

 

Blogging about Netduino, .NET, STM8S and STM32 and generally waffling on about life

Follow @nevynuk on Twitter


#19 meterMan

meterMan

    Member

  • Members
  • PipPip
  • 25 posts

Posted 06 March 2012 - 10:01 PM

What do I need to add to this to work with more than 1 shift register?

This code is for turning on a single led, led 3. Bit boring but shows how things work. You are basically passing a number between 1 and 8 and a true or false to toggle the corresponding LED on each of the 8 outputs (Q0 to Q7).

public class Program            /// Define any variables used in the program and subroutines after Main()///
    {
        //shift register pins
        static OutputPort data = new OutputPort(Pins.GPIO_PIN_D2, false);
        static OutputPort clock = new OutputPort(Pins.GPIO_PIN_D3, false);  
        static OutputPort latch = new OutputPort(Pins.GPIO_PIN_D4, false);
        
        //bitwise maths for changing individual LEDs
        static int[] bits = { 1, 2, 4, 8, 16, 32, 64, 128 };
        static int[] masks = { 254, 253, 251, 247, 239, 223, 191, 127 }; 
        static int ledState = 0;

        public static void Main()   
        {
            while (true)            
            {
                changeLED(3, true);  //turns on led 3
            }
        }
        /// changeLED(int led, int state) - changes an individual LED 
        /// the LED we are addressing whether that LED is to be on or off
        public static void changeLED(int led, bool state)
        {
            ledState = ledState & masks[led];  //clears ledState of the bit we are addressing
            if (state)      //if the bit is on we will add it ledState 
            {
                ledState = ledState | bits[led]; 
            } 
            updateLEDs(ledState);              //send the new LED state to the shift register
        }
        // sends the LED states set in value to the 74HC595 sequence
        /// the 8 bit number to be displayed in binary on the LEDs                  
        static void updateLEDs(int value)
        {
            latch.Write(false);          //Pulls the chips latch low

            for (int i = 0; i < 8; i++)  //Will repeat 8 times (once for each bit)
            {
                int bit = value & 0x80;  //We use a "bitmask" to select only the eighth bit in our number (the one we are addressing this time through
                value = value << 1;      //we move our number up one bit value so next time bit 7 will be bit 8 and we will do our math on it
                if (bit == 128)
                {
                    data.Write(true);    //if bit 8 is set then set our data pin high
                }
                else
                {
                    data.Write(false);   //if bit 8 is unset then set the data pin low
                }

                clock.Write(true);      //the next three lines pulse the clock pin      
                Thread.Sleep(1);
                clock.Write(false);
            }
            latch.Write(true);          //pulls the latch high shifting our data into being displayed
        }

    }



#20 littlebone

littlebone

    New Member

  • Members
  • Pip
  • 2 posts

Posted 07 December 2012 - 05:52 PM

I'm a little late to the party here; but Omar, thanks for the example. I read quite a few SPI overviews before finding this and couldn't find any that explained where the SPI1 module's Netduino pins needed to connect to the 74HC595 pins. This example was just what I needed. I just wanted to add this change for the Netduino 2 Plus. By trial and error I found that the clock rate should be set to 4000. I guess that makes sense, because the 2 plus has a clock 4X the rate of the original Netduino. When I used the original rate, only some of the LEDs lit. If I lowered the rate, even fewer lit. If my assumption about the reason for the clock rate=4000 is wrong, I would appreciate a correction. I don't want to mislead anyone. Joe




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.