How to interface 8 digits 7-segment with shift register 74HC595 and PIC16F877A

Published by MKDas on

Sometimes, we need to drive multiple displays in line. Sometimes we need to drive multiple numbers from one micro-controller. As micro-controller has fixed number of pins so it is not possible to configure any circuit to drive 100 digit or even more 7-Segments. That is why, we need to use shift registers. In this article, you will see how to use a shift register to interface multiple 7segments with micro-controller.

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.

What is shift registers?

In digital circuits, a shift register is a cascade of flip flops, sharing the same clock, in which the output of each flip-flop is connected to the “data” input of the next flip-flop in the chain, resulting in a circuit that shifts by one position the “bit array” stored in it, “shifting in” the data present at its input and ‘shifting out’ the last bit in the array, at each transition of the clock input. _Wiki.

To know more about shift registers, please visit wiki page here.

Shift registers are different in types. The most common ones are

  1. Serial in-parallel out
  2. Parallel in – Serial out

There are many types of shift registers, which can not be explain in short articles. Please do some research on this issue over the internet.

About 74HC595 Shift Register:

74HC595 is a serial in to parallel out with latch triggered tri-state shift register. This 16pin shift register is very common in use with micro-controller as port extender.

74HC595 shift register [Click to down datasheet]
DIP package

This SIPO shift register have a data input pin (A) where data can be loaded which is controlled by shift clock. Then one latch clock shifts these data to its output pins according to the 8bit data pattern given serially at data pin. Output Enable pin (!OE) is active low to enable output of that shift register. And the reset pin is also active low, connecting this reset pin to VDD will keep the operation going on. When we need more outputs, we just connect shift registers in cascade mode. For this, there is a data output (serial data out) pin. This pin will be then connected to the data input pin of next shift register.

Cascading multiple shift registers

When we need more than 8bit output, we can just use more shift registers. These shift registers are then connected in cascade mode. Serial Data Output of previous one will be connected to the data input of the next one. Keeping latch clock, shift clock common for each registers, we can then get output from all of the shift registers according to our command.

Cascade connection

This is a simple cascade connection for shift register. Here any type of shift registers works almost in same way. A common clock signal keep all the shift registers synchronized.

Utilizing micro-controller’s feature to drive shift register:

Each micro-controller have some special feature built in with it. In this project, we selected PIC16F877A micro-controller. Smaller micro-controllers can be used if you wish to.

Here, in MSSP module, we have an opportunity to use SPI module. This Serial Peripheral Interface have dedicated communicating pins. RC5/SDO, RC4/SDI/SDA & RC3/SCL. Using these pins, we can easily interface any shift registers with micro-controller.

Circuit diagram:

Utilizing the cascade connecting facilities of 74HC595, we can draw our circuit diagram for driving multiple seven segments.

Circuit diagram

Here in this simulation, I did not used any resistor between shift register and 7-Segment display. You should use a resistor in practical circuit. Better using a driver IC if the segment is big. ULN2003A will work fine.

Coding:

Here is the mikroC code for our multi-display project:

/*******************************************************************************
* Program for, Shift Register Display test for multiple digits                 *
* Program Written by_ Engr. Mithun_K_Das, mithun060@gmail.com                  *
* MCU:PIC16F877A; X-Tal: 20MHz; mikroC pro for PIC v6.5.0                      *
* Date: 07-09-2017                                                             *
*******************************************************************************/

Digit_conversion(char digit)
{
   switch(digit)
   {
      case 0: digit = 0x3F; return digit;
      case 1: digit = 0x06; return digit;
      case 2: digit = 0x5B; return digit;
      case 3: digit = 0x4F; return digit;
      case 4: digit = 0x66; return digit;
      case 5: digit = 0x6D; return digit;
      case 6: digit = 0x7D; return digit;
      case 7: digit = 0x07; return digit;
      case 8: digit = 0x7F; return digit;
      case 9: digit = 0x6F; return digit;
   }
}

unsigned long number=0;
int digit=0;
void Disp_number(unsigned long value)
{
   digit = (value/1u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/10u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/100u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/1000u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/10000u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/100000u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/1000000u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/10000000u)%10;
}
void Update_display()
{
  PORTC.F6=1; //one latch clock
  PORTC.F6=0;
}

void InitTimer1()
{
    T1CON         = 0x31;
    TMR1IF_bit    = 0;
    TMR1H         = 0x0B;
    TMR1L         = 0xDC;
    TMR1IE_bit    = 1;
    INTCON        = 0xC0;
}

void Interrupt() iv 0x0004 ics ICS_AUTO
{
  if (TMR1IF_bit)
  {
      TMR1IF_bit = 0;
      TMR1H = 0x0B;
      TMR1L = 0xDC;
      //Enter your code here
      Disp_number(number);
      Update_display();
  }
}



void main()
{
  TRISC = 0x00;
  PORTC = 0x00;
  CMCON = 0x07;
  ADCON1 = 0x07;
  SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV4, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);
  InitTimer1();
  number = 2;
  while(1)
  {
      number+=number;
      Delay_ms(500);
      if(number>99999999)number=2;
  }

}

Code explanation:

Digit_conversion(char digit)
{
   switch(digit)
   {
      case 0: digit = 0x3F; return digit;
      case 1: digit = 0x06; return digit;
      case 2: digit = 0x5B; return digit;
      case 3: digit = 0x4F; return digit;
      case 4: digit = 0x66; return digit;
      case 5: digit = 0x6D; return digit;
      case 6: digit = 0x7D; return digit;
      case 7: digit = 0x07; return digit;
      case 8: digit = 0x7F; return digit;
      case 9: digit = 0x6F; return digit;
   }
}

In this part, digits are converted for 7-Segment. For Common Anode, you need to edit these values.

void Disp_number(unsigned long value)
{
   digit = (value/1u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/10u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/100u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/1000u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/10000u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/100000u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/1000000u)%10;
   SPI_Write(Digit_conversion(digit));
   digit = (value/10000000u)%10;
}

Here, the 8 figure number is split into individual digits and written to the shift register through SPI module.

void Update_display()
{
  PORTC.F6=1; //one latch clock
  PORTC.F6=0;
}

This is generating a latch clock to throw the input of the shift register to its output pins. After writing all data serially, one latch clock reflects the inputs in output pins.

void Interrupt() iv 0x0004 ics ICS_AUTO
{
  if (TMR1IF_bit)
  {
      TMR1IF_bit = 0;
      TMR1H = 0x0B;
      TMR1L = 0xDC;
      //Enter your code here
      Disp_number(number);
      Update_display();
  }
}

You may not need to use ISR for periodic update, but here I used ISR to update the shift registers periodically. This helps making the display more responsive. You can call these two function serially to update the shift registers in while loop.

Disp_number(number);
Update_display();

      number+=number;
      Delay_ms(500);
      if(number>99999999)number=2;

And finally inside while loop, this code is used to demonstrate the result in simulation quickly. You can use in any format you need.

Test result:

In proteus, a simulation result shows how everything works. Check the video here:

Test result

If you understand the concept, you can add almost any number of shift registers and 7-Segment displays you need to. Here is another example where I elaborately used shift registers to interface several Seven Segment displays:

Elaborate use of shift register

I’ll write another article on this one later. Anyway, I hope you are well familiar to shift registers now. Can you make one for yourself now? I hope you can. If you can’t and stuck in middle, feel free to ask me. Thank you very much. Enjoy!


MKDas

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

0 Comments

Leave a Reply

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