How to interface multiplexed Seven Segment Display with Arduino with no library file in easy way

Published by MKDas on

I was looking for a good library to interface multiplexed Seven Segment with Arduino. But unfortunately, found no such good library what I can use as myself. Each one making trouble in Proteus simulation. Some examples I found over internet, not explained properly or not simplified at all. That is why, I wrote my own code for multiplexed Seven segment display for Arduino that can be used as I want. May be this article will help you a lot.

Disclaimer: Electricity is always dangerous. Skill required to work with electricity. Do work with your own risk. Author will not be responsible for any misuse or harmful act. This website contents is also copyright protected. Anything copied and directly posted in your website and claiming it as yours is prohibited and nonsensical. Author published all the articles as opensource to help you making your project and learning purpose only. Learn and make one for yourself. If need any help feel free to ask the author. Author will be helpful to you. Thanks.

Basics of seven segment display

Before we start, we must know the basic of seven segment displays. If you know this already, just go to the next stage. Anyway, most of the seven segment are made with LED blocks. There are other two types of segments in the market, crystal based and tube based. But the LED based one is the most common.

Seven Segment

As you see, the segments are two types according to the LED configuration. One is Common Cathode another is Common Anode. If you want to drive these segments, you just need to maintain the right voltage & polarity. Now, these segments have total 8 segment pins and two shorted common pins. If we attach 3 or 4 same type of segment in a line and keep the 8 segment pins in common and shorted pins individual for each digit, it will form a multiplexed 7Segment display of 3×1 or 4×1.

Multiplexed Seven Segment

Benefit of this type of display is, we have the common 8 pins for each segment and individual data pins for each digits. In this way, I/O pin can be reduced and it become more suitable for circuit placement.

But problem is, driving these type of multiplexed display is not as simple as like single digit driving. If you have a set of outputs for the segment pins, you can activate only one digit each time to display it correctly.

Multiplexed Seven segment animation

I found an animation for multiplexed Seven segment display. As you can see, the data pins are setting a configuration for a number and the data pin is activating the individual digits. This process going on sequentially. If we do this job faster I mean within 10ms, our eye will see this as a 4 digit number of 1238. That’s the secrete of driving multiplexed seven segment displays.

Drawing the circuit diagram:

Now, to test this process of multiplexing, we need to make a circuit diagram first. Lets draw a circuit diagram like this in Proteus:

Circuit diagram

Now, we need to write our code for this circuit diagram. But first we need to simplify our working mechanism to drive the multiplexed 7Segment display.

Simplified working mechanism:

Pattern generation:

From that animated image, you know we need to generate a pattern first for each number.

Pattern generation

To show 0, we need to turn on some LEDs of our segment. a,b,c,d,e,f are 1 and g = 0; Then if forms ‘0’ in display. Similarly, we can generate a pattern for each number from 0 to 9. Note that, if you want to display characters, you can do that too. But for first project, limit in numbers only.

As we are going to use Arduino, we have to make these pattern according to Arduino style. In Arduino, 1 = HIGH and 0 = LOW.

If we take an array for this, we can store all the pattern in that array. Now, as we have to use 8 individual pins for segment pattern and also have to create 10 of this type of pattern, so we must arrange an array with dual dimension.

Dual dimension array

Now we can call the pattern of any number and can set our 8 pins according to our segment pattern. We’ll see more about this later on code section below.

Timing generation:

After generating our pattern, we need to generate a timing. I mentioned earlier that, if we do the animation faster we can see one single picture of a complete number of 4 digits. Whatever 3,4 or more digits, we have to do all the process within 0.25 seconds. Then we can see a still number of multiple digits. That means, if we use 4 digit display and maintain a timing of 5ms for each update we can see a single number of 4 digit on the display without any blinks.

For this timing generation, we can use Timer modules of Arduino. Setting the interrupt in 5000us or 5ms, we can easily generate our timing

Now we can write our code for our project.

Arduino Code:

#include <TimerOne.h>
const int segment_pins[] = {13, 12, 11, 10, 9, 8, 7, 6}; //segments a to g
const int digit_pins[] = {5, 4, 3, 2}; // 4digits
const int digit_number = 4;//for 4 digit segment
byte dot_position;//set dot position from right side. 
bool dot_point=false;// having dot or not, true = have dot, false = no dot. 

const int segment_array[10][8] = // for common cathode segment only
{
  {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, LOW}, //0
  {LOW, HIGH, HIGH, LOW, LOW, LOW, LOW, LOW},     //1
  {HIGH, HIGH, LOW, HIGH, HIGH, LOW, HIGH, LOW},  //2
  {HIGH, HIGH, HIGH, HIGH, LOW, LOW, HIGH, LOW},  //3
  {LOW, HIGH, HIGH, LOW, LOW, HIGH, HIGH, LOW},   //4
  {HIGH, LOW, HIGH, HIGH, LOW, HIGH, HIGH, LOW},  //5
  {HIGH, LOW, HIGH, HIGH, HIGH, HIGH, HIGH, LOW}, //6
  {HIGH, HIGH, HIGH, LOW, LOW, LOW, LOW, LOW},    //7
  {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW},//8
  {HIGH, HIGH, HIGH, HIGH, LOW, HIGH, HIGH, LOW}, //9
};


void int_sev_segment() 
{
  for (int k = 0; k < 8; k++)
  {
    pinMode(segment_pins[k], OUTPUT);//I/O settings
  }
  for (int k = 0; k < digit_number; k++)
  {
    pinMode(digit_pins[k], OUTPUT);//I/O settings
  }
  for (int k = 0; k < 8; k++)
  {
    digitalWrite(segment_pins[k], LOW);//keep low
  }
  for (int k = 0; k < digit_number; k++)
  {
    digitalWrite(digit_pins[k], HIGH);//keep high = disable segments (CC)
  }
  Timer1.initialize(5000);//5000us = 5ms
  Timer1.attachInterrupt(display_segment);
}


char digits[5];
void display_7segment(int number, byte dot)
{
  digits[3] = number / 1000u;//extract 1000th digit
  digits[2] = (number / 100u) % 10u;//extract 100th digit
  digits[1] = (number / 10u) % 10u;//extract 10th digit
  digits[0] = (number / 1u) % 10u;//extract 1st digit
  dot_position = dot;
}


int digit_position = 0;
void display_segment(void) // called periodically using timer interrupt
{
  for (int k = 0; k < digit_number; k++)
  {
    digitalWrite(digit_pins[k], HIGH);//reset digit pins
  }
  if (digit_position > 3)digit_position = 0;

  for (int k = 0; k < 8; k++) //print the a to g segment pins
  {
    digitalWrite(segment_pins[k], segment_array[digits[digit_position]][k]);
    if (digit_position == dot_position && dot_point == true)
    {
      digitalWrite(segment_pins[7], HIGH);//print dot point
    }    
  }

  if (digit_position == 3)
  {
    digitalWrite(digit_pins[0], LOW);
    digitalWrite(digit_pins[1], HIGH);
    digitalWrite(digit_pins[2], HIGH);
    digitalWrite(digit_pins[3], HIGH);
  }
  else if (digit_position == 2)
  {
    digitalWrite(digit_pins[0], HIGH);
    digitalWrite(digit_pins[1], LOW);
    digitalWrite(digit_pins[2], HIGH);
    digitalWrite(digit_pins[3], HIGH);
  }
  else if (digit_position == 1)
  {
    digitalWrite(digit_pins[0], HIGH);
    digitalWrite(digit_pins[1], HIGH);
    digitalWrite(digit_pins[2], LOW);
    digitalWrite(digit_pins[3], HIGH);
  }
  else if (digit_position == 0)
  {
    digitalWrite(digit_pins[0], HIGH);
    digitalWrite(digit_pins[1], HIGH);
    digitalWrite(digit_pins[2], HIGH);
    digitalWrite(digit_pins[3], LOW);
  }
  digit_position++;
}


int cnt = 0;
void setup()
{

  int_sev_segment();//initialize seven segment program

}

void loop()
{

  cnt++;
  display_7segment(cnt, 1); //display value of cnt, dot in position 1 from right side
  delay(500);

}



// end

Code explanation:

#include <TimerOne.h>
const int segment_pins[] = {13, 12, 11, 10, 9, 8, 7, 6}; //segments a to g
const int digit_pins[] = {5, 4, 3, 2}; // 4digits
const int digit_number = 4;//for 4 digit segment
byte dot_position;//set dot position from right side. 
bool dot_point=false;// having dot or not, true = have dot, false = no dot. 

Here, TimerOne.h is used for timer interrupt. We mentioned earlier that we will not use any library for multiplexed Seven segment display. But Timers is not that library to Seven Segment. We have to use this to active interrupts.

Segment_Pins array contain the individual pins for segments a to g. And other parameters are easy to understand. If you do not want to keep the dot point, set dot_point=false.

const int segment_array[10][8] = // for common cathode segment only
{
  {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, LOW}, //0
  {LOW, HIGH, HIGH, LOW, LOW, LOW, LOW, LOW},     //1
  {HIGH, HIGH, LOW, HIGH, HIGH, LOW, HIGH, LOW},  //2
  {HIGH, HIGH, HIGH, HIGH, LOW, LOW, HIGH, LOW},  //3
  {LOW, HIGH, HIGH, LOW, LOW, HIGH, HIGH, LOW},   //4
  {HIGH, LOW, HIGH, HIGH, LOW, HIGH, HIGH, LOW},  //5
  {HIGH, LOW, HIGH, HIGH, HIGH, HIGH, HIGH, LOW}, //6
  {HIGH, HIGH, HIGH, LOW, LOW, LOW, LOW, LOW},    //7
  {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW},//8
  {HIGH, HIGH, HIGH, HIGH, LOW, HIGH, HIGH, LOW}, //9
};

In working mechanism section, we came to know that we must generate a dual dimensional array for our display. Here in this segment_array, we set the pin outputs in patterns to generate individual number on segment.

void int_sev_segment() 
{
  for (int k = 0; k < 8; k++)
  {
    pinMode(segment_pins[k], OUTPUT);//I/O settings
  }
  for (int k = 0; k < digit_number; k++)
  {
    pinMode(digit_pins[k], OUTPUT);//I/O settings
  }
  for (int k = 0; k < 8; k++)
  {
    digitalWrite(segment_pins[k], LOW);//keep low
  }
  for (int k = 0; k < digit_number; k++)
  {
    digitalWrite(digit_pins[k], HIGH);//keep high = disable segments (CC)
  }
  Timer1.initialize(5000);//5000us = 5ms
  Timer1.attachInterrupt(display_segment);
}

In this initialization section, we initialized the input/output configuration and timer interrupt.

char digits[5];
void display_7segment(int number, byte dot)
{
  digits[3] = number / 1000u;//extract 1000th digit
  digits[2] = (number / 100u) % 10u;//extract 100th digit
  digits[1] = (number / 10u) % 10u;//extract 10th digit
  digits[0] = (number / 1u) % 10u;//extract 1st digit
  dot_position = dot;
}

This display_7segment function is extracting digits of different positions which is stored in digits array.

int digit_position = 0;
void display_segment(void) // called periodically using timer interrupt
{
  for (int k = 0; k < digit_number; k++)
  {
    digitalWrite(digit_pins[k], HIGH);//reset digit pins
  }
  if (digit_position > 3)digit_position = 0;

  for (int k = 0; k < 8; k++) //print the a to g segment pins
  {
    digitalWrite(segment_pins[k], segment_array[digits[digit_position]][k]);
    if (digit_position == dot_position && dot_point == true)
    {
      digitalWrite(segment_pins[7], HIGH);//print dot point
    }    
  }

  if (digit_position == 3)
  {
    digitalWrite(digit_pins[0], LOW);
    digitalWrite(digit_pins[1], HIGH);
    digitalWrite(digit_pins[2], HIGH);
    digitalWrite(digit_pins[3], HIGH);
  }
  else if (digit_position == 2)
  {
    digitalWrite(digit_pins[0], HIGH);
    digitalWrite(digit_pins[1], LOW);
    digitalWrite(digit_pins[2], HIGH);
    digitalWrite(digit_pins[3], HIGH);
  }
  else if (digit_position == 1)
  {
    digitalWrite(digit_pins[0], HIGH);
    digitalWrite(digit_pins[1], HIGH);
    digitalWrite(digit_pins[2], LOW);
    digitalWrite(digit_pins[3], HIGH);
  }
  else if (digit_position == 0)
  {
    digitalWrite(digit_pins[0], HIGH);
    digitalWrite(digit_pins[1], HIGH);
    digitalWrite(digit_pins[2], HIGH);
    digitalWrite(digit_pins[3], LOW);
  }
  digit_position++;
}

This function is being called periodically in 5ms interval. Here, step by step we are doing some important works. First, we are disabling all 4 digits by setting the digit pins HIGH. Then the position counter is being reset to 0 if it is over 3.

for (int k = 0; k < 8; k++) //print the a to g segment pins
  {
    digitalWrite(segment_pins[k], segment_array[digits[digit_position]][k]);
    if (digit_position == dot_position && dot_point == true)
    {
      digitalWrite(segment_pins[7], HIGH);//print dot point
    }    
  }

And the most important work is done here. As you can see, we are calling that dual dimensional array here and setting our segment array pins according to the digits of each position. Also if there is any dot, we have to print that too.

if (digit_position == 3)
  {
    digitalWrite(digit_pins[0], LOW);
    digitalWrite(digit_pins[1], HIGH);
    digitalWrite(digit_pins[2], HIGH);
    digitalWrite(digit_pins[3], HIGH);
  }
...

Then we are activating each digits one at a time shifting to the next and rolling to position 0 when done. As this ISR is being called in each 5ms interval, so we are printing our digits one by one within 5×4 = 20ms.

In the loop function, we are simply calling this to count a number and display that on our multiplexed segment.

Test result:

Simulated test result

Conclusion:

In the end, I hope you understood the project and now you can practice yourself. After practice, I’ll suggest to make one for yourself and share here. Anywhere in the middle if you need any help, just ask. I’ll try my best to help you.

Thank you very much. Enjoy!


MKDas

Mithun K. Das; B.Sc. in EEE from KUET. Blog: https://labprojectsbd.com

2 Comments

Rajbir Dass · March 7, 2021 at 6:23 pm

Sir please give me code for ac 220v/ 100A current meter code in 3digit 7segment display for Arduino

    Mithun K. Das · March 8, 2021 at 5:23 am

    You can make it yourself. Kindly read the high current sensing article besides this article. If you can not understand let me know. Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *