Triple Shift Register question

Why is a function call more clunky than what you wished for ?
You wanted

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

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

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 How do you pass a function as a parameter in C? - Stack Overflow for passing function names to functions.

US ribbon cable source - dipmicro electronics
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.

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.

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: Gammon Forum : Electronics : Microprocessors : Using a 74HC595 output shift register as a port-expander

  1. 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.

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.

Jim_Socks:
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:

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!

pour( vodka, oh);

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

vodka.pour(oh);

:slight_smile:

Cheers,
John

vodka.shift1= 0; vodka.shit2=16;  vodka.shift3 = 0;  // initialize it in setup()

Not sure that second statement is going to work too well.

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

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.

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).

Jim_Socks:
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...

Random drink dispenser - could be interesting.

UKHeliBob:

Jim_Socks:
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...

Random drink dispenser - could be interesting.

(O.T.)
Yeah you could get a random drink to enjoy while you're having a random tattoo applied by by Chris Eckert's "Auto Ink":

Auto Ink is a three axis numerically controlled sculpture. Once the main switch is triggered, the operator is assigned a religion and its corresponding symbol is tattooed onto the persons arm. The operator does not have control over the assigned symbol. It is assigned either randomly or through divine intervention, depending on your personal beliefs.

EEK!

It sounds like this auto ink creation could use a little less "auto" !

Also of note:

Yesterday while I was out of the house- the house lost power! How ironic that we JUST disscussed this in the thread! And just as we discussed- when power came back on a bunch of random lights came on- causing two liters of water to be pumped into a cardboard box full of clothes and books :fearful:

I returned to find a mess, but it could've been WAY worse if a finished barbot with 24 bottles of booze was connected! I really need to fix this glitch before pressing on any further lol

Read again Reply #14,
That is what you need to implement.

I did, but haven't implemented it yet. Just wanted to share the story :slight_smile:

Hmm... pull down 10k resistors on each MR line, with a pin controlling when it goes high, STILL does not alleviate random lights from coming on when power is first applied.

Why aren't these solutions working? Should I be using different sized resistors?

The only thing I haven't tried now is a pull-up resistor on the output enable lines... But judging by these attempts I am having little faith that it will work? What I don't get is, on Nick Gammon's schematic he lists a single 10k pull down. He says it will stop erroneous inputs from coming in during power-on. This leads me to believe that it works for him. Why didn't the same method work for me?

Then I used pull-downs on the master reset lines, and controlled the output with pin 5. This didn't stop the erroneous inputs, either. (granted, with this setup, the inputs would go away as soon as the code initialized and brought MR low, but by this time I would already have 8 different types of booze splattered all over my counter...)

Maybe I am just doing something wrong... I'll quad-check it...

...seems to be correctly wired. I don't get it. Should I have to use this many outputs to control this phenomenon? These pull-down resistors should have done the trick, right?

One resistor should have done it, and wire all the /MR pins in parallel.

Looking at the datasheet again, perhaps what you need is /OE to be wired high (via a pull-up). That will force the outputs to be high-impedance. Then put pull-up or pull-down resistors as appropriate on each output pin. That will pull them to the desired level, while /OE (output enable) is high.

He says it will stop erroneous inputs from coming in during power-on.

However it boots so quickly I can't say for certain that it worked. :slight_smile:

Why not pull OE high instead, let it sit there while the code starts up, and don't take it low until some valid data has been clocked in & latched.

Pin 10 of the shift register ~SNCLR should be pulled low with a resistor suitable for the logic family you have. That is a 10K for a HC or a 470R for an LS. This will clear all the outputs of the shift register. Then once you have booted, it should be taken HIGH to allow data to be clocked into the shift register.
If this pin is not resetting all the shift register bits then either you have wired it wrong or you have a faulty chip.

That is the same as /MR (master reset) that we have been discussing.