Pages: [1] 2 3   Go Down
Author Topic: Triple Shift Register question  (Read 1603 times)
0 Members and 1 Guest are viewing this topic.
Illinois, US
Offline Offline
Jr. Member
**
Karma: 2
Posts: 97
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello again everyone!

Quick question-

Is it possible to send info across three shift registers using only one "shiftout"?  It's not is it?

I have LEDs currently connected to each output on the 74HC595s for a total of 24 lights, and I need to light only single lights at a time, on command.  Currently, if I wanted to light only the 5th LED in the middle register I am doing something like this:

Code:
digitalWrite(latch, 0);
  shiftOut(data, clock, MSBFIRST, 0);
  shiftOut(data, clock, MSBFIRST, 16);
  shiftOut(data, clock, MSBFIRST, 0);
  digitalWrite(latch, 1);

and I suppose what I am hoping for is a solution more like this:

Code:
digitalWrite(latch, 0);
  shiftOut(data, clock, MSBFIRST, 0, 16, 0);
  digitalWrite(latch, 1);

Would it maybe work if I used an array?  So possibly...

Code:
byte shiftarray[] = {0, 16, 0};

for (byte i = 0, i < 3, i++) {

  digitalWrite(latch, 0);
  shiftOut(data, clock, MSBFIRST, shiftarray[i]);
  digitalWrite(latch, 1);

}


Quite honestly, I have only just begun to grasp arrays, so maybe I am way off base.  Thanks in advance for any help you are able to provide!

