Oct-11th-2008

Multiplexed Seven Segment Displays – Part II

Hi Friends, In last tutorial we discussed about Multiplexing Seven Segment Displays. So you must be very much familier with the therory. Now let us write the code and design a small project that will make you expert in using these displays in your own projects. We will make a system that can display any number between 0-999 using three of these displays. We will write a function Print() that we can use on own later projects to easily write integers onto displays. Once we have successfully tested this function we can add to to any project without any problem. This concept of code reuse will make bigger project both easy to make and far less painfull. In this sample project we will test our function by using it in a loop to print all numbers from 0-999.

   for(i=0;i<1000;i++)
   {
  	    Print(i);
       Wait();
   }
We will assemble the project in a breadboard as shown below.
Multiplexed Seven Segment Displays.

Fig - Multiplexed Seven Segment Displays.

The Circuit Diagram.

You can use a Home Made AVR Devboard or a low cost xBoard MINI to experiment with seven segment displays. In the picture I have used xBoard MINI. The project is designed with ATmega8 but can easily be done through ATmega16 or ATmega32. The crystal value is not so critical for this you can use 12 MHz or 16 MHz it would only change the refresh rate of displays.
Multiplexed Seven Segment Displays.

Fig - Multiplexed Seven Segment Displays.

The Code


/*

Description:   Program to demonstrate the use of Seven

            Segment Displays In Multiplexed Mode.
________________________________________________________

Author:  Avinash Gupta
Date: 11 Oct 08
Web      www.eXtremeElectronics.co.in

   
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay_basic.h>


#define SEVEN_SEGMENT_PORT PORTD
#define SEVEN_SEGMENT_DDR DDRD

volatile uint8_t digits[3];


void SevenSegment(uint8_t n,uint8_t dp)
{
/*
This function writes a digits given by n to the display
the decimal point is displayed if dp=1

Note:

n must be less than 9
*/
   if(n<10)
   {
      switch (n)
      {
         case 0:
         SEVEN_SEGMENT_PORT=0b00000011;
         break;

         case 1:
         SEVEN_SEGMENT_PORT=0b10011111;
         break;

         case 2:
         SEVEN_SEGMENT_PORT=0b00100101;
         break;

         case 3:
         SEVEN_SEGMENT_PORT=0b00001101;
         break;

         case 4:
         SEVEN_SEGMENT_PORT=0b10011001;
         break;

         case 5:
         SEVEN_SEGMENT_PORT=0b01001001;
         break;

         case 6:
         SEVEN_SEGMENT_PORT=0b01000001;
         break;

         case 7:
         SEVEN_SEGMENT_PORT=0b00011111;
         break;

         case 8:
         SEVEN_SEGMENT_PORT=0b00000001;
         break;

         case 9:
         SEVEN_SEGMENT_PORT=0b00001001;
         break;
      }
      if(dp)
      {
         //if decimal point should be displayed

         //make 0th bit Low
         SEVEN_SEGMENT_PORT&=0b11111110;
      }
   }
   else
   {
      //This symbol on display tells that n was greater than 9
      //so display can't handle it

      SEVEN_SEGMENT_PORT=0b11111101;
   }
}

void Wait()
{
   uint8_t i;
   for(i=0;i<10;i++)
   {
      _delay_loop_2(0);
   }
}

void Print(uint16_t num)
{
   /* 

   
   This function breaks apart a given integer into separete digits
   and writes them to the display array i.e. digits[]
   
   */
   uint8_t i=0;
   uint8_t j;
   if(num>999) return;


   while(num)
   {
      digits[i]=num%10;
      i++;

      num=num/10;
   }
   for(j=i;j<3;j++) digits[j]=0;
}





void main()
{
   uint16_t i;

   // Prescaler = FCPU/1024
   TCCR0|=(1<<CS02);

   //Enable Overflow Interrupt Enable
   TIMSK|=(1<<TOIE0);

   //Initialize Counter

   TCNT0=0;

   //Port B[2,1,0] as out put
   DDRB|=0b00000111;

   PORTB=0b00000110;

   //Port D
   SEVEN_SEGMENT_DDR=0XFF;

   //Turn off all segments

   SEVEN_SEGMENT_PORT=0XFF;

   //Enable Global Interrupts
   sei();

   //Infinite loop
   //Print a number from 1 to 999
   while(1)
   {
      for(i=0;i<1000;i++)
      {
         Print(i);
         Wait();
      }

   }
}

