For this project, we will be explaining how to setup a simple multi-digit seven-segment LED display (SSD or 7SD) and then making a simple counter that will display the time after the board is turned on. Seven-segment displays are used in most digital displays to show numerical digits.
Qty | Description | Typical Image | Schematic Symbol | Breadboard Image |
---|---|---|---|---|
1 | Four Digit seven-segment Display | ![]() |
||
4 | 220Ω Resistors | ![]() |
||
A seven-segment LED display is an array of seven (or sometimes eight) LEDs that has either a common anode or cathode (you can review previous LED projects if you need a refresher on terminology). Characters on the display are shown by illuminating particular LEDs in the array. Figure 2 shows how the digit “2” would be illuminated on a seven-segment display, and then shows the equivalent circuit.
The seven-segment display used for this project is a common anode type (meaning the anode of each LED is connected). For organization and for the rest of this project, the cathode pins of each LED segment will be referred to as pins A–G (as in Fig. 2), and the decimal point, DP.
This project will also use a four digit display. Figure 3 shows a circuit diagram of all four digits. You may have noticed that all four digits share the same cathode pin. This means with all four anode pins driven HIGH, and for instance the ”A“ cathode pin is driven LOW, that particular segment would illuminate for all four digits.
While this doesn't really seem useful at first, it is quite common to all seven segment displays. Even with shared pins we are still able to display separate digits, so sharing pins like this allows us to save on the overall pin count of the device (from 36 pins to only 12). The chipKIT board is used to create a precisely timed sequence, which will allow us to display information on each digit separately.
The chipKIT board will drive all cathodes and anodes in sequence. By only driving one anode HIGH at a time with the desired cathodes for the segments you want illuminated driven LOW, we can display a value on only one digit. Now if we cycle between digits slowly (i.e., turn the current anode off, and then turn on the next anode with all of the cathodes needed for the next digit driven LOW), you can see each digit display information separately in a kind of round robin fashion. The rate at which sequences cycle through each digit is the ”refresh rate“. The refresh rate can be increased until you can no longer see the switching and all digits ”appear“ on the display at the same time. This is the same concept behind driving an LED with PWM from previous projects, or television and video displays (i.e., images changing so fast that the brain observes them as a single image).
So for example, to display ”1234“, initially anode 1 is HIGH (while all others are LOW), and cathodes B and C are LOW (with all other cathodes HIGH). This correctly biases segment B and C of digit 1 only. After a short amount of time, anode 1 is set LOW, and anode 2 is set HIGH. All of the cathode pins to display a ”2“ are then set LOW (i.e., A,B,G,E,D), thus displaying a ”2“ in the digit 2 position. Continuing this sequence for digits 3 (driving anode 3 HIGH and cathodes A,B,C,D,G LOW) and then 4 (anode 4 HIGH, and cathodes F,G,B,C LOW). After going through all four digits, the sequence then starts over. Setting the refresh rate is only a matter of setting the delay time before switching to the next digit. For our project we will be using 200 Hz, which displays fine without any flicker.
You may notice that this circuit uses a lot of wires and pins on the chipKIT board
to setup. To save on pin counts, I/O expanders or shift register ICs can be used
to communicate with the seven-segment display serially (the chipKIT essentially
communicates to the IC in serial, and then the IC communicates to the Segment
display in parallel). While slightly out of the scope of this project, such
components could be used in future projects.
The following code will display a running count in seconds and minutes on the seven-segment display screen.
// seven-segment elements to chipKIT pins
const unsigned int A = 5;
const unsigned int F = 4;
const unsigned int G = 33;
const unsigned int B = 3;
const unsigned int E = 29;
const unsigned int D = 30;
const unsigned int C = 32;
const unsigned int DP = 31;
const unsigned int Anode1 = 9;
const unsigned int Anode2 = 11;
const unsigned int Anode3 = 12;
const unsigned int Anode4 = 13;
// seven-segment digit
unsigned int digit = 1;
// Clock count
unsigned int SecondsD1 = 0;
unsigned int SecondsD2 = 0;
unsigned int MinutesD1 = 0;
unsigned int MinutesD2= 0;
unsigned int tick = 0;
void setup() {
// Pin Setup
pinMode(Anode1, OUTPUT);
pinMode(Anode2, OUTPUT);
pinMode(Anode3, OUTPUT);
pinMode(Anode4, OUTPUT);
pinMode(A,OUTPUT);
pinMode(B,OUTPUT);
pinMode(C,OUTPUT);
pinMode(D,OUTPUT);
pinMode(E,OUTPUT);
pinMode(F,OUTPUT);
pinMode(G,OUTPUT);
pinMode(DP,OUTPUT);
}
void decodeAndWrite(unsigned int value){
/* Initialize all values HIGH in order to not display information by default, and then depending
* on the "value" parameter set the corresponding element
* LOW to display a number.
*/
digitalWrite(A,HIGH);
digitalWrite(B,HIGH);
digitalWrite(C,HIGH);
digitalWrite(D,HIGH);
digitalWrite(E,HIGH);
digitalWrite(F,HIGH);
digitalWrite(G,HIGH);
digitalWrite(DP,HIGH);
// if digit being display is digit 2, add the decimal point
if (digit == 2){
digitalWrite(DP,LOW);
}
switch(value){
// Each case corresponds to the digit that is being displayed
case 0:
digitalWrite(A,LOW);
digitalWrite(F,LOW);
digitalWrite(E,LOW);
digitalWrite(D,LOW);
digitalWrite(C,LOW);
digitalWrite(B,LOW);
break;
case 1:
digitalWrite(C,LOW);
digitalWrite(B,LOW);
break;
case 2:
digitalWrite(A,LOW);
digitalWrite(G,LOW);
digitalWrite(E,LOW);
digitalWrite(D,LOW);
digitalWrite(B,LOW);
break;
case 3:
digitalWrite(C,LOW);
digitalWrite(B,LOW);
digitalWrite(A,LOW);
digitalWrite(G,LOW);
digitalWrite(D,LOW);
break;
case 4:
digitalWrite(F,LOW);
digitalWrite(B,LOW);
digitalWrite(G,LOW);
digitalWrite(C,LOW);
break;
case 5:
digitalWrite(A,LOW);
digitalWrite(F,LOW);
digitalWrite(G,LOW);
digitalWrite(C,LOW);
digitalWrite(D,LOW);
break;
case 6:
digitalWrite(C,LOW);
digitalWrite(G,LOW);
digitalWrite(E,LOW);
digitalWrite(D,LOW);
digitalWrite(F,LOW);
break;
case 7:
digitalWrite(A,LOW);
digitalWrite(B,LOW);
digitalWrite(C,LOW);
break;
case 8:
digitalWrite(A,LOW);
digitalWrite(F,LOW);
digitalWrite(B,LOW);
digitalWrite(G,LOW);
digitalWrite(C,LOW);
digitalWrite(D,LOW);
digitalWrite(E,LOW);
break;
case 9:
digitalWrite(A,LOW);
digitalWrite(F,LOW);
digitalWrite(B,LOW);
digitalWrite(G,LOW);
digitalWrite(C,LOW);
break;
default:
// do not display information for the default case
break;
}
}
void loop() {
/* Switch between which anode is driven HIGH in a
* round robin fashion. Digit 1 is the furthest left of the seven-segment display.
*
* This will drive each digit according to the clock counting variables.
* MinutesD2 will always display on digit 1
* MinutesD1 : digit 2
* SecondsD2 : digit 3
* SecondsD1 : digit 4
*/
switch(digit){
case 1:
digitalWrite(Anode1,HIGH);
digitalWrite(Anode2,LOW);
digitalWrite(Anode3,LOW);
digitalWrite(Anode4,LOW);
decodeAndWrite(MinutesD2);
break;
case 2:
digitalWrite(Anode1,LOW);
digitalWrite(Anode2,HIGH);
digitalWrite(Anode3,LOW);
digitalWrite(Anode4,LOW);
decodeAndWrite(MinutesD1);
break;
case 3:
digitalWrite(Anode1,LOW);
digitalWrite(Anode2,LOW);
digitalWrite(Anode3,HIGH);
digitalWrite(Anode4,LOW);
decodeAndWrite(SecondsD2);
break;
case 4:
digitalWrite(Anode1,LOW);
digitalWrite(Anode2,LOW);
digitalWrite(Anode3,LOW);
digitalWrite(Anode4,HIGH);
decodeAndWrite(SecondsD1);
break;
default:
//default off
digitalWrite(Anode1,LOW);
digitalWrite(Anode2,LOW);
digitalWrite(Anode3,LOW);
digitalWrite(Anode4,LOW);
break;
}
// Cycle through the digits,
digit++;
if (digit == 5){
digit = 1;
}
// Increment the clock tick count
tick++;
// main loop will run at 200 Hz
// so SecondsD1 will increment every 200 ticks
if (tick == 200){
SecondsD1++;
tick = 0;
}
// roll over to the second seconds digit
if (SecondsD1 == 10){
SecondsD1 = 0;
SecondsD2++;
}
// roll over to the first minutes digit
if (SecondsD2 == 6){
SecondsD2 = 0;
MinutesD1++;
}
// roll over to the second minutes digit
if (MinutesD1 == 10){
MinutesD1 = 0;
MinutesD2++;
}
if (MinutesD2 == 6){
MinutesD2 = 0;
}
delay(5);
}
Once loaded, the count will begin right away.
Now that you've completed this project, you should be able to:
You could also extend this project in various ways: