NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Getting started with shift registers

November 14, 2011
by claesz
claesz's Avatar

Just thought I'd share the home made lib I use whenever I use shift registers. I seem to recall I saw some lib for this on the forum some time back, but now I couldn't find it again. If this is a duplicate I apologize...

This is not really of interest to anyone who has been using NK for some time and worked with shift registers before. But I thought I should share it as it might be useful for someone trying out shift registers for the first time.

Basically it gives you 3 easy functions to control the shift registers:

shiftOutBit(pin, value) - f ex shiftOutBit(7, 1); shiftOutByte(value) - f ex shiftOutByte(0b00110011); shiftLatch() to update the shift reg after changes

so to turn on every second pin you would shiftOutByte(0b10101010); shiftLatch(); and then to turn on pin 4 you would do (pin 4 would be 3 in the array (0-7 = 8)) shiftOutBit(3,1); shiftLatch();

or you could update many values in one go shiftPin[1] = 1; shiftPin[2] = 1; shiftPin[3]; shiftOutBit(1,1); // We need to pass a pin value to update the whole array, so we pass pin 1 again. shiftLatch();

Not very exciting stuff, I know, but perhaps of some use if you want an easy way of integrating shift regs with their NK projects.

#define SHIFT_REGISTER DDRB
#define SHIFT_PORT PORTB
#define DATA (1<<PB3)   //MOSI
#define LATCH (1<<PB2)  //SS   (RCK)
#define CLOCK (1<<PB5)  //SCK  (SCK)

int shiftPin[8] = {0,0,0,0,0,0,0,0};    // used to keep track of Shift Register Pin status 0/1

void shiftInit() {

    SHIFT_REGISTER |= (DATA | LATCH | CLOCK);   //Set outputs pins
    SHIFT_PORT &= ~(DATA | LATCH | CLOCK);      //Set pins low

    //Setup SPI
    SPCR = (1<<SPE) | (1<<MSTR);  //Start SPI as Master
}

void shiftOutBit(pin, value)  {

    shiftPin[pin] = value;

    SHIFT_PORT &= ~LATCH;  // set to low to initiate SPI transfer

    //Shift in data
    int i;
    int newval = 0b00000000;
    for(i = 0; i<9; i++) {
        if (shiftPin[i] == 1) { newval |= (1<<i); } else { newval &= ~(1<<i); }
    }

    SPDR = newval;

    while(!(SPSR & (1<<SPIF)));

}

void shiftOutByte(value) {

    SHIFT_PORT &= ~LATCH; // set to low to initiate SPI transfer
    SPDR = value; // shift in data

    while(!(SPSR & (1<<SPIF))); //Wait for SPI to complete
}

void shiftLatch() {
    SHIFT_PORT |= LATCH;
    SHIFT_PORT &= ~LATCH; // refresh the shift reg so changes take effect
}

Here is an example using the lib:

#include <avr/io.h>
#include "../libnerdkits/io_328p.h"
#include "../libnerdkits/delay.h"
#include "./shiftreg.h"

// Shift register pins:
// 1-8 row of LEDs

int main(void) {

    shiftInit();
    int i;

    while(1) {

        for(i = 0; i<8; i++) {
            shiftOutBit(i,1);
            shiftLatch();
            delay_ms(75);   
        }

        for(i = 0; i<8; i++) {
            shiftOutBit(i,0);
            shiftLatch();
            delay_ms(75);   
        }

        for(i = 7; i>=0; i--) {
            shiftOutBit(i,1);
            shiftLatch();
            delay_ms(75);   
        }

        for(i = 7; i>=0; i--) {
            shiftOutBit(i,0);
            shiftLatch();
            delay_ms(75);   
        }

    }

    return 0;
}
November 14, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi calesz,

Thanks for posting this. It should help folks who are new to using shift registers. It might be helpful if you posted a Library article about your code, that way it easier to find in the future.

Humberto

November 14, 2011
by claesz
claesz's Avatar

Thanks! Didn't quite feel it was advanced enough for the "permanent" library so I updated it quickly to handle chained shift regs. I have just tested this quickly, and it seems to work. With two shift regs you would simply do

shiftOutBit(7,1); shiftOutBit(15,1); shiftLatch();

to set the last pin of both regs.

I'll wait a bit to see if anyone has some comments and if not I'll post it as a library article.

#define SHIFT_REGISTER DDRB
#define SHIFT_PORT PORTB
#define DATA (1<<PB3)   //MOSI
#define LATCH (1<<PB2)  //SS   (RCK)
#define CLOCK (1<<PB5)  //SCK  (SCK)
#define TOTSHIFTREG 2   // the number of shift regs you use (connected in series)

