Multiplexing 3 rows 6 columns 7-segment based digital clock using 74HC595

Hello All,
I am working on displaying day, date & time information on 7 segment LED using 74HC595 shift registers and COMMON ANODE configuration.
Please see my attached diagram. I am explaining the acrchitecture as follows:

  1. The top row displays time in HH:MM:SS format.

  2. The middle row displays date in DD:MM:YY format.

  3. The lowest row (single 7-segment LED) displays Day of week. Each day coresponds to each segment in the 7 segment LED.

  4. I am using 3 shift registers 74HC595, in which Clock & Latch lines are common. The Data is cascaded from one shift register to another.

  5. I am getting the day/date/time values from RTC and extracted the DD:MM:YY, HH:MM:SS, DAY data to be displayed.

For display, I am following the below multiplexing technique: (Multiplexing using Timer 100 ms)

  1. Switch ON PD5 (left most LEDs, i.e. 1st column, all the 3 rows) and remaining OFF.

  2. Pull Latch LOW → Shift out 3 bytes of data with clock → Pull Latch HIGH.

  3. Switch ON PD4 (i.e. 2nd column, all the 3 rows) and remaining OFF.

  4. Pull Latch LOW → Shift out 3 bytes of data with clock → Pull Latch HIGH.
    .
    .
    .So on … till the 6th column.

I am facing below two problems:

  1. Suppose, I activated the 1st column and shifting out 3 bytes data in this order:

[ Day → Date(ten’s place ) – > Hours (ten’s place) ].

All the digits are displaying at their corresponding rows in the 1st column, but in between, the Hours values is also getting reflected & flickering in the Date’s place. i.e. Row 3 value is reflecting in Row 2 and Row 2 value is reflecting in Row 1.
This problem is associated with all the columns.

  1. Because of the above problem, Row 3 (Day LED) is not reflecting the correct segment. .e.g if my Day value from RTC is 1, then only one segment should glow while others will be OFF, but all the segments are flickering.

I checked my Timer is working fine, and I can increase/decrease the frequency, but I am not able to resolve the flickering/overwriting of one value on another.

I hope I am able to put my problem clearly. Can anyone of You Please help me on this?

My code is as follows:

#define DS_low()  PORTC&=~_BV(1) //PC1 - DATA
#define DS_high() PORTC|=_BV(1)

#define SH_CP_low()  PORTC&=~_BV(2) // PC2 - CLOCK
#define SH_CP_high() PORTC|=_BV(2)

#define ST_CP_low()  PORTC&=~_BV(0) // PC0 - LATCH
#define ST_CP_high() PORTC|=_BV(0)

unsigned char disp_column=0;

void Switch_Column(unsigned char);
void shift_out_byte(unsigned char);
void InitPort(void);
void InitTimer();


int main(void)
{
InitTimer();//initialize Timer for 100ms
InitPort();

while(1)
{} //infinite loop

return (0)

}

void InitPort(void)
{

DDRC = 0x00; //all as output port
DDRD = 0x00; //all as ouput port

}

void Switch_Column(unsigned char num_colum)
{

switch(num_colum)
{
   case 0:

   PORTD=0x20; // switch ON 1st column, PD5, and remaining OFF
   
   ST_CP_low();
   
   shift_out_byte(hrs_digit);
   shift_out_byte(date_digit);
   shift_out_byte(day_segment);
   
   ST_CP_high();
break;

   case 1:

   PORTD=0x10; // switch ON 2nd column, PD4, and remaining OFF
   
   ST_CP_low();
   
   shift_out_byte(hrs_digit);
   shift_out_byte(date_digit);
   shift_out_byte(day_segment); 
   
   ST_CP_high();
break;

   case 2:

   PORTD=0x08; // switch ON 3rd column, PD3, and remaining OFF
   
   ST_CP_low();
   
   shift_out_byte(hrs_digit);
   shift_out_byte(date_digit);
   shift_out_byte(day_segment); 
   
   ST_CP_high();
break;

   case 3:

   PORTD=0x04; // switch ON 4th column, PD2, and remaining OFF
   
   ST_CP_low();
   
   shift_out_byte(hrs_digit);
   shift_out_byte(date_digit);
   shift_out_byte(day_segment); 
   
   ST_CP_high();
break;

   case 4:

   PORTD=0x02; // switch ON 5th column, PD1, and remaining OFF
   
   ST_CP_low();
   
   shift_out_byte(hrs_digit);
   shift_out_byte(date_digit);
   shift_out_byte(day_segment); 
   
   ST_CP_high();
break;

   case 5:

   PORTD=0x01; // switch ON 6th column, PD0, and remaining OFF
   
   ST_CP_low();
   
   shift_out_byte(hrs_digit);
   shift_out_byte(date_digit);
   shift_out_byte(day_segment); 
   
   ST_CP_high();
break;

}


}//end of function Switch_Column()

void shift_out_byte(unsigned char value)
{
			 
unsigned char i;

for(i=0; i<8; i++)
{

      	if( value & (0x01<<i)  )  // insert the LSB first
          {
             DS_high();   		// If first bit is set, switch serial input high
      	  }
          else	
          {
             DS_low();					// Serial input (of 74HC595) low
          }
  
                SH_CP_high();				// trigger clock to shift if in.

	      	SH_CP_low();				// switch clock low again
      		               
}

} //end of function shift_out_byte()


void ISR_TIMER()
{

   Switch_Column(disp_column); //switcj ON each column at a time and shift out the data

   disp_column++;

   if(counter>5) { disp_column= 0;} // reset the counter

   TCNT0=0;//clear the timer interrupt pending flag

}

Sorry that I am too tired at this hour to examine you code.

But I do have to say - you do not show an anode driver, without which you will be severely limited in the current you can supply from the Arduino.

Somewhat more to the point, why are you not using two MAX7219s to do all the work for you? Only one resistor each, plenty of brightness, you do not have to write multiplexing code at all so the present problem would be moot.

And - please do not say that the MAX7219 cannot be used with common anode displays. That is total and ignorant nonsense - it does the job perfectly, far easier than what you are attempting here.

For common anode , I am using ULN2803 for driving positive. I appreciate your suggestion, but at this point of time, I am using ULN2803. Is the problem because of Timer issue? or anything else?

Regards, R.S.

Hi, you must switch off all columns before you shift your 3 bytes. Only switch a column on after the shifting is complete. For example:

switch(num_colum)
{
   case 0:

   PORTD=0; // switch OFF all columns
   
   ST_CP_low();
   
   shift_out_byte(hrs_digit);
   shift_out_byte(date_digit);
   shift_out_byte(day_segment);
   
   ST_CP_high();

   PORTD=0x20; // switch ON 1st column, PD5, and remaining OFF

break;

   case 1:

   PORTD=0; // switch OFF all columns
   
   ST_CP_low();
   
   shift_out_byte(hrs_digit);
   shift_out_byte(date_digit);
   shift_out_byte(day_segment); 
   
   ST_CP_high();

   PORTD=0x10; // switch ON 2nd column, PD4, and remaining OFF

break;

PaulRB: Hi, you must switch off all columns before you shift your 3 bytes. Only switch a column on after the shifting is complete.

No, that is not correct.

You are using 74HC595s which are latched. You only need to update the latch after shifting all the data in.

The correct sequence is:

  • Shift all the new data into the registers.

  • Switch off the previous column.

  • Latch the data.

  • Switch on the new column.

  • Perform all the other processing until time to move to next column.

Other general points.

You are not using the conventional "setup()" and "loop()" functions for some reason.

There is rarely any reason to use interrupts for the multiplexing. Much simpler to do it in the "loop()" and poll the timer for 10 ms increments. Can supply code for this if necessary.

Hi Paul, Thanks for Your suggestion. I will try it. Ok. I will not use Timer ISR. Actually I am using Atmega microcontroller. It would be helpful if You can supply me a piece of code on this.

Thanks. R.S.

Hi Paul, Your idea works !! Thanks. The 1st problem is solved. Now I am only left with the 2nd problem. i.e. displaying Day on the 7 LEDs. As per my diagram, the lowest row has only one 7 segment LED, in which each segment corresponds to each day of weekend. The segments are connected like this to shift register:

QA = seg a QB = seg b QC = seg c QD = seg d QE = seg e QF = seg f QG = seg g

Now as per my code, I am sending the 3rd byte as Day into the shift register. e.g for day = 1, I should send 0b01111111=0x7F. But, if I send this, the "a" is segment not getting ON. Also, if I send 0 as 3rd byte, a Digit "0" get displayed on this. I am not able to understand why this is happening. Can You please provide any help on this. ?

Regards, R.S.