Last Updated: August 20, 2021
Originally Published: February 15, 2019
Skill Level: Intermediate
Table Of Contents
- Introduction
- What Is Needed
- Background Information
- Building The Circuit
- Writing The Sketch
- Running And Testing The System
- Summary
Introduction
This tutorial will teach you how to interface a 7-segment display to an Arduino Uno.
A basic understanding of electronics and programming is expected along with some familiarity with the Arduino platform. If you are new to the Arduino platform or would just like to refresh your knowledge, please see our Blink: Making An LED Blink On An Arduino Uno tutorial before proceeding with this one.
This tutorial will use a solderless breadboard to build a circuit from a schematic diagram. The All About Circuit’s Understanding Schematics, SparkFun’s How to Read a Schematic, Core Electronics’ How to Use Breadboards, and Science Buddies’ How to Use a Breadboard guides are good resources for learning how to translate a schematic to a breadboard.
The resources created for this tutorial are available on GitHub for your reference.
What Is Needed
- Linux, macOS, Or Windows Based Computer With A USB Port
- Arduino IDE
- Arduino Uno (R3 available on Arduino and SparkFun, WiFi Rev2 available on Arduino and SparkFun) With Compatible USB Cable
- Solderless Breadboard (available on Adafruit and SparkFun)
- Preformed Breadboard Jumper Wire Kit (available on SparkFun and CanaKit)
- 7 x Male-Male Jumper Wires (available on Adafruit and Arrow)
- 74LS47 BCD To 7-Segment Decoder/Driver Integrated Circuit (available on Arrow and Digi-Key)
- 7-Segment Display (available on SparkFun and Digi-Key)
- Momentary Push Button (available on Adafruit and SparkFun)
- 7 x 330 Ω Resistors (available on SparkFun and Amazon)
Background Information
I am using the Arduino Uno WiFi Rev2 development board connected to a macOS based computer with the desktop Arduino IDE. If you are using a different Arduino board or computer setup, the vast majority of this tutorial should still apply, however, some minor changes may be necessary.
In this tutorial, I will be connecting a common anode 7-segment display to an Arduino through a 74LS47 BCD To 7-Segment Decoder/Driver integrated circuit (IC). This chip decodes binary coded decimal (BCD), which is just basic binary numbers for the 0-9 decimal digits, into the individual LED segments of a 7-segment display. The 4 BCD inputs of the chip are denoted as A through D, while the individual LED segment outputs are denoted as a through g. See the 74LS47 datasheet for more information. While usage of the IC is not strictly necessary, it does allow us to use fewer Arduino GPIO pins and write a simpler program. If you prefer to use a common cathode display instead, replace the 74LS47 decoder IC with a 74LS48 chip and make sure to connect the common terminals of the display to ground instead of power.
If you need assistance with your particular setup, post a question in the comments section below and I, or someone else, can try to help you.
Building The Circuit
Before connecting any circuitry to your Arduino board, disconnect it from power and your computer. This avoids accidental damage during wiring.
Place the components and wire up the circuit on a breadboard according to the schematic diagram shown below.
I left the LT, BI, and RBI inputs of the 74LS47 IC disconnected as we will not be utilizing those testing and blanking features.
A 0.1 µF bypass capacitor was placed across the power pins of the 74LS47 IC in order to reduce any power supply noise that may be present in the system.
Note, you may come across other 7-segment display circuits using only one resistor at the common terminal(s), but using resistors across all the segments, as done here, ensures a constant level of brightness regardless of how many segments are lit.
The circuit should look similar to the one shown below once completed. Note, I used a two digit display (that I had available) in my circuit, but I only connected one digit.
Once the circuit is built, connect your Arduino to your computer with the USB cable.
Writing The Sketch
Open the Arduino IDE and create a new sketch named BCD7SegmentDisplay with the code shown below.
const uint8_t Button = 2; const uint8_t BCD_A = 3; const uint8_t BCD_B = 4; const uint8_t BCD_C = 5; const uint8_t BCD_D = 6; const unsigned long DisplayPeriod = 1000; void setup() { pinMode(Button, INPUT_PULLUP); pinMode(BCD_A, OUTPUT); pinMode(BCD_B, OUTPUT); pinMode(BCD_C, OUTPUT); pinMode(BCD_D, OUTPUT); } void loop() { static uint8_t count = 0; // display count static unsigned long previousDisplayTime = 0; unsigned long currentTime = millis(); if (digitalRead(Button) == LOW) count = 0; // reset count if button pressed if (currentTime - previousDisplayTime >= DisplayPeriod) { // check if time to update display displayWrite(count); // update display count++; // increase counter if (count == 10) count = 0; // reset to 0 if count exceeds 9 previousDisplayTime = currentTime; } } void displayWrite(uint8_t value) { digitalWrite(BCD_A, bitRead(value, 0)); // BCD LSB digitalWrite(BCD_B, bitRead(value, 1)); digitalWrite(BCD_C, bitRead(value, 2)); digitalWrite(BCD_D, bitRead(value, 3)); // BCD MSB }
Let’s take a look at some of the more interesting parts of the code.
The BCD_A
through BCD_D
pins, defined on lines 2-5, represent the A through D BCD inputs of the 74LS47 chip, which itself subsequently drives the a through g segment inputs of the 7-segment display.
The DisplayPeriod
, defined on line 7, sets the time between display updates in milliseconds. The value of 1000
means the display will be updated every second.
The pin mode of the button, defined on line 10, is specified as INPUT_PULLUP
, which uses the internal pull-up resistor for the pin within the microprocessor on the Arduino board, instead of just INPUT
since we did not use an external pull-up resistor in the circuit.
The loop()
routine performs a variety of operations:
- It defines and keeps track of the
count
that is displayed on the 7-segment display and resets it back to 0 when the next value to be displayed reaches double digits. - Checks if the reset button was pressed, and if so, resets the counter.
- Keeps track of the time when the display needs to be updated according the specified display period and calls the
displayWrite()
function when the display is ready to be updated.
The displayWrite()
function utilizes the Arduino bitRead()
function to write the appropriate binary coded decimal (BCD) values to the 74LS47 chip that then translates those values to drive the appropriate LED segments of the display. Speaking of bitRead()
, this function just translates a number into its individual binary bits. For example bitRead(5, 0)
will return 1 since the least significant bit in the number 5, 00000101 in binary, is 1. Likewise, bitRead(5, 1)
will return 0.
If there is something that needs further explanation, please let me know in the comment section and I will try to answer your question.
Running And Testing The System
Now that our circuit is built and our software is written, it is time to run and test our display project.
Upload (Sketch > Upload) the sketch to the board and you should see the 7-segment display counting up from 0. When it reaches 9, it should reset back to 0. Press the button on the breadboard at any time and the display should reset back to 0 during the next display update cycle.
Before we end, now would be a good time to upload the BareMinimum sketch (Main Menu > File > Examples > 01.Basics > BareMinimum) to reset all pins back to their default states. This ensures no outputs are being driven when plugging in your board for your next project.
Summary
In this tutorial, we learned how to interface a common anode 7-segment display to an Arduino Uno using a 74LS47 BCD To 7-Segment Decoder/Driver integrated circuit.
The final source code and schematic used for this tutorial is located on GitHub.
Thank you for joining me along this journey and I hope you enjoyed the experience. Please feel free to share your thoughts in the comments section below.
Hello John,
This is one of the most recent posts I’ve stumbled across searching for information. At the beginning of the tutorial you stated to contact you if we were using a different set up. Which I am, and could use some assistance.
First, (for some background) I’m currently attending the University of Advancing Technology for a BS in robotics and embedded systems. The current course I’m in the professor has given a choice in projects to reflect concepts in RSA. I’ve chosen to create a single digit 7 segment Arduino clock. The project doesn’t necessarily have to work, but I would like to turn in a fully functional product if possible. I currently have around 10 days to complete this project so hopefully this reaches you fairly quickly.
I’m using a Arduino Uno REV3, with a Adafruit Datalogger/RTC shield. The shield is using a PCF8523 RTC IC, and I’m attempting to get the time from the RTC to the seven segment via a 74LS48N decoder IC. Another difference here is that I am running a common cathode 7 seg.
I’ve inspected your code example but I’m having a hard time applying it to my use case. I’d be more than happy to supply a diagram if need be if you would be willing to assist. I just need someone to point me in the right direction here. I have some code written, but it’s only running a count up, and it’s certainly not very readable at the moment.
Sure, I can try to help. Where are you getting stuck? I would suggest that you first get the base display circuit and code working before attaching the shield, then we can see what changes are necessary once the shield is attached.
I’ll have to remove the shield to proceed, but I’m just unclear as to 1.) which outputs on the Arduino I need to utilize, and 2.) how the code would be constructed to retrieve the Hours and Minutes and send it to the seven segment. Currently, the code I have sends the information through the serial via the serial monitor in the IDE. I do have all the components functioning from my initial assessment, but I’m just not getting the proper output at the seven seg. Initially, I attempted to send directly to the seven seg via binary on digital pins 2-9 for a count-up. Which was successful. But I recently understood that I would need a BCD decoder in the circuit to get the time from the RTC as the PCF8523 sends out all code in BCD format. This is where I’m having difficulty as I’m unsure of the written code I would need to accomplish this. At the same time I reached out to you I also posted the issue in Quora and have had some given answers that I will explore this evening. But certainly I do appreciate the response and any assistance you could provide. Cheers~ J. Rusch
I sounds like you are having less difficulty with the content of this tutorial and more difficulty with interfacing the Adafruit Datalogger/RTC shield to your Arduino. I do not have any experience with this shield. Have you checked out the Adafruit Data Logger Shield learning guide? It provides library and code examples for accessing the RTC. Also, how are you trying to display the clock data on a single 7-segment digit as most clock values would require two digits?
That’s likely the case. Yes, I have looked at that guide and unfortunately it isn’t very much help to me. And that is something I may have failed to mention. What I want to do is display one digit at a time. My intended configuration I want to use an RGB LED output to 4 different colors. The color of the LED will indicate the place of the digit on the seven seg. So format would be HH:MM. For example, Magenta = 1st digit hour, Green = 2nd digit hour, Red= 1st digit minute, etc. I’m not concerning myself with seconds in this project, although if I can get the format right it’d be nice to use the DP output to show a seconds indicator.
If you are using the libraries mentioned in the Adafruit guide, you should be able to get the hour and minute values (in integers), break out the individual digits, and then send them to the 7-segment display. For instance the A pin for minutes would be
int digit_10s = minutes / 10; // get 10s digit for minutes
int digit_1s = minutes % 10; // get 1s digit for minutes
digitalWrite(bcdA, bitRead(digit_10s, 0));
// some time later
digitalWrite(bcdA, bitRead(digit_1s, 0));
Is this what you are looking for?
Its certainly a step in the right direction, I will try to implement and see if I can get some results. Thanks a ton, l know its difficult to try and help with such limited information, I really wish I had more time with this. But as I stated, its not a requirement that the project is functional. Its more about the process itself.
So, I attempted a quick experimental sketch. I tried to make some modifications for this specific case. But I’m getting errors.
#include
void setup() {
// Pin mapping _setup code here, to run once:
const byte bcdA = 2; //LSB
const byte bcdB = 3;
const byte bcdC = 4;
const byte bcdD = 5; //MSB
// Pin configuration
pinMode(bcdA, OUTPUT);
pinMode(bcdB, OUTPUT);
pinMode(bcdC, OUTPUT);
pinMode(bcdD, OUTPUT);
RTC_PCF8523 rtc;
DateTime now = rtc.now();
int digit_10s = (now.minute() /10); //will get the 10s place for digit:mintue
int digit_1s = (now.minute() % 10); //will get the 1s place for digit:minute
}
void loop() {
//main code here, to run repeatedly:
digitalWrite(bcdA, (bitRead(digit_10s, 0)));
delay (1000);
digitalWrite(bcdA, (bitRead(digit_1s, 0)));
delay (1000);
}
/////////////////////////
I get the following error when compiling:
variable or field “loop” declared void
exit status 1
I see a few issues with your code.
Without knowing your exact setup, the following appears to me to be what you are looking for.
Greetings John,
I made numerous modifications to the code. My results are in the right direction, but I’m only getting an 8 digit, and a 5 digit on the display. The sequence appears to be working, it’s just the output isn’t correct.
Below is the current code:
#include “RTClib.h”
// Pin mapping _setup code here, to run once:
const byte bcdA = 2; //LSB
const byte bcdB = 3;
const byte bcdC = 4;
const byte bcdD = 5; //MSB
const int red = 7;
const int blue = 8;
const int green = 9;
RTC_PCF8523 rtc;
// Pin configuration
void setup() {
pinMode(red, OUTPUT);
pinMode(green, OUTPUT);
pinMode(blue, OUTPUT);
pinMode(bcdA, OUTPUT);
pinMode(bcdB, OUTPUT);
pinMode(bcdC, OUTPUT);
pinMode(bcdD, OUTPUT);
}
void loop() {
DateTime now = rtc.now();
int digit_hourFirstplc =(now.hour()/10); //get 10s place for hours
int digit_hourSecondplc =(now.hour()%10); //get 1s place for hours
int digit_minuteFirstplc = (now.minute()/10); //will get the 10s place for digit:minute
int digit_minuteSecondplc = (now.minute()% 10); //will get the 1s place for digit:minute
digitalWrite(red, HIGH);//lights red
digitalWrite(blue, LOW);
digitalWrite(green, LOW);
digitalWrite(bcdA, (bitRead(digit_hourFirstplc, 0)));
digitalWrite(bcdB, (bitRead(digit_hourFirstplc, 1)));
digitalWrite(bcdC, (bitRead(digit_hourFirstplc, 2)));
digitalWrite(bcdD, (bitRead(digit_hourFirstplc, 3)));
delay (2000);
digitalWrite(red, HIGH);//lights magenta
digitalWrite(blue, LOW);
digitalWrite(green, HIGH);
digitalWrite(bcdA, (bitRead(digit_hourSecondplc, 0)));
digitalWrite(bcdB, (bitRead(digit_hourSecondplc, 1)));
digitalWrite(bcdC, (bitRead(digit_hourSecondplc, 2)));
digitalWrite(bcdD, (bitRead(digit_hourSecondplc, 3)));
delay (2000);
digitalWrite(red, LOW);//lights blue
digitalWrite(blue, LOW);
digitalWrite(green, HIGH);
digitalWrite(bcdA, (bitRead(digit_minuteFirstplc, 0)));
digitalWrite(bcdB, (bitRead(digit_minuteFirstplc, 1)));
digitalWrite(bcdC, (bitRead(digit_minuteFirstplc, 2)));
digitalWrite(bcdD, (bitRead(digit_minuteFirstplc, 3)));
delay (2000);
digitalWrite(red, LOW);//lights green
digitalWrite(blue, HIGH);
digitalWrite(green, LOW);
digitalWrite(bcdA, (bitRead(digit_minuteSecondplc, 0)));
digitalWrite(bcdB, (bitRead(digit_minuteSecondplc, 1)));
digitalWrite(bcdC, (bitRead(digit_minuteSecondplc, 2)));
digitalWrite(bcdD, (bitRead(digit_minuteSecondplc, 3)));
delay (2000);
}
The code looks okay to me. If you have not done so already, I would suggest verifying the digit_hour… and digit_minute… values by printing them to the Serial Monitor. If that looks good, verify your decoder/display circuit and A/B/C/D pin connections. You were able to get the original tutorial sketch working (counting) without any issues, right?
I was able to get the counter working except for the number 6 wasn’t displaying properly, I never determined why. I’ll review everything once again and see if there is something amiss. When you state, “I would suggest verifying the digit_hour… and digit_minute… values by printing them to the Serial Monitor”…meaning, just send outputs to serial instead of digitalWrite?
Correct.
Add the following two lines somewhere in your
setup()
function.Then add something like
Serial.print("First place digit of hour: "); Serial.println(digit_HourFirstplc);
within theloop()
function after you define the digit variables. Open the Serial Monitor window (Main Menu > Tools > Serial Monitor) and then upload the sketch. You should see the value of the digit_HourFirstplc variable being printed in the Serial Monitor.Happy Days John!!!!!!
Got a break through last night after playing with it for awhile. It appears this shield is finicky. I had to re-flash the RTC to get the time closer to current. It’s still about 5 minutes off, but I can live with it. Additionally, the Adafruit shield doesn’t account for daylight savings . So re-flashing it, I was able to get more accurate. I implemented the code from your last message and see the serial output now along with the functioning display. It’s in 24 hour format, but working like a clock (pun intended)! I can’t thank you enough for your help and appreciate the patience you’ve shown. If there is anything I can do to help you I’d be more than happy to assist. Thanks a million!!
You are very welcome and I am glad to hear it is now working for you! Thank you for reading my articles!