int shiftPin[TOTSHIFTREG*8] = {};   // used to keep track of Shift Register Pin status 0/1

void shiftInit() {
    SHIFT_REGISTER |= (DATA | LATCH | CLOCK);   //Set outputs pins
    SHIFT_PORT &= ~(DATA | LATCH | CLOCK);      //Set pins low

    //Setup SPI
    SPCR = (1<<SPE) | (1<<MSTR);  //Start SPI as Master
}

void shiftOutBit(pin, value) {
    shiftPin[pin] = value;
    SHIFT_PORT &= ~LATCH;  // set to low to initiate SPI transfer

    //Shift in data
    int i; // counter for what pin
    int ii; // shift reg counter
    int iii = 0; // counter for where in array
    int newval;
    for (ii = 0; ii<TOTSHIFTREG; ii++) {
        newval = 0b00000000;
        for(i = 0; i<8; i++) {
            if (shiftPin[iii] == 1) { newval |= (1<<i); } else { newval &= ~(1<<i); }
            iii++;
        }   
        SPDR = newval;
        while(!(SPSR & (1<<SPIF)));
    }   
}

void shiftOutByte(value) {
    // Used for shifting the value of a whole shift reg.  For more than one
    // shiftreg you need to shift out for each separately
    SHIFT_PORT &= ~LATCH; // set to low to initiate SPI transfer
    SPDR = value; // shift in data

    while(!(SPSR & (1<<SPIF))); //Wait for SPI to complete
}

void shiftLatch() {
    SHIFT_PORT |= LATCH;
    SHIFT_PORT &= ~LATCH; // refresh the shift reg so changes take effect
}

And here a sample code:

#include <avr/io.h>
#include "../libnerdkits/io_328p.h"
#include "../libnerdkits/delay.h"
#include "./shiftregmulti.h"

// Shift register pins:
// 1-8 row of LEDs on two chained shift regs

    int main(void) {

        shiftInit();
        int i;

        while(1) {

            // Some examples and explanations:
            //shiftOutByte(0b11000000); // you can set an initial value for reg 2
            //shiftOutByte(0b00000011); // you can set an initial value for reg 1
            //shiftLatch();
            //delay_ms(5000);

            //shiftOutBit(12,1); // pins are counted from 0 on the last shiftreg to (numberofshiftreg x 8) on the first shiftreg... 
            //shiftOutBit(6,1);  // ...so with 2 shiftreg, 0 is pin 1 on the 2nd shiftreg and 15 is the last pin on the 1st reg
            //shiftLatch();
            //delay_ms(5000);

            for(i = 0; i<=15; i++) {
                shiftOutBit(i,1);
                shiftLatch();
                delay_ms(75);   
            }

            for(i = 0; i<=15; i++) {
                shiftOutBit(i,0);
                shiftLatch();
                delay_ms(75);   
            }

            for(i = 15; i>=0; i--) {
                shiftOutBit(i,1);
                shiftLatch();
                delay_ms(75);   
            }

            for(i = 15; i>=0; i--) {
                shiftOutBit(i,0);
                shiftLatch();
                delay_ms(75);   
            }

        }

        return 0;
    }
November 14, 2011
by Ralphxyz
Ralphxyz's Avatar

The nice thing about the Nerdkit Community Library is that it is "like" a wiki. It is the communities responsibility to make sure postings are first quality. If I see something posted that I think should be enhanced then I have the responsibility to enhance it or at the least to make mention of the library article here in the forum. There isn't a specific library discussion forum.

Or for that matter even direct attribute, if you post an article then your user name is attributed until I go in and make a spelling correction, then I would be attributed and your atribute would be lost. That is why it truly is a community library like a wiki.

So please if you have working code or a working project or even just information you believe to be accurate please post it to the library.

I like your shift register code, between that and Rick's shift register postings I've gotten a good handle on shift register operations.

It would be good to have them consolidated or posted in parallel in the library so they both would be at hand.

Possible you are making certain assumptions about people's understanding of coding syntax so you might want to consider what level of programing skills you assume the average reader has but post what you have "that works".

Ralph

November 15, 2011
by claesz
claesz's Avatar

I'll have a look at Rick's code and either post it together with my lib, or if he doesn't mind, borrow a bit of the code and make a single lib.

I know I am neither very good at commenting my code nor laying it out in a logical way. My preparation for each project before I start typing code usually consist of two cups of espresso. It may not be as professional as starting with a pen and paper draft, but it does have the advantage of waking me up.

Post a Reply

Please log in to post a reply.

Did you know that you can connect digital calipers to a microcontroller? Learn more...