ISR(TIMER0_OVF_vect)
{
   /*

   This interrup service routine (ISR)
   Updates the displays

   */
   static uint8_t i=0;

   if(i==2)
   {
      //If on last display then come

      //back to first.
      i=0;
   }
   else
   {
      //Goto Next display
      i++;
   }

   //Acivate a display according to i

   PORTB=~(1<<i);

   //Write the digit[i] in the ith display.
   SevenSegment(digits[i],0);

}

Download Code 7SegMUX.c


29 Responses to “Multiplexed Seven Segment Displays – Part II”

  1. 1
    Interfacing Temperature Sensor with AVR Microcontrollers - LM35 | eXtreme Electronics Says:

    [...] Using Seven Segment Displays in Multiplexed Mode. [...]

  2. 2
    nick Says:

    your code is really good.i make the project with great succesfull and with little bit different code.i think i can expand this for four displays.your code inspire me.thnx a lot

  3. 3
    Avinash Says:

    Hi Nick,
    :) Thanks for your response , I am very happy that my work helped you.

    You can easily expand the code for 4,5 displays.

    Nice to meet you :)

  4. 4
    Ritesh Says:

    Hello avinash

    the program for counting 0-999 its working but I am using stk500 with ATMega16 m using PORTB for Display, PORTD three pins for 3Xseven segment display , my question is why its working with PORTD PIN 0,1,2 only , I have changed only where u have activated 0,1,2 to 5,6,7 is it ok , but still its not working plz help me out …this is my c code :

    [CODE REMOVED] – Site Admin.

  5. 5
    Ritesh Says:

    Dear Avinash,

    In this program you have not defined Digit its giving error

  6. 6
    Ritesh Says:

    Dear Avinash,

    In this program you have not defined Digit its giving error
    I think that is array .

  7. 7
    Avinash Says:

    *************************************
    A SMALL BUG IN ABOVE PROGRAM REMOVED.
    *************************************
    – Site Admin.

  8. 8
    black Says:

    in the above program digit[i] was not initialised.now if my program is long and takes some time to reach print(i) in main loop then i will reach the interrupt routine before print(i).
    ie we expect that our interrupt comes at least after the 1st print(i).
    what will the output be in this case or what error will it give?

  9. 9
    Avinash Says:

    Thanks for your deep analysis!:)

    As varriables are stored in RAM and For uninitialized varriable contains unpredictable data.

    The best way to test is to simply remove the Print() call at all!

    And then run it so check what shows up
    :)

  10. 10
    Emeka Udo-Chijioke Says:

    Thanks Avinash. Can I buy you a drink?

  11. 11
    Avinash Says:

    @Emeka
    :) Sure !!!

  12. 12
    AVR Project - Digital Stop Watch with ATmega8 | eXtreme Electronics Says:

    [...] Multiplexed Seven Segment Display Interfacing [...]

  13. 13
    Kevin Says:

    How come you never call the ISR(TIMER0_OVF_vect) function? How do you end up printing the numbers since it is never called.

  14. 14
    Avinash Says:

    Hello Kelvin,

    The function ISR(TIMER0_OVF_vect) is an ISR i.e. Interrupt Service Routine. It is called automatically by the hardware (in this case the TIMER) when it needs attention of CPU. Do you get it now ???

  15. 15
    ritesh Says:

    Hello Avinash

    I the above program helped me lot..good man nice work……but if I want like digit should blink same as we put blinking bulb in diwali for decoration…like 1 comes it blinks for some time the 2 comes and so on…..is it possible? can you tel me how

  16. 16
    ritesh Says:

    hi all
    any one knows how can I blink the numbers or alphabets which comes on seven segment display , same like diwali bulbs it comes then go ,comes then go……

  17. 17
    sonal Says:

    hi sir
    i want to know that how to simulate it in proteus.i am trying but not able to get expected result. can u plz help …
    thak you.

  18. 18
    Claudiu Says:

    Why you use this: “for(j=i;j<3;j++) digits[j]=0;" because it`s never call.
    Because the variable "i" will be 3 when exiting from while(num) so j=3 and "j<3" is not true, then all the code in section "for()" it will never be executed.

  19. 19
    Avinash Says:

    @Claudiu

    Don’t use your brain too much. Leave it to the CPU (or the MCU) to execute the code

    Its the difference between theory and reality.

    Why will i=3 when the while loop break?

    It will be 1 when the number to be printed is 1 digit say 3
    It will be 2 when the number to be printed is 2 digit say 21

    when the number to be printed is single or two digit then this code is used to fill leading 0.

    Got anything ???

    Give more emphasis on doing thing not finding faults in others.

    Sorry if I am bit harsh.

  20. 20
    Claudiu Says:

    Ok, sorry for that. I understand now, you are right.
    When I`ve make my multiplexed 7segm code, I didn`t put zeros in front of the digits, so that`s why I didn`t understand.

    PS: your code is much better and easy to implement.

  21. 21
    Avinash Says:

    @Cladiu

    Glad you understood it. Coz if you leave that line, then there may be left out digit from the last print. Thats why I fill them with Zeros.

    Example:

    You printed 435 first. The display will show it fine. Then say you wanna print 7 then it will show 437 instead of 7. The 4 and 3 are shadow left from last call. So we fill zero in unwanted places.

    Got it ???

  22. 22
    Robert Says:

    Hi…

    btw. great site :) Thanks.

    Just wondering is there any reason you couldn’t move the 330 Ohm resistors to the Anode end? Therefore only 3 resistors needed instead of the 7 on the PORTD/Cathode end.

  23. 23
    Mohammed Says:

    Hell0;

    when i compiled your program i get the following errors in AVR studio 4 please help i am beginner and i am using atmega32

    ../multiplesevensegments.c:134: error: ‘TCCR0′ undeclared (first use in this function)
    ../multiplesevensegments.c:137: error: ‘TIMSK’ undeclared (first use in this function)

  24. 24
    Avinash Says:

    @Mohammed

    Did you configured AVR Studio project to use ATmega32 ???

    Please reply ASAP or your comment will be deleted.

  25. 25
    Mohammed Says:

    i am sorry i was configuring it to atmega328p now i got it thanks but please do tell me should the bc557 be connected to positive terminal of the battery since iam using common anode seven segment leds

  26. 26
    scada Says:

    The entire project is wonderful. However, I’m using PIC16F877 and the compiler is mikroC. Can you help me out with converting these line of codes into mikroC?

    ISR(TIMER0_OVF_vect){ ...}
    // Prescaler = FCPU/1024
    TCCR0|=(1<<CS02);

    //Enable Overflow Interrupt Enable
    TIMSK|=(1<<TOIE0);

    //Initialize Counter

    TCNT0=0

    //Enable Global Interrupts
    sei();

  27. 27
    Avinash Says:

    @Scada,

    The following code is for PIC16F877A using HI-TECH C

    http://extremeelectronics.co.in/code-snippets/multiplexed-seven-segment-display-using-pic16f877a-and-hi-tech-c/

  28. 28
    scada Says:

    I’m using a 4MHz PIC16F877 to send a signal to a PING ultrasonic sensor to measure distance of object relative to the sensor. The Get_Fuel_Level procedure in the code below sends and reads the signal but still, it doesn’t work. I need help. Thank you.(I’m using MPLAB).

    #include

    #define _XTAL_FREQ 20000000UL

    typedef unsigned char UINT8;
    typedef signed char INT8;
    typedef unsigned int UINT16;
    typedef signed int INT16;

    //Connection of Seven segment display
    #define SEVEN_SEGMENT_LAT PORTC
    #define SEVEN_SEGMENT_TRIS TRISC

    //MUX Control
    #define MUX_PORT PORTB
    #define MUX_START_POS 0 //From which bit on port the select lines start

    //MUX settings
    #define MUX_DISP_COUNT 3 //Number of displays

    //Global Varriable
    UINT8 DisplayArray[MUX_DISP_COUNT];//Holds ‘data’ for each disp
    unsigned short start_time,end_time,f_time,roundnum;
    volatile float length;

    void Get_fuel_level()
    {
    //unsigned short start_time,end_time;
    //unsigned short f_time;
    start_time=0;
    end_time=0;
    f_time=0;
    //Clear TMR1 and enable TMR1 disable TMR1 interrupt
    TMR1ON=0;
    TMR1H=0×00;
    TMR1L=0×00;
    TMR1ON=1;
    TMR1IE=0;

    //Get fuel level in seconds
    TRISB3=0;
    RB3=1; //Output trigger pulse
    _delay(5); //Trigger pulse is 5us long
    RB3=0; //End trigger pulse
    _delay(200); //Delay to take care of Thold-off
    TRISB3=1; //Make RA0 an input

    do{
    if (start_time==0)
    {
    if(RB3==1)
    {
    start_time=TMR1H;
    start_time<<=8;
    start_time+=TMR1L;
    }
    }
    else
    {
    if (RB3==0)
    {
    end_time=TMR1H;
    end_time<<=8;
    end_time+=TMR1L;
    }
    }
    }while(end_time==0);
    }

    void SevenSegmentWrite(UINT16 n)
    {
    /*
    n=data to dislay
    example:
    n=1234 will display 1234 in a 4 segment display

    Working:
    This function breaks apart a given integer into separete digits
    and writes them to the display array i.e. digits[]
    */

    UINT8 i=0;
    UINT8 j;

    while(n)
    {
    DisplayArray[i]=n%10;
    i++;

    if(i==MUX_DISP_COUNT)
    break; //We don't have room for more digits

    n=n/10;
    }

    //Fill Unused area with 0
    for(j=i;j<MUX_DISP_COUNT;j++) DisplayArray[j]=0;
    }

    void WriteSegment(UINT8 num)
    {
    switch (num)
    {
    case 0:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B01000000;
    break;

    case 1:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B01111001;
    break;

    case 2:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B00100100;
    break;

    case 3:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B00110000;
    break;

    case 4:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B00011001;
    break;

    case 5:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B00010010;
    break;

    case 6:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B00000010;
    break;

    case 7:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B01111000;
    break;

    case 8:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B00000000;
    break;

    case 9:
    //-GFEDCBA
    SEVEN_SEGMENT_LAT = 0B00010000;
    break;

    }

    }

    void Wait()
    {
    UINT8 i;
    for(i=0;i<1;i++)
    __delay_ms(10);
    }
    void main()
    {
    //Set Up I/O Ports

    TRISB0=0;
    SEVEN_SEGMENT_TRIS = 0B10000000;//Disp is connect from 0-6 last bit 7 is unused

    //MUX select lines
    TRISB = 0B11111000;

    //Init TIMER0

    T0CS=0; //Timer Clock source is intruction clock that is 5MHz
    PSA=0; //Prescaler is assigned to TIMER0
    PS2=1;
    PS1=1;
    PS0=0; //Prescaler = FCPU/128
    TMR0IE=1; //Enable Timer0 Interrupt
    PEIE=1; //Enable Peripheral Interrup

    //Enable Interrupts Globally
    ei();

    while(1)
    {
    Get_fuel_level();
    f_time=end_time-start_time;
    length=f_time;
    length=length/0.58068; //length in centimetre
    SevenSegmentWrite(length);
    _delay(200);
    }

    }

    //Our Interrupt Service Routine
    void interrupt ISR()
    {
    if(TMR0IE && TMR0IF)
    {
    //TIMER0 Overflow Interrupt
    //First Clear the INT flag
    TMR0IF=0;

    // Current display selected
    //Value of "static varriable" is retained between calls
    static int i;

    //Switch On Display Pointed by 'i'
    MUX_PORT = (~(1<<(i+MUX_START_POS)));

    //Latch digit on it
    WriteSegment(DisplayArray[i]);

    //On each time out select next display
    i++;

    //If on last display then goto first
    if(i==MUX_DISP_COUNT)
    i=0;
    }
    }

  29. 29
    andyy Says:

    Great job avinash ..:) thank you…But I would ask u How to write program to display data onto 4-digit multiplexed 7-segmentdisplays? in asemmbly not C….?so controlling for digits by PORTD(D0…D3) and controlling segment’s leds by PORTB(B0…B7)..by using atmega32 microcontroller…
    Waiting for ur help thank u

Leave a Reply

Comments

    • wlewis: @Av.. To my knowledge, practically all the non-ic humidity sensors are frequency dependant...
    • wlewis: @Av.. about ADC.. how about a tutorial that does a 10bit conversion?
    • wlewis: @Av I have a great idea for a tutorial… sensors which output are measured by frequency....
    • BoB: Hello… I’m still a newbie in this field..so, may I ask…this application used...
    • Hill: Why dont you mention in your URL which PICs these burner supports? It will help avoid guesswork...
    • victor: I have to rectify, that is not an issue, instead is a LCD’s McU limitation in locations...
    • wlewis: Avrdude code for atmega32 // 16mhz crystal // Jtag disabled. avrdude -p m32 -b 19200 -P COM3...

Video

  • Comments

    • wlewis: @Av.. To my knowledge, practically all the non-ic humidity sensors are frequency dependant...
    • wlewis: @Av.. about ADC.. how about a tutorial that does a 10bit conversion?
    • wlewis: @Av I have a great idea for a tutorial… sensors which output are measured by frequency....
    • BoB: Hello… I’m still a newbie in this field..so, may I ask…this application used...
    • Hill: Why dont you mention in your URL which PICs these burner supports? It will help avoid guesswork...
    • victor: I have to rectify, that is not an issue, instead is a LCD’s McU limitation in locations...
    • wlewis: Avrdude code for atmega32 // 16mhz crystal // Jtag disabled. avrdude -p m32 -b 19200 -P COM3...