Scoreboard via Code and Shift Registers

Can someone please give me a hand to confirm some voltages for the items listed below before I start creating my power supply.

I'm creating a scoreboard using the following items:

  • 24V, 15A regulated power supply
  • 15 off 24V seven segment digits
  • Arduino Uno - supply voltage range on 7 to 12V
  • 15 off TPIC6B595 shift registers - supply voltage - 4.5 to 5.5V
  • A siren - supply voltage 12V
  • LED strobe light - supply voltage 12V
  • DS3231 real time clock - supply voltage range 2.3 to 5.5V
  • 12 Channel receiver - supply voltage 12V
  • 15 off 0.75" CA 7 segment displays for breakout test board - 12V, ??mA per segment

So I'm trying to rationalize supply voltages given the above:

  • 24V for large digits - straight off the supply, 105mA draw/segment = 11.7A draw total
  • Arduino - what is the best voltage to supply via "Vin"? Current setup draws 68mA
  • TPIC6B595 - spec sheet says Logic Supply voltage Vcc = 7V. Is there a range? Not sure the mA draw on Vcc for each register
  • Siren 12V, 200mA
  • Led strobe light 12V, 18mA
  • DS3231 - 5V, 3mA draw. Best from Arduino? Note, this will be located 1m from the main board - outside the scoreboard (for ambient temperature monitoring). Will this cable length affect anything?
  • 12 channel receiver, 51mA draw
  • Small 7 segment displays - 12V, 8mA (total max 840mA)

