Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Multiplexed 7segment display simulation problem in proteus

Status
Not open for further replies.

Mithun_K_Das

Advanced Member level 3
Advanced Member level 3
Joined
Apr 24, 2010
Messages
899
Helped
24
Reputation
48
Reaction score
26
Trophy points
1,318
Location
Dhaka, Bangladesh, Bangladesh
Activity points
8,254
I had several 7segment based meters which works fine in hardware. Most of these are regular products, no display problem found yet in last 7yrs+.
Today, I was trying to make a simple simulation based on 7segment display in proteus 8.9. But I found that, it can not display 7segment properly.
Either it shows still non-digits or flickering. I tried changing timing for multiplexing. But can't find the problem.

Can anyone tell me whats wrong here? Again I'm mentioning that, it works in hardware with this 5ms refresh interval. Sometimes little adjustment may required.
It is not working properly in proteus only.

Here is the simplified code which I was testing.

Code:
unsigned short mask(int num)
{
   switch (num)
   {
       case 0 : return 0xC0;
       case 1 : return 0xF9;
       case 2 : return 0xA4;
       case 3 : return 0xB0;
       case 4 : return 0x99;
       case 5 : return 0x92;
       case 6 : return 0x82;
       case 7 : return 0xF8;
       case 8 : return 0x80;
       case 9 : return 0x90;
   }
}
unsigned short  portb_index;
unsigned int digit,number;
unsigned short portb_array[5];

void display_digits()
{
  PORTB = portb_array[portb_index];
  if(portb_index==3)
  {
     RC0_bit = 1;
     RC1_bit = 0;
     RC2_bit = 0;
     RC3_bit = 0;
  }
  if(portb_index==2)
  {
     RC0_bit = 0;
     RC1_bit = 1;
     RC2_bit = 0;
     RC3_bit = 0;
  }
  if(portb_index==1)
  {
     RC0_bit = 0;
     RC1_bit = 0;
     RC2_bit = 1;
     RC3_bit = 0;
  }
  if(portb_index==0)
  {
     RC0_bit = 0;
     RC1_bit = 0;
     RC2_bit = 0;
     RC3_bit = 1;
  }
   portb_index ++ ;
   Delay_ms(5);
   if (portb_index > 3)portb_index = 0;
}


 void Digit_seperation()
 {
     digit = (number / 1u) % 10u;
     portb_array[0] = mask(digit);
     digit = (number / 10u) % 10u;
     portb_array[1] = mask(digit);
     digit = (number / 100u) % 10u;
     portb_array[2] = mask(digit);
     digit = number / 1000u;
     portb_array[3] = mask(digit);
 }


void main()
{
  TRISA = 0xFF; // all input.
  TRISB = 0x00; // Set PORTB direction to be output
  TRISC = 0x00; // Set PORTB direction to be output
  PORTC = 0x00;
  PORTB = 0x00;
  ADCON1 = 0x00;// all analog in
  while(1)
  {

    number = 5432;
    Digit_seperation();
    display_digits();

  }//Endless loop;
}//End.



// end


And the proteus file:

- - - Updated - - -

This is happening most of the time.
Capture.PNG
 

Attachments

  • AC voltmeter with PIC16F73.rar
    16.4 KB · Views: 196

Ugh!
Please use a timer to set the multiplexing rate, it is the only way you will get the digits to have equal brightness. Ideally, use a timer to create an interrupt and cycle through the digits at each call to the ISR.

Why are you using that switch/case statement when a simple array would suffice and take up far less space, and more importantly a constant time to execute regardless of the index?

Brian.
 

1. Delay_ms() statement isn't simulated in real time. Your code has to be corrected for this fact.
2. Muxed LCD component in Proteus is working as a one shot with configurable pulse width. The parameter can be adjusted.
3. Your display_digits() procedure has a fault that might not show in real hardware. You need to disable the digit driver first, then write the new segment value, then enable the new digit.
 

In main program I used timer. As it was not working properly, I simplified the code to check if there is any mistake in timer ISR. With timer ISR, it work fine in real hardware. But that same code in simulation can not display segment properly.

Switch-case issue: This code was first developed in around 2010. As it is not making any trouble so I did not changed later. If array consume less memory, I'll change to array.

Muxed LCD component: I tried changing the response time; Either it shows in flickering, or in non-digit. Even I've collected one ready file from libstock.com to check. It is also not displaying properly. I've attached the video here.
Also file is attached here:

- - - Updated - - -

The other simulation file in the last uploaded project file works.
 

Attachments

  • 1371395518_multiplexed_seve_mikroc_pic.rar
    64.8 KB · Views: 188

For clarification - are you using 7-segment LEDs or LCDs? They require completely different drive signals, the code and schematic are for LEDs but your text mentions "Muxed LCD component".

I can't verify your simulation, Proteus only runs under Windows.

Brian.
 

Oh sorry, Muxed LCD component may be wrong. It should be LED for sevensegment. I copied from previous post of FVM.

Anyway, I solved this problem.

There was a timing problem for Data pins in interrupt ISR.

Finally modified code:
Code:
char segment_array[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6  F};//cmmon cathode_non dot

sbit digit0 at RC0_bit;
sbit digit1 at RC1_bit;
sbit digit2 at RC2_bit;
sbit digit3 at RC3_bit;

char digits[5];
void display_7segment(int number)
{
   digits[3]=number/1000u;
   digits[2]=(number/100u)%10u;
   digits[1]=(number/10u)%10u;
   digits[0]=(number/1u)%10u;
}

void InitTimer0()
{
  OPTION_REG     = 0x85;
  TMR0           = 100;
  INTCON         = 0xA0;
}

int position=0;
void Interrupt() iv 0x0004 ics ICS_AUTO
{
  if (TMR0IF_bit)
  {
    TMR0IF_bit   = 0;
    TMR0         = 100;
    
    digit0 = 1;
    digit1 = 1;
    digit2 = 1;
    digit3 = 1;
    if(position>3)position=0;
    
    if(position==1)PORTB = segment_array[digits[position]]+128; //dot point
    else PORTB = segment_array[digits[position]];
    
    if(position==3)
    {
        digit0 = 0;
        digit1 = 1;
        digit2 = 1;
        digit3 = 1;
    }
    else if(position==2)
    {
        digit0 = 1;
        digit1 = 0;
        digit2 = 1;
        digit3 = 1;
    }
    else if(position==1)
    {
        digit0 = 1;
        digit1 = 1;
        digit2 = 0;
        digit3 = 1;
    }
    else if(position==0)
    {
        digit0 = 1;
        digit1 = 1;
        digit2 = 1;
        digit3 = 0;
    }
    position++;
  }
}



unsigned int cnt=0;
void main()
{
 TRISB=0x00;//all output
 TRISC=0x00;//all output
 PORTB=0x00;
 PORTC=0x00;//clear ports
 InitTimer0();//5ms timer
 while(1)
 {

    display_7segment(cnt);
    cnt++; Delay_ms(200);
    if(cnt>9999)cnt=0;
 }
}












//

- - - Updated - - -

If you have any further suggestion for this code to make it more professional please share. Thanks.
 

Technically you shouldn't enable the GIE bit in INTCON at the same time as the interrupt itself but it wouldn't make any difference the performance in your program.

You can further simplify it by using an array for the digit drive signals as well and in real life you probably need to allow for some 'dead' time between digits, a brief period when all the segments are turned off before setting the next pattern, or you may see some 'ghosting'. A trick here is to combine the two suggestions, by turning all the digits off before changing the segments then turning the new digit on.

Brian.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top