Part 1: Mega Digits

A Versatile Display System

Mike Hansell

Issue 5, November 2017

This article includes additional downloadable resources.
Please log in to access.

Log in

This system can create huge numerical displays. Suitable for use as a scoreboard, stopwatch, or just a really, really, REALLY big clock.

It's easy to connect an LCD or a 4-way 7-segment display to an Arduino. But what if you want to go bigger? We're talking MUCH bigger... MEGA DIGITS provides you with a useful and powerful display driver system, with virtually unlimited physical scale.

Using the powerful 74HC595 shift register IC, we can offload display processing from the Arduino, using just three GPIO points to drive an unlimited number count. This frees up the GPIO to drive separate displays. Perhaps you have a real time clock, stopwatch, score... all of these digits would quickly use up all available I/O on even the largest of microcontrollers. With this method we can have multiple number groups, using just three GPIO per group!

In this part 1, we're going to focus on building a working prototype using the 74HC595 shift register. Next month, we'll provide you with a useful PCB module to build each digit with. Each digit won't be a small 7-segment display use used here. It will be a 12V powered digit which can be made from 12V LED strip. This provides you with a powerful springboard to create digits as large as you want. One metre high display digits? Sure!


This project has 2 types of modules. A switch module and 6 x 7 segment display modules. The display modules can be cascaded and the sketch modified to suit.


We have designed this prototype as a single-digit display, which can be used as a "master" (driven from an Arduino), or a "slave" (driven from the previous display module in the chain. The 74HC595 is specifically designed to do this. The primary reason is simplicity. It means we are free to create one circuit per segment, without concern for its position in the system.

For a detailed look at the 74HC595 shift register, check out the What The Tech article for a deeper look at how it works. In this project we'll focus more on the function than how the chip itself works.


For our prototype, we're using standard Common Cathode 7-segment displays. To drive one of these directly from an Arduino requires 7 pins (8 for the decimal point too, but we're not using it in this system at this stage), which quickly adds up for multiple digits.

The shift register is a logic block that can convert serial data (1 bit at a time) to parallel (in our case 8 bits or 1 byte wide), or vice versa. The beauty of this is that we can transmit data from the Arduino to the shift register 1 bit at a time, using the Arduino’s shiftOut() function. That’s just 1 pin from the Arduino plus 2 more pins for control, but that’s it. It’s easy to cascade module to module with no extra pins used on the Arduino. You can see that’s a lot more efficient than using 7 Arduino pins, being 1 pin to switch each segment of the 7 segment display. In any case that might well exceed the limitation of the Arduino current handling spec.

Once we have our 8 bits loaded into the shift register we can tell it to set 8 of its output pins high or low depending on the data we sent it. This could easily be used to drive 8 LEDs to show the output in binary, but humans work better in decimal, so the sketch translates the digits appropriately.

Ok, that’s 1 digit but how does the cascade of modules work? The answer is very simply. The shift register has an ‘overflow’ pin that we simply connect to the next modules input pin. The 2nd modules overflow pin connects to the next module on and on.

Other than the 74HC595 IC and the 7 segment display itself there are just 7 resistors to limit the current from the IC and through each LED segment.

Note: it is possible to multiplex multiple displays from the one 74HC595 driver. However this rapid switching makes the overall display run slower the more digits you add, with the configuration we're using. The IC is rather cheap, so we decided to use one per display for this reason, as it increased reliability and reduced flicker overall. Especially as we introduce transistors to switch 12V outputs, and things get more complicated.


Before we take you through the build itself, we have an important note about the IC. Most makers will be well aquainted with handling CMOS devices but for the sake of safety here’s some advice.

CMOS is static sensitive. Have you ever walked across the carpet and got a "zap" or spark when you’ve touched something metallic? That’s static. Mini lightning if you like. That static buildup on your body can destroy totally or partially CMOS devices like the 74HC595 used in this project. CMOS devices should always be carried in some sort of anti-static material. You will have to handle the IC in this project but that doesn’t mean it will be damaged. At the minimum, touch something that is properly earthed before touching the device. Professionals use an anti-static wrist strap. I’d suggest you insert the IC into the breadboard once all of the other components installed.


Parts Required (Per Module)JaycarAltronics
1 x 7 Segment Display - Common Cathode ZD1855 Z0190
1 x 74HC595 Integrated Circuit ZC4895 Z8924
7 x 220Ω Resistors RR0556 R7542

You will also need standard prototyping hardware such as breadboards and jumper wires. We used one small breadboard per display, as this is how our PCB will be developed too. However there's no reason you cannot combine digits onto one breadboard as long as you have enough space.

Each module is assembled in an identical way. The single and only difference is the data. On the first module, it comes from Pin 11 on the Arduino. On subsequent modules, Pin 14 of the shift register connects to Pin 9 of the next module's shift register, and the cycle continues for each subsequent digit.

The CLOCK and LATCH pins are all common. You can daisy-chain them from breadboard to breadboard to make wiring simpler. Of course, for convenience, power is connected between breadboards too, however each breadboard can be powered independently from a suitable 5V source.

schematic 1
circuit 1


It's unlikely that you'll want just a counter up or down, without any hardware control. For this reason, we have created a control interface also (note, this hardware is only used in the countdown and 24hr clock sketches - the simple counter sketch has no hardware interfacing provisions, however you can experiment with your own modifications to the code).

Using a switch with your Arduino is simple, right? Well, yes and no. The thing with switches is they ‘bounce’. That is they make contact then spring open again, make contact again etc for several random cycles. You and I wouldn’t notice this as it occurs over a few milliseconds, but a device like the Arduino will see all of the indivual bounces. So to fix this we’ve implemented "switch debounce" circuits on each of the 5 switches. It’s just 2 resistors and a capacitor. It is possible to do this in the software but we’re trying to keep the clock accurate so we’re not going down that route.

Parts Required (Per SWITCH)JaycarAltronics
1 x Tactile Switch SP0608 S1120
1 x 0.1µF Capacitor RG5125 R2736B
1 x 100kΩ Resistor RR0620 R7070
1 x 10kΩ Resistor RR0596 R7058

You can see from the diagram below how the tactile switch is integrated with the debounce circuit. Each switch "module" is identical (much like our display modules), so the same basic circuit is simply replicated for the number of control switches we need (as long as your Arduino can support the IO of course).

schematic 2
circuit 2

We’re using 5 for this project. Depending on the sketch you're using, each of the 5 switches has a dedicated purpose. The button functions are from left to right:

MODE: Cycles the current time unit being set from hours to minutes to seconds and back to hours with each press.
UP: Increment the current time unit; hours, minutes or seconds.
DOWN: Decrement the current time unit; hours, minutes or seconds.
START: Starts the clock. You can’t set the hours, minutes or seconds while the clock is running.
STOP: Stops the clock to allow you to set the hours, minutes or seconds.


There are three example sketches you can load and experiment with. You'll only need an UNO for these sketches, but will work on any Arduino compatible board with enough GPIO to support the hardware interface (if required). All sketches are included in the resources downloads.

COUNT UP SEQUENCE: A simple 0 - 999999 second increment counter. It doesn't work to hours and minutes, simply 1-million increments (speed adjustable in the sketch), with 0-9 on each display. Load count_up_v1.ino

COUNT DOWN TIMER: A reliable count-down timer. Defaults to one hour with start-time, however you can change the default time. Hardware interface provides setting of the start time too, as well as stop / start functionality. Load count_down_v1.ino.

24HR CLOCK: This is just as it sounds, with a 24hr time representation. The time is set using the hardware interface. The default time could use a Real Time Clock module, but we haven't worried about it here as we're not expecting regular restarting of the hardware either. Load 24hr_clock_v1_ino.


It's worth noting that with all this pushing and pulling of data going on, it's easy for time to drift a little. Perhaps due to software delay, processing time, or some other random cause. For this reason, we have an internal process to recover any time lost.

We simply keep track of the time that has passed since the Arduino booted. It is entirely possible (even probable), that there's a few milliseconds of processing time for each second of time past. Data, after all, happens on to a clock, and each command, no matter how small, must take some time on that clock.

  currentMillis = millis();
  diff = currentMillis - prevMillis;
       // We've delayed around 900ms, but maybe
       // 1-3 more or less. Adjust for this.
  diff -= 1000;
  diff = 100 - diff;
  if (diff < 0) 
// Delays drifted low. They normally drift high.
    diff = 100;
    Serial.println("Diff was negative");
        // For debug or for your interest
  prevMillis = currentMillis;

We have internal delays of 900ms within the code. This allows us up to 100ms of "adjustable delay" to wait for the next whole second to come around. This is FAR more accurate than simple having a 1-second full delay at a single point in our code.

Therefore, if it has taken us 903 miliseconds to get around to incrementing another second , we can counteract this and simply wait 97 milliseconds, instead of a full 100. This helps eliminate time drift that you may experience over long periods.

Of course, it's not going to be keeping time for the Olympics or anything, so this is probably of little consequence. However we thought it was prudent to check it all out to be sure.

We perform this adjustment in both the count down timer, and 24hr clock circuits. The count up sequence isn't keeping specific time anyway, so there's no reason for any further adjustment.


Each of the individual segments in a 7 segment display has a letter assigned to it, A to G. Refer to the diagram on the previous page. The shift register IC has 8 output pins that can drive LEDs, We don’t use the decimal point so we need only consider 7 outputs. If we sent the number 1 to the shift register we’d have the A segment lit. If we sent 2 we’d have the B segment lit. This is fine for binary but we want to display decimal numbers. Consider that if we want to display the digit 2 we need to illuminate segments A, B, G, D, E. This means we need to translate the decimal number into another value to light the relevent segments.

The sketch uses an array to do this. An array is a related collection of variables. They could be chars (a Z), strings (“hello, world!”) or numbers. Our array looks like this:

int aDecValues[] = { 63, 6, 91, 79, 102, 109, 125, 7, 127, 103 };

Each element of the array represents the sum of the binary values needed to light the necessary segments to show the decimal number. Consider the 2nd element with a value of 6. This is the sum of 2+4. This lights the B and C segments, hence number 1 is shown of the display. The 1st element is the sum of 1 + 2 + 4 + 8 + 16 + 32. This turns on segments A, B, C, D, E and F. That is all the segments necessary to show 0 on the 7 segment display.

So far, so good, but how do we display 67? Well, that requires 2 display modules. When the shift register is ‘full’, it signals this via what is effectively an overflow pin (pin 9 on the IC). We connect the first digit overflow pin to the next digits ‘data in’ pin (pin 14 on the IC). Now we have 2 modules in series and can display 00 to 99. To allow display of 00 00 00 to 99 99 99 we use 6 modules. For this project we want to display up to 23 59 59.


mega digit

Now we have our clock systems working, our hardware controls functioning, and we're happy overall with performance, we can start to make things interesting.

What's great about the shift register IC is that it gives us full control over display outputs. This makes it very simple to use some transistors, and scale-up the hardware to drive MUCH bigger displays.

Of course, we don't have to be displaying time... you could make a ticket counter, a door-entry counter, pretty much anything that uses numbers. 7 segment displays can show letters too, but their clarity is limited and they're really better suited to numbers.

In order to achieve all of this, we'll create a custom PCB to hold all components. You can see from the images on this page that we've created a prototype, and it works very well. But it's merely that, a prototype.

Sure, there are large 7-segment displays around, but nothing quite like this. Our goal is to create a fully modularised circuit that can drive a large 12V LED strip. While we're still finalising the details, we should be able to accept a 12V supply, since the power demands for the LED strip are far greater than the other components.

We'll take 5V from that to power the logic side of things. The PCBs will be modular so the same overall module can be used for a time display, scoreboard, or simple two-digit number counter.

In the meantime, play, experiment, get familiar, and you'll be ready to tackle part 2 next month!