Summary: 24V @ 11.7A, 12V @ 1.19A (68+200+18+51+840, 7V @ ?mA, 5V @ 51mA.

So it seems I need 24V, 12V, 7V and 5V. Do I need all these diverse voltages or can the 595's run off 12V? Should I run the DS3231 from the arduino board or is a separate supply better? Is it best to supply these with voltage regulators such as L7812 (for fixed 12V), LM317 (for 7V) and L7805 for fixed 5V)?

The TPIC6B595 works with 5V, no special power supply nor logic level translators required. Please don't confuse maximum ratings and typical/recommended ones. Also check whether the large LED digits require 24V or 2.4V. A 24V*12A ~ 300W illumination looks questionable to me.

Long logic power supply cables should be terminated by a capacitor, to eliminate spikes.

The Uno on-board regulator can provide logic supply voltage (Vcc=5V) to the connected logic chips.

Thanks DrDiettrich.

I see now. The spec sheet on the TPIC6B595 says the "absolute maximum ratings" for the Logic supply voltage is 7V. Then on the following page it says "recommended operating conditions" for the Logic supply voltage is between 4.5V and 5.5V. Hence 5V sounds good. Ta.

The large LEDs I've made do run at 24V. They're about 300mm high x 200mm wide with 360 leds each. So all good there - hence the large power supply.

Is it for the DS3231 time/temperature module that you are suggesting a terminate with a capacitor to eliminate spikes? If so, what size (0.1uF cerami?) and how is it wired in. Does it go across Vcc and Gnd as close to the sensor as possible?

So what I think you're saying is I can supply 5V to both the module as well as the 15 shift registers directly from the Arduino Uno. Is that correct? I do measure the current draw as only 8mA.

cjcj:
Is it for the DS3231 time/temperature module that you are suggesting a terminate with a capacitor to eliminate spikes? If so, what size (0.1uF cerami?) and how is it wired in. Does it go across Vcc and Gnd as close to the sensor as possible?

Each of the TPIC6B595 chips should have a 0.1uF cap as well. The time module may have a bypass cap next to the chip already.

Thanks Duane.

I have designed in a cap next to each TPIC6B595. I'm still however not sure on checking if I need a cap for the time/temperature module, size and where to place it. Not sure if the module has one already.

Also, I tried to use a voltage regulator that I had laying around (MC78T12C - 12V, 3A) for the 12V supply off the 24V supply. I found however that it got really hot quickly. At 1.1amps (max draw), I'm guessing this is (24-12)x1.1 = 13.2Watts. This is quite a big heat sink. Is there a better way? I'm guessing it might be cheaper to just purchase a 12V 2A plug pack?

cjcj:
Also, I tried to use a voltage regulator that I had laying around (MC78T12C - 12V, 3A) for the 12V supply off the 24V supply. I found however that it got really hot quickly. At 1.1amps (max draw), I'm guessing this is (24-12)x1.1 = 13.2Watts. This is quite a big heat sink. Is there a better way? I'm guessing it might be cheaper to just purchase a 12V 2A plug pack?

You can get nice cheap little switching DC-DC converters that would be far better than the linear MC78T12C + big heatsink.
Something like this can handle a 24V input and produce 12V out at up to 4A, without generating all of that heat:-
DC 4-38V to 1.25-36V Step-Down(Buck) Converter 5V/12/24V 5A Power Supply Module

Get a switched mode regulator sometimes called a buck converter. These do not generate as much heat as they are not burning off the excess power.

Hi,
You have given us a list of the components your are going to use, BUT, not what your project is, what is the application of all these bits.
Edit, Sorry eyes tired, didn’t see the scoreboard bit.

Can you please post a copy of your full circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
It is getting to a stage where you are having load current problems, yet we have no idea what is causing them.
Even a picture of you project as it stands will help.

A picture, a circuit diagram and a sketch is worth a thousand words and can save a thousand ill informed posts.

Thanks…Tom… :slight_smile:

OldSteve:
You can get nice cheap little switching DC-DC converters that would be far better...

Thanks Steve. That looks perfect. Looking however at what others have bought more of, I found this link:
DC 4V-38V to 1.25V-36V 5A Step Down Power Supply Buck Module 24V 12V 9V 5V New

TomGeorge:
...Can you please post a copy of your full circuit, in CAD or a picture of a hand drawn circuit in jpg, png? It is getting to a stage where you are having load current problems, yet we have no idea what is causing them. Even a picture of you project as it stands will help.

Thanks Tom.
Interesting, today I've been preparing a schematic as suggested by "CrossRoads" in another thread I posted. I'm not sure however whether to start a new thread here and include both the project description, schematic and code - asking for someone to help check it prior to me now making the circuit board. The topic name should really be something different. What do you suggest?

DON'T start a new thread!
All questions about a project should be in a single thread.
Ask a moderator to merge the threads you already have posted.( click "report to moderator" at the bottom of the post)

It's much easier to help if all the information is in one place.
You can edit the topic header if you wish

cjcj:
Thanks Steve. That looks perfect. Looking however at what others have bought more of, I found this link:
DC 4V-38V to 1.25V-36V 5A Step Down Power Supply Buck Module 24V 12V 9V 5V New

Even better - exactly the same and far cheaper. (And it looks like they also provide a heatsink, in case you need it.)
I just linked to the first one I came across, as an example. I wasn't necessarily saying to buy that particular one. (I didn't think you'd be here in Oz, actually.)
AU$2.28 delivered sure beats the other one at $5.99. :slight_smile:

Hutkikz:
DON’T start a new thread! All questions about a project should be in a single thread…

Oops, I’m glad I asked. I’ve just now asked a moderator to make that happen. Ta

So I will therefore add the info here.

Outline:
I’ve created a scoreboard from discrete components (2014/2015) for my soccer club. It runs on large 7 segment displays I made (with circuit boards printed for me in China). It has a clock, temperature display, home score, away score, count-down timer. I’m now wanting to change the circuits to code and shift registers (for ease of repair / fault finding). I’ve finished the breadboard setup that includes all of the above, plus a siren, a strobe light (to say the siren is active), a method of turning the display off my remote, displaying a test pattern on all displays, included ability to set the game time to any number of minutes, and I’ve also added 15 small 7 segment displays on a break-out board to check things when fault finding. I haven’t checked this breadboard with all 15 large 7 segment displays (as they are on the scoreboard!). I can only test 2 displays (I have as spares).

I’m now at the stage I’d like someone to “overview” the finished code for major oversights, and also check my circuit layout (sufficient capacitors, correctly sized components, etc). Attached is a copy of the code as well as a PDF of the schematic. Sorry, this is the first “schematic” I’ve ever drawn up, so hopefully it reads correctly. If not, please let me know of mistakes and I’ll amend it so others can use it. Thanks in advance.

Scoreboard_17-01-16_uno.ino (36.1 KB)

Scoreboard schematic V1.pdf (234 KB)

Thank You
You'll need to edit the topic header in your first post to get it to show up in the forum listing that way.

cjcj:
Attached is a copy of the code…

It’s better if you post your code, rather than attach it. And it must be posted between code tags. </> in the “Reply”
dialog. When it’s just attached, we have to download it, create a folder then open your code in our IDE. And afterwards, the folder remains unless we navigate to the “Temp” folder and manually remove it. It’s much easier to just view the code in your post.

The only way I’ve worked out to attach my code (as it’s 800 lines worth is to do it in 4 segments, so here goes…

/* Part 1 of 4...

This program is used to display the current melbourne time, current ambient temperature, incrementing 
and displaying the home score, displaying and incrementing the away score, setting a game duration (up 
to 59 minutes), counting up to this set half time duration and sounding a siren alert when the duration 
is reached.  Where buttons are used herein, these will be replaced with wireless remote tranismitter/
receiver.

It is operated with this code loaded on on an Arduino Uno, a circuit board, 24VDC and 12VDC supply and
the scoreboard itself.

This sketch includes the following:

1.  A DS3231 real time clock module is used to read the current temperature and time.  The same
    module automatically adjusts for Melbourne, Australia day light savings time. This clock module
    uses the arduino I2C bus.  This is pin A4 to SDA(data) and A5 to SCL(clock)
    This unit required between 2.3 to 5.5V - perfect for running via Arduino power.
    Suggestion - cut the link between the diode and "201" resistor as this module does not come
    with a rechargeable battery (not to mention the charge voltage is insufficient!)
    https://edwardmallon.wordpress.com/2014/05/21/using-a-cheap-3-ds3231-rtc-at24c32-eeprom-from-ebay/
    
2.  An LDR is used to control the brightness of the 7 segment displays.  One leg to ground, the other
    leg to 10K resistor to Arduino 5V.  Same resistor leg to analog pin A0.

3.  The code also includes an array of "nth" number of switches with corresponding "nth" number
    of actions.

4.  Each switch has 3 operations - quick single press, quick double press and long press

5.  A home and away score based on 2 x 7 segment LED digits for each score.
    These count from 00 to 99 with an increment increase with a single press of a dedicated remote button.
    An increment decrease can be achieved with a quick double click of that same button.
    Each score can be reset back to 00 with a long press of that same button.

6.  The score / numbers are updated to TPIC6B595 shift registers which can handle the large 24V, 7 segment
    displays used here for this project.  These require a supply/signal of up to 7V which I'm delivering
    with 12V.  These registers have an output rating of 50V, 150mA with a max of 500mA.

7.  To get the colon blinking when the timer is running, I run the character "c" on the temperature
    with a dot (216) and without a dot (88).  This data is shifted to the shift register which grounds
    to turn on and off the colon about every 0.5 seconds.  I use the change in seconds to trigger
    the "on" signal.
    To activate the continuous blinking colon for the current time, I have utilised one of the outputs from
    the shift register (the one that only displays a "c" for celcius).  For the timer that requires
    blinking during operation and steady on when paused, I have used another output from the same register

Created by Chris Job 2015/2016
*/

//--[libraries]---------------------------
#include <DS3232RTC.h>                    //http://github.com/JChristensen/DS3232RTC
#include <Streaming.h>                    //http://arduiniana.org/libraries/streaming/
#include <Time.h>                         //http://playground.arduino.cc/Code/Time
#include <Timezone.h>                     //http://github.com/JChristensen/Timezone
#include <Wire.h>                         //http://arduino.cc/en/Reference/Wire

//--Display variables---------------------
enum displayState {                       // display on/off/test
  display_off,                            // can be used to turn off displays at end of day
  display_on,                             // can be used to turn on displays at start of day if turned off
  display_test                            // this can be used to test all 7 segment display LED work
}; // end enum

int displayState = display_test;          // all led digits off until button pressed

// Below are numbers 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, c with seg 2, c, c with seg 1&2, and nil.
// In order to get the same led intensity on both the time colon (that continually blinks) and the timer colon (that only
// blinks when the timer is running), spare outputs from shift register used for the "c" (celcuius) 7 segment digit are used.
// Hence below, 88+2, 88 and 89+1+2)
const int digit[14] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111, 88+2, 88, 88+1+2, 0};
// below are firstly each edge of the display, then 9, 8, 7, 6, 5, 4, 3, 2, 1 and 0
const int test[18] = {2, 4, 8, 16, 32, 1, 64, 0, 111, 127, 7, 125, 109, 102, 79, 91, 6, 63};

/* The above decimal value is used to display numbers 0 to 9 based on:
         1
     -----------
     |         |
32   |         | 2
     |   64    |
     |---------|
     |         |
16   |         | 4
     |   8     |
     |---------|

Using above, "0" is 1+2+4+8+16+32=63.  "1" is 2+4=6. Etc, etc.*/


//--push button variables-----------------
enum buttonStep {                         // used in knowing the push button positions
  button_ready,
  button_pressed,
  button_released,
  button_checkdouble,
  button_finish
}; // end enum

const int num = 7;                        // change this number to suit number of buttons below
byte button[num] = {2,3,4,5,6,7,8};       // current push-buttons connected to these pins (called up as 0,1,2,3,4,5,&6)
byte buttonState[num] = {1,1,1,1,1,1};    // set button states to high
byte n = 10;                              // used for flashing colon
int p = 1000;                              // delay for startup test pattern
unsigned long previousMillis = 0;         // used in pushbutton timinig
unsigned long currentMillis = 0;          // used in pushbutton timinig
unsigned long pressStartTime = 0;         // used in pushbutton double click recognition
unsigned long buttonPressLength = 0;      // length of time the button is held pressed
unsigned long buttonPressLong = 1000;     // min time required for long press delay
unsigned long doubleClickMax = 250;       // max time allowed between "double clicks"
const int debounce = 50;                  // to stop mulitiple false triggering
int buttonStep = button_ready;            // used to progress in pushbutton stages
byte i;                                   // used in a loop to go through each button number
byte j;                                   // used to ensure switch loop cycle completes for current switch only


//--Siren variables-----------------------
enum sirenState {                         // used in indicating the siren has been requested
  inactive,                               // as well as allowing sounding it once
  active,
  completed
}; // end enum

int sirenState = inactive;
byte sirenPin = 16;                       // digital pin used to pass the "tone" to the siren
byte siren = 1;                           // used in turning the sound off after a set duration time
unsigned long sirenStartTime = millis();  // used to set the siren sounding length
int sirenDuration = 500;                  // siren "sound on" duration


//--Strobe variables----------------------
enum strobeState {                        // used to make the strobe active or inactive                     
  not_flashing,
  flashing
}; // end enum

byte strobePin = 17;
byte strobe = 1;                          // used for toggling the light on and off
int strobeState = not_flashing;
unsigned long strobeStartTime = millis(); // used to time the flashing of the strobe
int strobeOn = 200;                       // strobe on time
int strobeOff = 2000;                     // strobe off time


//--[LDR variables]-----------------------
const byte ldrIn = A1;                    // arduino pin A0 to leg 1 of the LDR as well as leg 1 of a 10K resistor
                                          // LDR leg 2 to GND and leg 2 of the 10K to Arduino 5V
const byte dimPin = 10;                   // arduio pin 10 connected to the TPIC6B595 pin 9 (Output Enable)
int ldrVal = 0;                           // variable to store the value coming from the sensor


//--Shift register variables--------------
const byte dataPin = 12;                  // arduino pin 12 to TPIC6B595 pin 3 serial in (SER IN)
const byte latchPin = 11;                 // arduino pin 11 to TPIC6B595 pin 12 latch signal (RCK)
const byte clockPin = 9;                  // arduino pin 9 to TPIC6B595 pin 13 clock (SRCK)
Part 2 of 4...

//--Score variables-----------------------
byte a = 0;                               // ones digit for home score
byte b = 0;                               // tens digit for home score
byte c = 0;                               // ones digit for home score
byte d = 0;                               // tens digit for home score

//--[timer variables]---------------------
enum counter {                            // used to start, pause and reset timer
  waiting,
  start,
  pause
};

int counter = waiting;                    // initial setup - waiting for input to start timer
byte e = 0;                               // Counting timer minute (tens)
byte f = 0;                               // Counting timer minute (ones)
byte g = 0;                               // Counting timer seconds (tens)
byte h = 0;                               // Counting timer seconds (ones)
byte ee = 0;                              // used to record pre-set game time minute (tens)
byte ff = 0;                              // used to record pre-set game time minute (ones)



//--[clock & temperature]-----------------
//Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = { "AEDT", First, Sun, Oct, 2, 660};    //UTC + 11 hours
TimeChangeRule aEST = { "AEST", First, Sun, Apr, 3, 600};    //UTC + 10 hours
Timezone ausET(aEDT, aEST);
TimeChangeRule* tcr;                      //pointer to the time change rule, use to get the TZ abbrev
time_t utc, local;
byte secondAdvance;                       // variable used in progressing display every second
int currentTemp;                          // variable to store the current 


//--[timer colon blinking]----------------
enum blinkState {                         // used to blink the timer colon when "counting" active
  blink_on,
  blink_off
};

int blinkState = blink_on;
unsigned long blinkMillis = millis();     // timer setting used to "blink" timer colon
int blinkDelay = 500;                     // timer colon blink delay


////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(void) {
  //--[general setup]---------------------
  Serial.begin(115200);                   // enable Serial
  secondAdvance = second(now());          // used to display once per second
  usage();                                // run the "usage function"

  //--[define input pins]----------------- 
  for (i = 0; i < num; i++) {
    pinMode(button[i], INPUT_PULLUP);     // set button pins to inputs using internal pullup resistor
  } // end for loop
  
  //--[define output pins]----------------
  pinMode(latchPin, OUTPUT);              // used for shift registers
  pinMode(clockPin, OUTPUT);              // used for shift registers
  pinMode(dataPin, OUTPUT);               // used for shift registers
  pinMode(dimPin, OUTPUT);                // used for shift registers - controlling LED intensity
  pinMode(sirenPin, OUTPUT);              // used to activate a siren for end of game sessions
  pinMode(strobePin, OUTPUT);             // used to indicate siren will sound (as noted above)
  digitalWrite(strobePin, LOW);           // set strobe off on startup
} // end void setup


