A Halloween Display Project - Am I Doing This Right (ish)?

Arduino R3
IDE 2.2.1
Developing on Ubuntu Linux

I've been doing this about two weeks, I'm sure it's very primitive. The task: visualize three mock "cannons" (or go to the TL;DR below to see them.) The goal is to execute three random signals, one each to lights, sound stored on an ISD chip (or 3) and one to relays to signal three fog machines for a short burst. This will likely be a long thread as I develop, make mistakes, and blow stuff up.

I have the first of the three parts, the lights, complete and working, as below. The LED's are only red, green, and yellow for development, I will probably use 2 reds, 1 yellow in each cannon. I am employing the LD74HC595 shift register to send the signals, as you can see I still have pins open for the other two parts of the project. My questions: does this circuit adequately isolate power demands from the Arduino? I will need to add ISD's for the sounds as suggested here and relays to control the fog machine switches, will I potentially blow up the chip or the Arduino? Am I doing this all wrong and do you have suggestions for a better way?

The schematic (I absolutely LOVE KiCad!) Sorry for the misalignment on the pins, I had to mod the 595 chip to match mine and had the grids messed up.

The Fritzing:

The code is not really relevant at this point, it works, but for reference, well commented as to what it's doing (and not, yet.)

/*
 * Cannons project 11/23
 *
 * Goal is to fire off three sets of synchronized signals to mock cannons: LED lights, sound boom, fog burst.
 * See cannons.kicad_pro and cannons-project-1.fzz (fritzing)
 *
 * Pins for 74Hc595 SPC Shift Register
 *
 *  1 = LED set 2 (3 green) register 6
 *  2 = LED set 3 (3 yellow) register 5
 *  8 = ground, 3-7 empty
 *  9 = empty 
 * 10 = +5v PS
 * 11 = Arduino 9 clock
 * 12 = Arduino 11 latch
 * 13 GND
 * 14 = Arduino 12 data
 * 15 = LED set 1 (3 red) register 7
 * 16 = +5v
 *
 * LED's - + to PS, 220 ohm resistor, common pinned as above (red -> 15, green -> 1, yellow -> 2)
 *
 * @TODO: Only lights implemented 11/23. We'll require two other sets of registers to fire at the same time:
 * 1) 3 DSI chips to hold "boom" sounds (or will one do?) Amplifier will not be needed, connects to
 *    external speaker jack with its own power. 
 * 2) 3 relays to control fog machine trigger switched for momentary "puff"
 *
 */

// Set to false to remove iteration stop and serial output
bool debug = true;

// 12 ST_CP [RCK] on 74HC595
int latchPin = 11;  

// 11 SH_CP [SCK] on 74HC595    
int clockPin = 9;  

// 14 DS [S1] on 74HC595    
int dataPin = 12;  

// Only using 3 registers on the 595: 7 is pin 15, 6 is pin 1, 5 is pin 2
// @TODO pick randomly, currently cycles through 0, 1, 2
int ledRegisters[] = { 7, 6, 5 };

// @TODO sound - need chip first to configure, dummy pin for testing to LED.
int soundPins[] = {5, 6, 7};

// @TODO fog relays - also dummies at this point.
int fogPins[] = {8, 10, 13};

// Fire the sequence, restart after (ms). @TODO control by potentiometer.
int fireDelay = 3000;

// holds max time between firing the 3 events, stored boomDelay. @TODO: Another potentiometer
// Should probably make sure this does not exceed fireDelay
int maxRandom = 400;

// How long to leave pin on HIGH. May need to address the three individually.
int fireLength = 100;

// For the shiftOut
byte leds = 0;

// Delay to the next "boom"
int boomDelay;


// Just for testing - if exceeds numIterations return from loop
int numIterations = 5;
  int numRun = 0;

/*
 * Print Serial messages. Only runs if debug == true
 * Must have a code error somewhere, won't run if this is below
 * @return bool
 */
bool debugPrint(int eventNum = 0, int boomDelay = 0)
{
    if (! debug) {
      return false;
    }

    Serial.println( "Current event " + String(eventNum) + " Current LED " + ledRegisters[eventNum] +
    " boom delay " + String(boomDelay) + " current sound " + String(soundPins[eventNum]) +
    " current fog relay " + String(fogPins[eventNum]));
  
  return true;
}

/*
 * - Set random seed from analog 0
 * - setup pins
 * - setup variables
 * @return void
 */
void setup()
{
  if (debug) { Serial.begin(9600);}
  
  // Guess we should be sure not to use analog 0
  randomSeed(analogRead(0));
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);

}

/*
 * Loop through the process.
 * @return void
 */
void loop()
{
  if (isMaxIterations()) { return; }

  for (int currentEvent = 0; currentEvent < 3; currentEvent++) {

    // Only need this in a variable for debugPrint, otherwise could be in the last delay
    boomDelay = (int)random(100,maxRandom);

    debugPrint(currentEvent, boomDelay);

    bitSet(leds, ledRegisters[currentEvent]);
    updateShiftRegister();
    delay(fireLength);

    bitClear(leds, ledRegisters[currentEvent]);
    updateShiftRegister();
    delay(boomDelay);
 
  }
  // delay the next firing by fireDelay
  delay(fireDelay);

}

/*
 * Write the data to the register
 * @return void
 */
void updateShiftRegister()
{
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, leds); 
    digitalWrite(latchPin, HIGH);

}

/*
 * only used if debug == true; exit execution in loop()
 * Puts Arduino in infinate loop that does nothing.
 * @return void
 */
bool isMaxIterations()
{
  numRun++;
  if (numRun > numIterations) {
    Serial.println("Exiting after " + String(numRun) + "iterations");
    return true;
  }

  return false;
}

The TL;DR

Why am I doing this? Halloween is my wife's favorite holiday, Christmas, blah, New Years, we're in bed by 10. This year she said we were doing pirates and wanted a pirate ship. Hoo boy. So I built one, all out of scrap materials that would be thrown away. The relevance: you can see the cannons here and they're doing stock long bursts, totally un-cannon like, no booms, I just can't let it happen next year.

You can see the cannons, but you'll also see something else at 1:30, which is another Arduino project. There are two skeletons in a sword fight - static. That doesn't fly with me either, nope, uh uh, those characters gotta move. I already have a ton of servos, both micro and high torque, on the table for that one. But that's another day. :smiley:

The LED resistors should be a bit larger, ≈ 470R

OK. I wondered if I got the schematic wrong. It was my first one in KiCad. It works, see fritzing.

Edit: fixed.

How are you powering the Arduino?

1 Like

Thank you! For the breadboarding I'm using the USB port, so there are two USB's, one for the power supply, powered by an adapter, one directly to the Arduino, powered by computer USB. In the final project it will most likely be a single 6-9v adapter, probably max 2amps, connected to the power jacks of the circuit board and the Arduino. I may or may not swap out the R3 with a mini or Mega when I get close to completion.

Standard form for Halloween projects is to kick off on the 25th of October or so :stuck_out_tongue:

Bonus points in that case if the Arduino is completely new to you.

So a year of lead-time is impressive - congratulations!

2 Likes

You oughta add a .1µF decoupling cap. to the shift register, too.

Thank you, right? As mentioned I only picked up the R3 super starter a few weeks ago, I figure a year should be just enough LOL . . . . There are other things too, like animating characters, making some physical mods to the ship prop to make it easier to move, more things for the kids to ooh-aw over, I love it. I've messed with electronics off and on most of my life, but have to re-learn everything. My strong point is the code, did that for 27 years. :-\

Case in point to the above, why? I know what a cap does (generally,) would this to be reduce noise, control random signals, what? And what pins? You're dealing with an ignoramus here. :smiley: (Off to search for decoupling . . . . )

Edit: Isolate noise, got it, presuming this would be pin 16 and ground.

:+1:t4:

Thanks kolaha, what's the advantage of using the mosfets? (Not as if I know what I'm doing, but I just read a few data sheets on them LOL)

const bool debug = true;

// 12 ST_CP [RCK] on 74HC595
const byte latchPin = 11;  

// 11 SH_CP [SCK] on 74HC595    
const byte clockPin = 9;  

// 14 DS [S1] on 74HC595    
const byte dataPin = 12;  

// Only using 3 registers on the 595: 7 is pin 15, 6 is pin 1, 5 is pin 2
// @TODO pick randomly, currently cycles through 0, 1, 2
//const byte ledRegisters[] = { 7, 6, 5 }; they are not connected to Arduino

// @TODO sound - need chip first to configure, dummy pin for testing to LED.
const byte soundPins[] = {5, 6, 7};

// @TODO fog relays - also dummies at this point.
const byte fogPins[] = {8, 10, 13};

// Fire the sequence, restart after (ms). @TODO control by potentiometer.
const int fireDelay = 3000;

// holds max time between firing the 3 events, stored boomDelay. @TODO: Another potentiometer
// Should probably make sure this does not exceed fireDelay
const int maxRandom = 400;

// How long to leave pin on HIGH. May need to address the three individually.
const byte fireLength = 100;

Thanks again . . . in most languages defining a variable as a constant means it cannot be modified later in the program, is that not true in the C - like language? That makes sense for pin assignments, not so sure about the vars that may change.

near to unlimited sink current. compare to 595.

1 Like

theoretically - yes, in this sketch fireDelay will not change.

At this point, but see comments - I will probably add pots to control both the "fire delay" and "restart delay." Your schematic with the mosfets has shed a lot of light on my original question. Even though I'm using an external power source, I'm still using the shift register to power this part of the circuit (correct?) I need to change this circuit from source current to sink current, this article demonstrates it very clearly. Thank you!

try not to solve not existing problem

1 Like

Haha . . . I was thinking this before I even started, "do I even need the shift register?" Using a sink current design for this part, no, I don't.

Thanks again all, it's been since November but have been collecting parts, experimenting, and working on this in my spare time. Here is where I'm at as of today, fully functional. TL;DR below. :smiley:

<TL;DR>
Thanks @ kolaha this all works perfectly just one thing - I had no idea 2N7002's were so small ->| |<-- LOL . . . yes I could have paid more attention to the data sheet. Anyway now I have a little experience in surface mount soldering with the breakout boards. :smiley:

I've added 3 10k pots to vary the max number in the Arduino/C random() function. This was to vary the length of the flash, the delay between the three "booms," and the restart delay. It all works as expected but random() is not all that random. Anyway still working on this, thanks again for your guidance and help, I'll update as it progresses.
</ TL;DR>