Want an Arduino digital clock using a seven-segment as display? Find tips on how to construct one here.
Introduction
Previously, you’ve learned how to create an Arduino clock with an OLED as a display using an Arduino UNO proto shield. This time, you’ll make an Arduino clock using a seven-segment display. Since this project may require space and pins, it will be constructed on an Arduino Mega proto shield.
You can browse through these seven-segment display resources to refresh your memories:
Seven Segment Digital Clock Setup
A seven-segment display can be hooked up easily to your Arduino. Below is an image and schematic where a mini breadboard is placed on top of an Arduino MEGA protoshield. The 4-digit seven-segment is connected to the breadboard, a bunch of resistors, and then to the Arduino MEGA ports. Along with this, an RTC module (DS1302) is connected to the I2C interface of the MEGA. The RTC is in charge of time-keeping functions.
To make the circuit permanent, you can solder it on the proto shield. You can optionally add a buzzer or switches and make your custom functions for alarm and time adjustment. Here, the DS1302 chip was used stand-alone (not in a module) along with a 32kHz crystal and a battery holder underneath. You can find more in-depth details on working with the DS1302 RTC chip in Create a Simple Arduino Alarm Clock.
Firmware
Below is the firmware for displaying basic time on a seven-segment display using an Arduino MEGA. Note that this code uses the RTClib.h library (for the DS1302 chip). You can vary the ports depending on your setup.
#include
RTC_DS1307 rtc;
byte toggle_DP = 0;
// OPTION
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
#define dot_time 1000
// Arduino MEGA
// All pins of the Seven Segment Display defined here
#define Pin1_E A2 // A0 UNO
#define Pin2_D A1 //PD7 UNO
#define Pin3_DP A0 //PD5 UNO
#define Pin4_C A3 // A2 UNO
#define Pin5_G A4 //PD2 //PB5 UNO
#define Pin6_D4 A5 //PD6 UNO
#define Pin7_B 2 // PD3 //PB4 UNO
#define Pin8_D3 3 // PD4 UNO
#define Pin9_D2 4 // PD1 UNO
#define Pin10_F 5 // A1 UNO
#define Pin11_A 6 // A3 UNO
#define Pin12_D1 7 // PD0 UNO
// Bit Digit Position Pins
#define Dig1 Pin12_D1
#define Dig2 Pin9_D2
#define Dig3 Pin8_D3
#define Dig4 Pin6_D4
// Segment Pins (Alphabet)
#define SegA Pin11_A
#define SegB Pin7_B
#define SegC Pin4_C
#define SegD Pin2_D
#define SegE Pin1_E
#define SegF Pin10_F
#define SegG Pin5_G
#define SegCL Pin3_DP
// OPTIONAL
// Buzzer
#define Buzzer 10
// Switches
#define Sel_SW 13
#define Hr_SW 12
#define Min_SW 11
unsigned long previousMillis = 0; // Stores the last time an action was performed
void display_digit(byte digit, byte segment) {
// turn on the supply of the chosen segment
switch (segment){
case 0:
digitalWrite(Dig1, 0);
digitalWrite(Dig2, 0);
digitalWrite(Dig3, 0);
digitalWrite(Dig4, 0);
break;
case 1:
digitalWrite(Dig1, 1);
digitalWrite(Dig2, 0);
digitalWrite(Dig3, 0);
digitalWrite(Dig4, 0);
break;
case 2:
digitalWrite(Dig1, 0);
digitalWrite(Dig2, 1);
digitalWrite(Dig3, 0);
digitalWrite(Dig4, 0);
break;
case 3:
digitalWrite(Dig1, 0);
digitalWrite(Dig2, 0);
digitalWrite(Dig3, 1);
digitalWrite(Dig4, 0);
break;
case 4:
digitalWrite(Dig1, 0);
digitalWrite(Dig2, 0);
digitalWrite(Dig3, 0);
digitalWrite(Dig4, 1);
break;
default:
break;
}
// switch on the digit of that segment
switch (digit) {
case 0:
// Display 0
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegE, 0);
digitalWrite(SegF, 0);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 1);
break;
case 1:
// Display 1
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegA, 1);
digitalWrite(SegD, 1);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 1);
break;
case 2:
// Display 2
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegG, 0);
digitalWrite(SegE, 0);
digitalWrite(SegD, 0);
digitalWrite(SegC, 1);
digitalWrite(SegF, 1);
digitalWrite(SegCL, 1);
break;
case 3:
// Display 3
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegG, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegCL, 1);
break;
case 4:
// Display 4
digitalWrite(SegF, 0);
digitalWrite(SegB, 0);
digitalWrite(SegG, 0);
digitalWrite(SegC, 0);
digitalWrite(SegA, 1);
digitalWrite(SegE, 1);
digitalWrite(SegD, 1);
digitalWrite(SegCL, 1);
break;
case 5:
// Display 1
digitalWrite(SegA, 0);
digitalWrite(SegF, 0);
digitalWrite(SegG, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegB, 1);
digitalWrite(SegE, 1);
digitalWrite(SegCL, 1);
break;
case 6:
// Display 1
digitalWrite(SegA, 0);
digitalWrite(SegF, 0);
digitalWrite(SegE, 0);
digitalWrite(SegD, 0);
digitalWrite(SegC, 0);
digitalWrite(SegG, 0);
digitalWrite(SegB, 1);
digitalWrite(SegCL, 1);
break;
case 7:
// Display 7
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 1);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 1);
break;
case 8:
// Display 8
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegE, 0);
digitalWrite(SegF, 0);
digitalWrite(SegG, 0);
digitalWrite(SegCL, 1);
break;
case 9:
// Display 9
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegE, 1);
digitalWrite(SegF, 0);
digitalWrite(SegG, 0);
digitalWrite(SegCL, 1);
break;
}
}
void display_dot(byte dot)
{
digitalWrite(Dig2, 1);
switch (dot){
case 1:
digitalWrite(SegA, 1);
digitalWrite(SegB, 1);
digitalWrite(SegC, 1);
digitalWrite(SegD, 1);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 0);
break;
case 0:
digitalWrite(SegA, 1);
digitalWrite(SegB, 1);
digitalWrite(SegC, 1);
digitalWrite(SegD, 1);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 1);
break;
default:
break;
}
}
void setup() {
// put your setup code here, to run once:
// Start and Check RTC
if(!rtc.begin()){
while(1);
}
// automatically sets the RTC to the date & time on PC this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// Comment out below line once you set the date & time.
// Following line sets the RTC with an explicit date & time
// for example to set January 13 2022 at 12:56 you would call:
// rtc.set(second(), minute(), hour(), weekday(), day(), month(), year());
// rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
// set day of week (1=Sunday, 7=Saturday)
// Set initial pin ports
// Seven Segment
pinMode(Dig1, OUTPUT);
pinMode(Dig2, OUTPUT);
pinMode(Dig3, OUTPUT);
pinMode(Dig4, OUTPUT);
pinMode(SegA, OUTPUT);
pinMode(SegB, OUTPUT);
pinMode(SegC, OUTPUT);
pinMode(SegD, OUTPUT);
pinMode(SegE, OUTPUT);
pinMode(SegF, OUTPUT);
pinMode(SegG, OUTPUT);
pinMode(SegCL, OUTPUT);
// OPTIONAL
// pinMode(Buzzer, OUTPUT);
// pinMode(Sel_SW, INPUT_PULLUP);
// pinMode(Hr_SW, INPUT_PULLUP);
// pinMode(Min_SW, INPUT_PULLUP);
}
void loop() {
// put your main code here, to run repeatedly:
unsigned long currentMillis = millis();
DateTime now = rtc.now();
// Display clock by lighting up each digit place with a short delay at a time
// since each pins of the segments are shared between the digit places
// Display Hour
display_digit(now.hour()/10, 1);
delay(3);
display_digit(now.hour()%10, 2);
delay(3);
// Display Minutes
display_digit(now.minute()/10, 3);
delay(3);
display_digit(now.minute()%10, 4);
delay(3);
// Blinking Dot
if((currentMillis - previousMillis) > dot_time){
toggle_DP ^= 1;
previousMillis = millis();
}
display_dot(toggle_DP);
delay(3);
}
All the seven-segment pins to Arduino ports are defined below. Additionally, you’ll also see the digit power pins supplied by another series of Arduino ports. Lastly, the alphabetized segments are mapped to their corresponding port pins (for simplicity).
// Arduino MEGA
// All pins of the Seven Segment Display defined here
#define Pin1_E A2 // A0 UNO
#define Pin2_D A1 //PD7 UNO
#define Pin3_DP A0 //PD5 UNO
#define Pin4_C A3 // A2 UNO
#define Pin5_G A4 //PD2 //PB5 UNO
#define Pin6_D4 A5 //PD6 UNO
#define Pin7_B 2 // PD3 //PB4 UNO
#define Pin8_D3 3 // PD4 UNO
#define Pin9_D2 4 // PD1 UNO
#define Pin10_F 5 // A1 UNO
#define Pin11_A 6 // A3 UNO
#define Pin12_D1 7 // PD0 UNO
// Bit Digit Position Pins
#define Dig1 Pin12_D1
#define Dig2 Pin9_D2
#define Dig3 Pin8_D3
#define Dig4 Pin6_D4
// Segment Pins (Alphabet)
#define SegA Pin11_A
#define SegB Pin7_B
#define SegC Pin4_C
#define SegD Pin2_D
#define SegE Pin1_E
#define SegF Pin10_F
#define SegG Pin5_G
#define SegCL Pin3_DP
The function for displaying digits 0-9 is display_digit(), and its parameters are the digit itself and which segment is to be powered (digit 1 – 4). Note that the orientation of the seven segments is common anode for this code to work correctly. You’ll just need to reverse the high and low values to make the code compatible to common cathode.
void display_digit(byte digit, byte segment) {
// turn on the supply of the chosen segment
switch (segment){
case 0:
digitalWrite(Dig1, 0);
digitalWrite(Dig2, 0);
digitalWrite(Dig3, 0);
digitalWrite(Dig4, 0);
break;
case 1:
digitalWrite(Dig1, 1);
digitalWrite(Dig2, 0);
digitalWrite(Dig3, 0);
digitalWrite(Dig4, 0);
break;
case 2:
digitalWrite(Dig1, 0);
digitalWrite(Dig2, 1);
digitalWrite(Dig3, 0);
digitalWrite(Dig4, 0);
break;
case 3:
digitalWrite(Dig1, 0);
digitalWrite(Dig2, 0);
digitalWrite(Dig3, 1);
digitalWrite(Dig4, 0);
break;
case 4:
digitalWrite(Dig1, 0);
digitalWrite(Dig2, 0);
digitalWrite(Dig3, 0);
digitalWrite(Dig4, 1);
break;
default:
break;
}
// switch on the digit of that segment
switch (digit) {
case 0:
// Display 0
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegE, 0);
digitalWrite(SegF, 0);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 1);
break;
case 1:
// Display 1
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegA, 1);
digitalWrite(SegD, 1);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 1);
break;
case 2:
// Display 2
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegG, 0);
digitalWrite(SegE, 0);
digitalWrite(SegD, 0);
digitalWrite(SegC, 1);
digitalWrite(SegF, 1);
digitalWrite(SegCL, 1);
break;
case 3:
// Display 3
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegG, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegCL, 1);
break;
case 4:
// Display 4
digitalWrite(SegF, 0);
digitalWrite(SegB, 0);
digitalWrite(SegG, 0);
digitalWrite(SegC, 0);
digitalWrite(SegA, 1);
digitalWrite(SegE, 1);
digitalWrite(SegD, 1);
digitalWrite(SegCL, 1);
break;
case 5:
// Display 1
digitalWrite(SegA, 0);
digitalWrite(SegF, 0);
digitalWrite(SegG, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegB, 1);
digitalWrite(SegE, 1);
digitalWrite(SegCL, 1);
break;
case 6:
// Display 1
digitalWrite(SegA, 0);
digitalWrite(SegF, 0);
digitalWrite(SegE, 0);
digitalWrite(SegD, 0);
digitalWrite(SegC, 0);
digitalWrite(SegG, 0);
digitalWrite(SegB, 1);
digitalWrite(SegCL, 1);
break;
case 7:
// Display 7
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 1);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 1);
break;
case 8:
// Display 8
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegE, 0);
digitalWrite(SegF, 0);
digitalWrite(SegG, 0);
digitalWrite(SegCL, 1);
break;
case 9:
// Display 9
digitalWrite(SegA, 0);
digitalWrite(SegB, 0);
digitalWrite(SegC, 0);
digitalWrite(SegD, 0);
digitalWrite(SegE, 1);
digitalWrite(SegF, 0);
digitalWrite(SegG, 0);
digitalWrite(SegCL, 1);
break;
}
}
Another function is the display_dot() that simply toggles the dot character depending on the dot parameter value.
void display_dot(byte dot)
{
digitalWrite(Dig2, 1);
switch (dot){
case 1:
digitalWrite(SegA, 1);
digitalWrite(SegB, 1);
digitalWrite(SegC, 1);
digitalWrite(SegD, 1);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 0);
break;
case 0:
digitalWrite(SegA, 1);
digitalWrite(SegB, 1);
digitalWrite(SegC, 1);
digitalWrite(SegD, 1);
digitalWrite(SegE, 1);
digitalWrite(SegF, 1);
digitalWrite(SegG, 1);
digitalWrite(SegCL, 1);
break;
default:
break;
}
}
The setup code initializes the RTC and adjusts its value based on compile time. Next, all seven-segment Arduino ports are configured as digital outputs.
void setup() {
// put your setup code here, to run once:
// Start and Check RTC
if(!rtc.begin()){
while(1);
}
// automatically sets the RTC to the date & time on PC this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// Comment out below line once you set the date & time.
// Following line sets the RTC with an explicit date & time
// for example to set January 13 2022 at 12:56 you would call:
// rtc.set(second(), minute(), hour(), weekday(), day(), month(), year());
// rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
// set day of week (1=Sunday, 7=Saturday)
// Set initial pin ports
// Seven Segment
pinMode(Dig1, OUTPUT);
pinMode(Dig2, OUTPUT);
pinMode(Dig3, OUTPUT);
pinMode(Dig4, OUTPUT);
pinMode(SegA, OUTPUT);
pinMode(SegB, OUTPUT);
pinMode(SegC, OUTPUT);
pinMode(SegD, OUTPUT);
pinMode(SegE, OUTPUT);
pinMode(SegF, OUTPUT);
pinMode(SegG, OUTPUT);
pinMode(SegCL, OUTPUT);
// OPTIONAL
// pinMode(Buzzer, OUTPUT);
// pinMode(Sel_SW, INPUT_PULLUP);
// pinMode(Hr_SW, INPUT_PULLUP);
// pinMode(Min_SW, INPUT_PULLUP);
}
The loop code consists of displaying each seven-segment digit with the hour and minute values obtained through the RTC functions. Note that there is a delay on every display of a digit so that you’ll be able to see that digit before transitioning to display the next digit. The reason for this procedure is that each segment pins (A-G) are shared among the digit positions to save pin count. Lastly, the blinking dot function is executed through a millis() timer and a toggle_DP variable.
void loop() {
// put your main code here, to run repeatedly:
unsigned long currentMillis = millis();
DateTime now = rtc.now();
// Display clock by lighting up each digit place with a short delay at a time
// since each pins of the segments are shared between the digit places
// Display Hour
display_digit(now.hour()/10, 1);
delay(3);
display_digit(now.hour()%10, 2);
delay(3);
// Display Minutes
display_digit(now.minute()/10, 3);
delay(3);
display_digit(now.minute()%10, 4);
delay(3);
// Blinking Dot
if((currentMillis - previousMillis) > dot_time){
toggle_DP ^= 1;
previousMillis = millis();
}
display_dot(toggle_DP);
delay(3);
}
Actual Run
(on bread board)
(soldered on the proto shield)
SHOP THIS PROJECT
-
Digital LCD Thermometer Temperature Gauge with Probe
$15.95Original price was: $15.95.$14.95Current price is: $14.95. Add to cart