////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop(void) {
  //--[shift values to shift registers]---
  shiftDisplay();                         // pass on the result to the 595s

  //--[score function]--------------------
  buttonUpdate();                         // check if any of the buttons have been pressed
  setBrightness();                        // check LDR value to set LED brightness

  //--[siren and strobe function]---------
  sirenCheck();
  strobeCheck();

  //--[time setting function]-------------
  serialTimeSet();                        // handle serial commands for setting date/time

  //--[timer advance function]------------
  if (secondAdvance != second(now())) {
    blinkMillis = millis();
    secondAdvance = second(now());        // used to progress time every second
    count();                              // this advances counter seconds every second
    serial_Output();                      // print to serial monitor for testing only
  } // end if

  //--[colons blink functions]------------
  blinkTimer();
  blinkColons();                         // used to flash the colon on when timer operating
} // end void loop



////////////////////////////////////////////////////////////////////////////////////////////////////////
//--[for clock time check and setup]------
void usage (void) {
  // at startup, show some information about program usage and check RTC operational
  Serial.println(F("\nThe time on the RTC is to be set to UTC (Universal Coordinated Time)"));
  Serial.println(F("In melbourne, AEST (Australian Eastern Standard Time) is UTC + 10 hours"));
  Serial.println(F("In melbourne, AEDT (Australian Eastern Daylight saving Time) is UTC + 11 hours"));
  Serial.println(F("To set the UTC date & time via serial monitor:"));
  Serial.println(F("  a. Set carriage return and new line in the monitor"));
  Serial.println(F("  b. Set the appropriate baud rate (115200?)"));
  Serial.println(F("  c. Type in the following UTC time format:  yyyy,mm,dd,hh,mm,ss"));
  Serial.print(F("\nInitialize RTC ..."));
  //setSyncProvider() causes the Time library to synchronize with the
  //external RTC by calling RTC.get() every five minutes by default
  setSyncProvider(RTC.get);
  Serial << F("\nRTC Sync");
  if (timeStatus() != timeSet) Serial << F("Unable to sync with the RTC");
  Serial << endl;
  currentTemp = (RTC.temperature() / 4);
  delay(5000);  // delay to allow user to read the above on first startup of serial monitor
} // end usage loop


//--[Time & date upload via Serial monitor]---
void serialTimeSet(void) {
  static time_t utcLast;
  time_t utc;
  tmElements_t tm;
  //check for input to set the RTC, minimum length is 12, i.e. yy,m,d,h,m,s
  if (Serial.available() >= 12) {
    //note that the tmElements_t Year member is an offset from 1970,
    //but the RTC wants the last two digits of the calendar year.
    //use the convenience macros from Time.h to do the conversions.
    int y = Serial.parseInt();
    if (y >= 100 && y < 1000)
      Serial << F("Error: Year must be two digits or four digits!") << endl;
    else {
      if (y >= 1000)
        tm.Year = CalendarYrToTm(y);
      else    //(y < 100)
        tm.Year = y2kYearToTm(y);
      tm.Month = Serial.parseInt();
      tm.Day = Serial.parseInt();
      tm.Hour = Serial.parseInt();
      tm.Minute = Serial.parseInt();
      tm.Second = Serial.parseInt();
      utc = makeTime(tm);
      RTC.set(utc);        //use the time_t value to ensure correct weekday is set
      setTime(utc);
      Serial << F("RTC set to: ");
      printDateTime(utc, "UTC");
      Serial << endl;
      //dump any extraneous input
      while (Serial.available() > 0) Serial.read();
    } // end if statement
  } // end if statement
  
  //get the current time
  utc = now();
  if (utc != utcLast) {          //display once per second
    utcLast = utc;
//    printDateTime(utc, "UTC  ");                            // not sure what this is
//    printDateTime(ausET.toLocal(utc, &tcr), tcr -> abbrev); // not sure about this either
    local = ausET.toLocal(utc, &tcr);

    if (second(utc) == 0) {  //display temperature once per minute
      float c = RTC.temperature() / 4.;
      float f = c * 9. / 5. + 32.;
//      Serial << F("  ") << c << F(" C  ") << f << F(" F");  // dont need this in Aussie land!
      currentTemp = (RTC.temperature() / 4);
    } // end if statement
    Serial << endl;
  } // end if statement
} // end serialTimeSet loop

//--[Print date& time to Serial]----------
void printDateTime(time_t t, char* tz) {
  printDate(t);
  Serial << ' ';
  printTime(t);
  Serial << tz;
} // end printDateTime loop

//--[Print time to Serial]----------------
void printTime(time_t t) {
  printI00(hour(t), ':');
  printI00(minute(t), ':');
  printI00(second(t), ' ');
} // end printTime loop

//--[Print date to Serial]----------------
void printDate(time_t t) {
//  printI00(day(t), 0);
//  Serial << monthShortStr(month(t)) << _DEC(year(t));
} // end printDate loop

//--[add zero to if < 10}-----------------
void printI00(int val, char delim) {
  if (val < 10) Serial << '0';
  Serial << _DEC(val);
  if (delim > 0) Serial << delim;
  return;
} // end printI00 function

//--[add zero to if < 10}-----------------
void printI00(int val, char delim) {
  if (val < 10) Serial << '0';
  Serial << _DEC(val);
  if (delim > 0) Serial << delim;
  return;
} // end printI00 function
[\code]
// Part 3 of 4...

//--[output to serial monitor]------------
void serial_Output(void) {
  Serial << "\nCurrent Melbourne time: ";
  printI00(hour(local),0);
  Serial << ":";
  printI00(minute(local),0);
  Serial << ":";
  printI00(second(local), 0);
  Serial << "  ";
  printI00(day(local),0);
  Serial << "/";
  printI00(month(local),0);
  Serial << "/";
  Serial.print(year(local));
  Serial << ".  Temperature: ";
  Serial.print(currentTemp);
  Serial << "\nCurrent UTC time:       ";
  printI00(hour(),0);
  Serial << ":";
  printI00(minute(),0);
  Serial << ":";
  printI00(second(),0);
  Serial << "  ";
  printI00(day(),0);
  Serial << "/";
  printI00(month(),0);
  Serial << "/";
  Serial.print(year());
  Serial << ".  Temperature: ";
  Serial.println(currentTemp);
} // end serial_Output function

//--[update display to all shift registers]--------
void shiftDisplay (void) {
  if (displayState == display_test) {     // this first runs on startup, then if called
    for (byte t = 0; t < 18; t++) {
      for (byte s = 0; s < 15; s++) {
        digitalWrite(latchPin, LOW);
        shiftOut(dataPin, clockPin, MSBFIRST, test[t]);
        digitalWrite(latchPin, HIGH);
      } // end for statement
      delay(p);
      displayState = display_on;
    } // end for statement
  } // end if statement

  if (displayState == display_on) {       // this is during normal operation
    digitalWrite(latchPin, LOW);

    shiftOut(dataPin, clockPin, MSBFIRST, digit[b]);                  // Home score 10s digit (9)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[a]);                  // Home score 1s digit (10)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[d]);                  // Away score 10s digit (11)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[c]);                  // Away score 1s digit (12)

    shiftOut(dataPin, clockPin, MSBFIRST, digit[currentTemp / 10]);   // temperature (14)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[currentTemp % 10]);   // temperature (15)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[n]);                  // temperature - "c"
  
    shiftOut(dataPin, clockPin, MSBFIRST, digit[hour(local) / 10]);   // Current hour tens (1)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[hour(local) % 10]);   // Current hour ones (2)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[minute(local) / 10]); // Current minute tens (3)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[minute(local) % 10]); // Current minute ones (4)

    shiftOut(dataPin, clockPin, MSBFIRST, digit[e]);                  // Timer - hour tens (5)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[f]);                  // Timer - hour ones (6)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[g]);                  // Timer - seconds tens (7)
    shiftOut(dataPin, clockPin, MSBFIRST, digit[h]);                  // Timer - seconds ones (8)

    digitalWrite(latchPin, HIGH);
  } // end if statement

  if (displayState == display_off) {      // this is used to turn off the displays at the end of the day
    for (byte s = 0; s < 15; s++) {
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, digit[14]); // this display a nothing digit
      digitalWrite(latchPin, HIGH);
    } // end for statement
  } // end if statement
} // end shiftDisplay function


//--[7 segment display brighness control]-
// control of 7 segment display brightness from night to day use
void setBrightness(void) {
  ldrVal = analogRead(ldrIn);             // read the value from the light dependant resistor
  ldrVal = constrain(ldrVal, 70, 900);    // constrain value between 0 to 1024 pending light range
  ldrVal = map(ldrVal, 70, 1000, 0, 254); // map above value between max 0 to 255 (note 255 = off)
  analogWrite(dimPin, ldrVal);            // set brightness on TPIC6B595s
} // end setBrightness function

//--[button operation]--------------------
void buttonUpdate(void) {
  currentMillis = millis();                           // set currentMillis to the current time
  for (i = 0; i < num; i++) {                         // loop to cycle through each switch number
    buttonState[i] = digitalRead(button[i]);          // read current state of the first button

    // when button "i" is pressed, record the start time of the press
    if (buttonStep == button_ready && buttonState[i] == LOW && currentMillis - previousMillis > debounce) {
      previousMillis = currentMillis;                 // reset these variables in order to capture button release
      pressStartTime = millis();                      // record the time the button has been pressed
      currentMillis = millis();                       // set variable to current time
      buttonStep = button_pressed;                    // used to progress to the next loop instructions
      j = i;                                          // j variable used to continue with the same push button number in the following loops
    } // end if statement

    // if button is held down for a long duration do this step:
    if (buttonStep == button_pressed && buttonState[j] == LOW && millis() - pressStartTime > buttonPressLong) {
      previousMillis = currentMillis;                 // reset these variables in order to capture button release
      switchAction3();                                // Actions to be taken for a long duration press
      pressStartTime = 0;
      buttonStep = button_finish;                     // used to progress to last loop
    } // end if statement

    // if button is held down for a short duration do this step:
    if (buttonStep == button_pressed && buttonState[j] == HIGH && millis() - pressStartTime < buttonPressLong) {
      previousMillis = currentMillis;                 // reset these variables in order to capture button release
      buttonStep = button_checkdouble;                // used to progress to the next loop instructions
    } // end if statement

    // if button gets released before longpress time check if double click time expires:
    if (buttonStep == button_checkdouble && buttonState[j] == HIGH && millis() - pressStartTime > doubleClickMax) {
      switchAction1();                                // Action to be taken for a short single press
      buttonStep = button_finish;                     // used to progress to last loop
    } // end if statement

    // if button gets released before longpress time check if it gets pressed in time for a double click:
    if (buttonStep == button_checkdouble && buttonState[j] == LOW && millis() - currentMillis < doubleClickMax) {
      previousMillis = currentMillis;                 // reset these variables in order to capture button release
      switchAction2();                                // Action to be taken for 2 short duration presses
      buttonStep = button_finish;                     // used to progress to last loop
    } // end if statement

    // button has been double clicked so wait for release before reset
    // (note, longer debounce/pause time below included in order to inhibit false double click at this state)
    if (buttonStep == button_finish && buttonState[j] == HIGH & currentMillis - previousMillis > debounce) {
      previousMillis = currentMillis;                 // reset these variables in order to capture button release
      pressStartTime = 0;                             // reset variable as no longer required
      j = 100;                                        // set to a number larger than [num] for resetting purposes
      buttonStep = button_ready;                      // used to progress back to start of function
    } // end if statement
  } // end for loop
} // end buttonUpdate function


//--[single quick press]------------------
void switchAction1 (void) {
// J=0 is used for the home score
  if (j == 0 || j == 1) {
    if (j == 0 && a < 9) {a++;}                        // if home score ones < 9 add one to it
    else if (j == 0 && a == 9) {a = 0; b++;}           // if home score ones is 9, change to 0 and add one to tens
    else if (j == 0 && a == 0 && b == 10) {b = 0;}     // if home score tens is 10, change tens to 0

// J=1 is used for the away score
    if (j == 1 && c < 9) {c++;}                        // if away score ones < 9 add one to it
    else if (j == 1 && c == 9) {c = 0; d++;}           // if away score ones is 9, change to 0 and add one to tens
    else if (j == 1 && c == 0 && d == 10) {d = 0;}     // if away score tens is 10, change tens to 0
  } // end if statement
[\code]
Part 4 of 4...


// J=2 is used to set the game durations tens of minutes in memory
  if (j == 2 && counter == waiting) {                  // check timer is not counting
    if (j == 2 && e < 5) {e++; ee = e;}                // if minutes tens is less than 5, add one to it
    else if (j == 2 && e == 5) {e = 0; ee = e;}        // if minutes tens is 5, set it back to 0
  } // end if statement
  
// J=3 is used to set the game duration ones of minutes in memory
  if (j == 3 && counter == waiting) {                  // check timer is not counting
    if (j == 3 && f < 9) {f++; ff = f;}                // if minutes tens is less than 5, add one to it
    else if (j == 3 && f == 9) {f = 0; ff = f;}        // if minutes tens is 5, set it back to 0
  } // end if statement

//   J=4 is used to toggle the and siren & strobe on/off
//   When activated, a strobe will keep flashing to indicate that the siren will function.
//   By pressing button "2" (e) and "3" (f), the game duration is set.  To do this, variables
//   ee is made to equal e and ff=f.  When the timer is reset, e is made 0 and f=0.
//   When the counter is started, the program waits for e to reach the preset value ee
//   and f reach ff.  Then the siren will sound for the pre-set time.
//   When the timer is reset, the siren will then sound again at time ee and ff (until
//   the toggle J4 switches it off)

  if (j == 4 && sirenState == inactive) {               // check if the siren is inactive
    sirenState = active;                                // if it is, make it active and the strobe as well
    strobeState = flashing;
    return;
  } // end if
  if (j == 4 && sirenState != inactive) {               // check if the siren is active
    sirenState = inactive;                              // if it is, make it inactive as well as the strobe
    strobeState = not_flashing;
    return;
  } // end if
  
// J=5 is used to start, pause the timer here (00:00)
  if (j == 5 && counter == waiting) {                  // check if timer is not in operation
    e = 0;
    f = 0;
    shiftDisplay();                                    // this displays the current time immediately
    counter = start;                                   // reset digits to 0 then start timer
    count();
    return;
  } // end if statement
  if (j == 5 && counter == start) {                    // check if timer is in operation
    counter = pause;                                   // toggle to pause timer
    return;
  } // end if statement
  if (j == 5 && counter == pause) {                    // check if timer is paused
    counter = start;                                   // toggle to start timer again
    count();
    return;
  } // end if statement
  
// J=6 will turn on the led display if currently turned off
  if (j == 6) {displayState = display_on;}             // turn on display (whether on or off)
} // end switchAction1 function


//--[double quick press]------------------
void switchAction2 (void) {
// DUE TO USING A TRANSMITTER / RECEIVER WITH RELAYS, A DOUBLE PICK DOESN'T REGISTER, SO NOT USED HERE
/*
  
// J=0 is used to decrease the home score by one - in case someone increased it accidentally
  if (j == 0 && a > 0) {a--;}                          // if home score ones is > 0, decrease by 1
  else if (j == 0 && a == 0 && b > 0) {a = 9; b--;}    // if home score ones and tens > 0, decrease tens by 1 and change ones to 9

// J=1 is used to decrease the away score by one - in case someone increased it accidentally
  if (j == 1 && c > 0) {c--;}                          // if away score ones is > 0, decrease by 1
  else if (j == 1 && c == 0 && d > 0) {c = 9; d--;}    // if away score ones and tens > 0, decrease tens by 1 and change ones to 9

// J=2 is used to decrease the game durations tens of minutes in memory
  if (j == 2 && counter == waiting && e > 0) {e--; ee = e;}

// J=3 is used to decrease the game durations tens of minutes in memory
  if (j == 3 && counter == waiting && f > 0) {f--; ff = f;}
*/
} // end switchAction2 function


//--[long press]--------------------------
void switchAction3 (void) {
   if (j == 0) {a = 0; b = 0;}                                   // reset Home score - both digits
   if (j == 1) {c = 0; d = 0;}                                   // reset Away score - both digits
   if (j == 2 && counter == waiting) {e = 0; ee = 0;}            // if timer is not active, reset timer set minutes tens
   if (j == 3 && counter == waiting) {f = 0; ff = 0;}            // if timer is not active, reset timer set minutes ones
// J=4 is used to run the digit display test - incase somethings not working properly
   if (j == 4) {p = 200; displayState = display_test;}   // ----------------------------------- after testing, reset the correct p value -----------------------------
   if (j == 5) {e = 0; f = 0; g = 0; h = 0; counter = waiting;}  // reset timer to zero and put in standby mode
   if (j == 5 && sirenState == completed) {e = 0; f = 0; g = 0; h = 0; sirenState = active;}   // once siren has sounded, it will wait for time again
   if (j == 6) {displayState = display_off;}                     // turn off led displays - can be used at end of day

} // end switchAction3 function

//--[Increment the timer sec and mins]----
void count (void) {
  if (counter == start) {                 // if counter is operating...
   if (h < 10) {h++;}                     // if seconds is less than 10, add one
   if (h > 9) {h = 0; g++;}               // if seconds is >9, make 0 and add one to tens of seconds 
   if (g > 5) {h = 0; g = 0; f++;}        // if tens of seconds is > 5, set seconds to 00 and add one to minute ones
   if (f > 9) {f = 0; e++;   }            // if minute ones is >9, make 0 and add one to tens of minutes
   if (e > 5) {                           // if tens of minutes is > 5, set all digits to zero 00:00
     e = 0;
     f = 0;
     g = 0;
     h = 0;
   } // end if statement
  } // end if statement
} // end count function

//--[Timing for colon blinking]-----------
void blinkTimer (void) {
  if(millis() - blinkMillis < blinkDelay) {       // if blink delay (500ms) not reach, colon on
    blinkState = blink_on;
  } // end if
  if (millis() - blinkMillis > 1.9*blinkDelay) {  // if blink delay (1.9 x 500ms) reached, colon off (full cycle)
    blinkState = blink_off;
  } // end if
  if (millis() - blinkMillis >= blinkDelay) {     // if blink delay (500ms) reached, colon off
    blinkState = blink_off;
  } // end if
} // end blinkTimer function


//--[Strobe the colon during count]-------
void blinkColons (void) {
  if (counter == start && blinkState == blink_on) {                          // colon in on position for for both time and timer
    n = 12;
  } // end if
  if (counter == start && blinkState == blink_off) {                         // colon in off position on both time and timer
    n = 11;
  } // end if
  if (counter == waiting || counter == pause && blinkState == blink_on) {   // colon in on position for time and on when timer paused
    n = 12;
  } // end if
  if (counter == waiting || counter == pause && blinkState == blink_off) {   // colon in off position for time and on off when timer paused
    n = 10;
  } // end if
} // end blinkColons

//--[Used to sound a siren]---------------
void sirenCheck (void) {
  if(counter == start && siren == 1 && e == ee && f == ff && g < 1 && h < 1 && sirenState == active) {
    sirenStartTime = millis();
    tone(sirenPin, 480);
    siren = 0;  
  } // end if
  if(counter == start && siren == 0 && e == ee && f == ff && sirenState == active && millis() - sirenStartTime > sirenDuration) {
    sirenStartTime = millis();
    noTone(sirenPin);
    sirenState = completed;
    siren = 1;
  } // end if
} // end sirenCheck function

//--[Used to flash the strobe]------------
void strobeCheck (void) {
  if(strobeState == flashing && strobe == 1 && millis() - strobeStartTime > strobeOff) {
    strobeStartTime = millis();
    digitalWrite(strobePin, HIGH);
    strobe = 0;
    return;
  } // end if
  if(strobeState == flashing && strobe == 0 && millis() - strobeStartTime > strobeOn) {
    strobeStartTime - millis();
    digitalWrite(strobePin, LOW);
    strobe = 1;
  } // end if
  if(strobeState == not_flashing) {
    digitalWrite(strobePin, LOW);
    strobe = 1;
  } // end if
} // end strobeCheck function

// end program ---------------------------
[\code]

Maybe someone will go over all of your code, and the schematic as you ask, checking components one-by-one etc. Keep your fingers crossed. It's a big job.

OldSteve:
Maybe someone will go over all of your code, and the schematic as you ask, checking components one-by-one etc. Keep your fingers crossed. It’s a big job.

Thanks Steve.
Given my code seems to be working ok, it would only really be to “skim” over it to see if there is anything majorly wrong.

My main interest right now is if someone could have a quick look at my schematic as I’m wanting to start drawing up the circuit board. I’m not sure if I have used the correct capacitor values and if I have any current issues that I’m overlooking. This is the most important for me at this stage. If anyone can take a look, that would be great.

Scoreboard schematic V1.pdf (234 KB)