As a side note, a few of you have been helping me tremendously along my journey and I just wanted to let you all know I am making lots of progress with the BarBot!  I now have all of my pumps and check valves- and I already have had it take an order over wifi from the iPad, and pour precise amounts of liquid!  Granted, it was colored water and not actual booze yet...  but it works anyways!  I picked up some transistor arrays too (so cool they make these!  I was planning on having to individually diode/resistor/transistor each one separately... )  And I picked up a big jug of Ferric Chloride to etch my own PCB when the time comes- that sounds fun! (I'm sure it will take a bit of practice though lol)

I gotta hit the sack for now, but I'll check back in the morning!  Thanks Guys!
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think I need a BarBot!

Anyway, the nature of shift registers is that you basically have to update the lot.

http://gammon.com.au/forum/?id=11518

It only takes 3 x SPI.transfer to reload three shift registers, and they execute very quickly, so I wouldn't get too worried.
Logged

East Anglia (UK)
Online Online
Faraday Member
**
Karma: 89
Posts: 3453
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How about making your code into a function like this
Code:
void shiftThree(int reg1, int reg2, int reg3)
{
  digitalWrite(latch, 0);
  shiftOut(data, clock, MSBFIRST, 0);
  shiftOut(data, clock, MSBFIRST, 16);
  shiftOut(data, clock, MSBFIRST, 0);
  digitalWrite(latch, 1);
}
Then you could call it like this
Code:
shift3(0,16,0);
Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
BarBot

BarBot!

Just what you need at the SuperBowl party.
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 436
Posts: 23648
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you have the shift registers daisy chained, then you need to update all three at once.
If you give each one its own latch line, you can address each one individually.

I have daisychained 20 of them with SPI transfers and sent the data out to them from an array. Very fast.
I have also used 4 MAX7219 for a scrolling message board, a 32 column panel of data. Each column there requires 2 SPI tranfers, address first and then data. So 64 SPI transfers to update the whole thing.  I was updating the entire display every 40mS while scrolling, made for good readability.

So 3 daisy chained is very quick, as Nick pointed out.
shiftout is a low slower, since the software has to create every clock pulse. The ATmega has dedicated hardware for SPI.
Make sure you have a 0.1uF cap from shift register Vcc pin to Gnd.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Illinois, US
Offline Offline
Jr. Member
**
Karma: 2
Posts: 97
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the replies!

NickGammon:

I'll post my build of it with code here once I'm done!  That way everyone can have one smiley

SPI transfer is now a new arrow in my quiver, and as Crossroads said, if it is less work for the software I am all over it, since my code is already so bloated with crap for it to do.

After reading the link you provided though, I have two burning questions:

1. That 10k pulldown resistor on the "D10"/"SS"/"Slave Select" pin...  is that pin 11, 12, or 14?  I would LOVE to put that on my circuit- so if the power should go out and come back on, my BarBot won't start arbitrarily pouring booze on the ground!

2. Where do you buy your ribbon cable good sir?  I would very much like to get my hands on some like yours.

UkHelibob:

What you suggested is exactly what I am currently doing actually, and it is very clunky for my purposes.  Let me elaborate.  My current code is as follows:

Code:
void pourcount(const byte shift1, const byte shift2, const byte shift3, byte ozcount)
{
  digitalWrite(latch, 0);
  shiftOut(data, clock,MSBFIRST, shift1);
  shiftOut(data, clock, MSBFIRST, shift2);
  shiftOut(data, clock, MSBFIRST, shift3);
  digitalWrite(latch, 1);
  Serial.print(F("pumped "));
  Serial.print(ozcount);
  Serial.print(F(" qtr oz, about "));
  Serial.print(ozcount / 4);
  Serial.println(F(" full oz."));
}
void pour(const byte shift1, const byte shift2, const byte shift3, byte ozcount, const int oz)
{
  ozcount = ozcount + 1;
  pourcount(shift1, shift2, shift3, ozcount);
  delay(oz);
}

(Notice, I AM learning from the previous suggestions to my threads, albiet slowly.  I have not incorporated arrays yet... I am still learning how they fit into my master plan.  Soon...  Soon...)

Anyways, with the above code my usage of pour looks like:

Code:
    //////////////////////// 1.Vodka on the rocks (lemon twist)  /////////////////////////////////////

    if (packBuff[0]== 'V' && packBuff[1]=='O' && packBuff[2]=='O' && packBuff[3]=='N')
    {

      pour(vodka1st, vodka2nd, vodka3rd, vodka, oh); End();
   
            udpWrite( F("Vodka on the rocks- Serve with a lemon twist.  Enjoy!"));

    }


That will get very tedious and lame when pouring drinks with seven or eight ingredients. (by the way, the "oh": above is my delay time, which stands for "one half ounce")  I would LOVE to find a way to make the code work like this:

Code:
pour(vodkashift, vodka, oh);

// or even BETTER would be to do

pour(vodka, oh);

//where "vodka" in this case is a function that contains both vodkashift and the const int vodka.
//however, I have no idea how to tell a function I am creating, that I am going to give it
//a random function name as an input condition...  If what I have just described doing
// (passing a function another function as an input condition) Please tell me how!

Crossroads:

Giving all three separate latch controls IS an attractive idea...  However then I would need to pass which latch pin into my input conditions of pour() right?  Or could I make pour() do all the work and deduce which latch pin to utilize by using if() then() else() logic?

thanks again guys!
Logged

East Anglia (UK)
Online Online
Faraday Member
**
Karma: 89
Posts: 3453
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Why is a function call more clunky than what you wished for ?
You wanted
Code:
digitalWrite(latch, 0);
  shiftOut(data, clock, MSBFIRST, 0, 16, 0);
  digitalWrite(latch, 1);
That is surely more clunky than the function call that I suggested
Code:
shift3(0,16,0);
As others have said, the time taken for the code to run should not be a cosideration in the case of your application

As to passing a function the name of a function to be executed, why bother ?  Why not just call the function directly ?  Alternatively pass a parameter to the pour() function which indicates the name of the function to be called so that you can easily see what you expect the function to do, which seems to be what you want and have the pour() function use switch/case based on the parameter to determine what should happen.  If you put the drink names in an enum you can use meaningful names for the drinks for switch/case.

Something like this
Code:
enum drinkList {vodka, gandt, drink3};

void setup()
{
  Serial.begin(9600);
  enum drinkList drink;

  pour(vodka);
  pour(drink3);
  pour(gandt);
}

void loop()
{
}

void pour(int drink)
{
  switch (drink)
  {
  case vodka:
    pour_vodka();
    break;

  case gandt:
    pour_gandt();
    break;
  case drink3:
    pour_drink3();
    break;
  }
}

void pour_vodka()
{
  Serial.println("actions to pour vodka go here");
}

void pour_gandt()
{
  Serial.println("actions to pour Gin and Tonic go here");
}

void pour_drink3()
{
  Serial.println("actions to pour drink 3 go here");
}
This being C there is a way to pass a function name directly to a function but I can understand the code as written above because I wrote it !  See http://stackoverflow.com/questions/9410/how-do-you-pass-a-function-as-a-parameter-in-c for passing function names to functions.
Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 436
Posts: 23648
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

US ribbon cable source - http://www.dipmicro.com/store/index.php?searchStr=ribbon&act=viewCat
Selecting which shift register to control - there are too many ways to get there.
You have to find one that you can reliably control.
For example, you might have 3 bytes of data that represent the 24 outputs you control.
Part of your code might set/clear a particular bit.
A later part of your code might compare all three to a previous value, and when one is determined to have changed, it would update the previous value to match, and send it out to the appropriate shift register.
I tend to write code that reflects my hardware design background. Others with software backgrounds might do it differently with functions and what not.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Giving all three separate latch controls IS an attractive idea.

It doesn't solve your problem: you still need to send the data 3 times to update any bit.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
That 10k pulldown resistor on the "D10"/"SS"/"Slave Select" pin...  is that pin 11, 12, or 14?  I would LOVE to put that on my circuit- so if the power should go out and come back on, my BarBot won't start arbitrarily pouring booze on the ground!

As on the diagram on my page: http://www.gammon.com.au/forum/?id=11518

Quote
2. Where do you buy your ribbon cable good sir?  I would very much like to get my hands on some like yours.

Personally I got it from Jaycar, but most electronics places should have it.

Quote
Giving all three separate latch controls IS an attractive idea.

For once I agree with dhenry, that doesn't solve much. Using them in the standard way is fine, you send 3 x 8 bits (3 x SPI.transfer) and then latch. It's simple, don't complicate it.

Keep in memory a "copy" off all 24 bits. Change them individually as required. Then shift out all 24.
Logged

Temple, Texas
Offline Offline
Sr. Member
****
Karma: 14
Posts: 354
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Anyways, with the above code my usage of pour looks like:
...
      pour(vodka1st, vodka2nd, vodka3rd, vodka, oh); End();
...    
... I would LOVE to find a way to make the code work like this:

pour(vodka, oh);

//where "vodka" in this case is a function that contains both vodkashift and the const int vodka.

This is a great observation!  I believe what you looking for is a structure, not a function:
Code:
struct dispenser {
  int shift1, shit2, shift3;  // "shift address"
  long totalOz;  // total ounces to date
  // other stuff specific to one pump
  char *name;
};

Then
dispenser vodka;  // vodka variable is no longer a mere int, it is now a structure
vodka.shift1= 0; vodka.shit2=16;  vodka.shift3 = 0;  // initialize it in setup()
vodka.name = "Vodka";

...

void pour( dispenser & disp, int amt)
{
   ...digiW
   shiftOut(data, clock, MSBFIRST, disp.shift1);
   shiftOut(data, clock, MSBFIRST, disp.shit2);
   shiftOut(data, clock, MSBFIRST, disp.shift3);
   ...digiWr
   ... pumpOn
   delay( "amt");
   ... pumpOff
   ...
   Serial.print "Total " << disp.name << " poured to date " << disp.totalOz ..
}

Then you are there!

Code:
pour( vodka, oh);  

Later maybe we talk about
  dispenser vodka("vodka", 0, 16, 0);
and the equivilance of
  pour( vodka, oh)
=
  vodka.pour(oh);

smiley

Cheers,
John

« Last Edit: January 31, 2013, 11:42:06 pm by johncc » Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 548
Posts: 46004
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
vodka.shift1= 0; vodka.shit2=16;  vodka.shift3 = 0;  // initialize it in setup()
Not sure that second statement is going to work too well.
Logged

Temple, Texas
Offline Offline
Sr. Member
****
Karma: 14
Posts: 354
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It'll work just fine.  I put that there because he 'tends "the good sh*t".
Logged

Illinois, US
Offline Offline
Jr. Member
**
Karma: 2
Posts: 97
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Johncc:

Whoa, blowin my mind.  I have been meaning to learn about structures... perhaps now is the time!  I'll try to dig up a tutorial or two so I can wrap my mind around the idea you just laid down.  It seems like a cool solution.  Now to just understand it fully LOL.  I'll get on some tutorial action after work tonight!

Nick Gammon:

I tried the 10k pull down resistor on the latch pin like the diagram shows, but it still lights up random lights on first power-on...

dHenry:

Ah yes... you are correct about that.  And I see why now.

Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You may need to put a pull-down resistor on the chip reset line, to keep the chip in reset. Then when you are ready bring that high (use a processor pin to do that).
Logged

Pages: [1] 2 3   Go Up
Jump to: