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.

7 segment digital clock with AT89S52 - running slow (not uniform) !!

Status
Not open for further replies.

rajesh279

Junior Member level 3
Joined
Jun 11, 2009
Messages
29
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,521
Dear All,
I have implemented multiplexing method to display HH:MM:SS (Hours, Mins & Secs) on 7 segment LED. I used RTC HT1380 (Holtek) with 32768 Hz crystal.
The AT89S52 controller is running with 11.0592 MHz crystal.
The problem I am facing is : Initially it runs and perfectly matches with the Time, but slowly the seconds is running slow. say, e.g. delay of approx 20 secs in a day (comparing time with my PC).
I tried changing the multiplexing time (ISR invoke period) and also, reading of RTC registers ( periodically each second using Timer delay); but still I am getting time mismatch.

Can someone please let me know how to rectify this problem? Is it a software issue or hardware issue?
Also, a strange thing I observed; I designed and implement the same with Atmega16 controller and there I got perfectly matching time.

I am computing the RTC values in main() -> while() loop , by disabling the Timer and once the RTC calculation is over, re-enabling the Timer.
Please find the below code:

Code:
#include <AT89X52.H>  // Header file for IO operations
#include "intrins.h"

#define SPI_DS	P2_5 //data 26
#define SPI_SH  P2_3//clock-24
#define SPI_ST  P2_2 //latch-23

#define DS_low()  SPI_DS = 0 //Data Low
#define DS_high() SPI_DS = 1 //Data High

#define SH_CP_low()  SPI_SH = 0 //Clock Low
#define SH_CP_high() SPI_SH = 1 //Clock High

#define ST_CP_low()  SPI_ST = 0 //Latch Low
#define ST_CP_high() SPI_ST = 1 //Latch High

/*Positive signals on Digit */

#define COL1 4   //P0.2
#define COL2 8   //P0.3
#define COL3 16  //P0.4
#define COL4 32  //P0.5
#define COL5 64  //P0.6
#define COL6 128 //P0.7

/* main() function starts here*/
int main (void)
{
/*-----------------------------------------------
Initializing the PORTS
-----------------------------------------------*/

InitPORTS();

Initialize_RTC();

InitTimer();

while (1)

  {  

        TR0 = 0; // Disable the Timer
        rtcGetDateTime(); //calculate the RTC date/time from Holtek HT1380
        TR0 = 1; //Enable the Timer
        
        delay_1sec();	   //Delay of 1 sec
  }	

  return 0;
}

/*-------------------------------------------------------------------*/
/*Send the values to shift register*/
void DisplayClock(unsigned char timeval1, unsigned char portval)
{
unsigned char dot1=0,dot2=0;

ST_CP_low();

shiftOut(Digit[timeval1]);

P0 = 0x00; //Switch off the P0 ports ( all the columns/LED)

ST_CP_high();

Delay(1);

ST_CP_low();

P0 = portval; //Enable one column/LED at a time

}

/*Select each LED at a time and send the values*/
void Display(unsigned char disp_count)
{

tens_hrs = hours/10; //hours, minutes & seconds are calculated from RTC rtcGetDateTime() function
unit_hrs = hours%10;
tens_min = minutes/10;
unit_min = minutes%10;
tens_sec = seconds/10;
unit_sec = seconds%10;
		
switch(disp_count)
{

case 1:
        //switch on 1st column and send tens hr 
        DisplayClock(tens_hrs,COL1); // COL1
        
break;

case 2:
        //switch on 2nd column and send unit hr
        DisplayClock(unit_hrs,COL2); // COL1
break;

case 3:
        //switch on 3rd column and send tens min
        DisplayClock(tens_min,COL3); // COL3

break;

case 4:
        //switch on 4th column and send unit min
        DisplayClock(unit_min,COL4); // COL4
break;

case 5:
        //switch on 5th column and send tens sec
        DisplayClock(tens_sec,COL5); // COL5
break;

case 6:
        //switch on 6th column and send unit sec
        DisplayClock(unit_sec,COL6); // COL6
break;
}

}

/*Initialize the Ports*/
void InitPORTS(void)
{

ST_CP_low(); //latch low
SH_CP_low(); //clock low

P0 = 0x00;

clock_init();

}
/*shifting data to shift register*/
void shiftOut(unsigned char val)
{
        unsigned char i;

        for (i = 0; i < 8; i++)  
        {
                        if ( val & (1<<i)) // LSB first
                         {
                                DS_high();
                         }
                        else
                         {  
                                DS_low();
                         }
        
                SH_CP_high();
                Delay(10);
                SH_CP_low();	 		
        }
}

/*Timer 0*/
void InitTimer(void)
{
/*Total machine cycles required to generate 9.7usec ~= 10usec delay = 9 
TH0 fixed value will be 0xFF-0x09 = 0xF6;
Using TH0= 0xF6; an overflow interrupt will generate after each 9 counts.
*/

EA=0;
TMOD = 0x02;
TH0 = 0xF6;
//TL0 = 0x66;
TR0 = 1;
ET0 = 1; 
EA = 1; //Enable Global interrupt
}

/*Timer 0 ISR */
void timer_0 () interrupt 1
{
   prev_sec++;

        if(prev_sec == 8)	 //0.07 ms
        {
                        while(seg_count<6) // Select each LED one by one
                        {
                        seg_count++;
                        Display(seg_count); 
                        }
                        seg_count=0;//reset
          }	
          prev_sec = 0;	
          
   } 
}

/*Function to provide a time delay of approx. 1 second. using Timer 1. */
void delay_1sec(void) 
{ 
int i; 
for(i=0;i<20;i++) 	//=20 for 1 sec
{ 
TL1=0xFD; 
TH1=0x4B; 
TR1=1; 
while(TF1==0); 
TR1=0; 
TF1=0; 
} 
} 

/*End of Code*/

Regards,
Rsj S.
 

Attachments

  • disital_clock_multiplexing.png
    disital_clock_multiplexing.png
    11.7 KB · Views: 104

Two possible explanations for the huge (nearly 2000 ppm) RTC clock deviation:
- wrong crystal circuit with HT1380
- the read routine rtcGetDateTime() is erroneously activating the stop clock flag during read. We should see the respective sources.

You can check the latter point by slowing down the RTC accesses (e.g. 2 or 5 sec delay) for test. If the timing error reduces, it's obviously caused by RTC read accesses.
 

Ok, I will try Your suggestion. Is my approach correct : Disable the Timer before reading RTC and then re-enable ?

Regards,
Raj S.

Two possible explanations for the huge (nearly 2000 ppm) RTC clock deviation:
- wrong crystal circuit with HT1380
- the read routine rtcGetDateTime() is erroneously activating the stop clock flag during read. We should see the respective sources.

You can check the latter point by slowing down the RTC accesses (e.g. 2 or 5 sec delay) for test. If the timing error reduces, it's obviously caused by RTC read accesses.
 

Without disclosing the actual coding of rtcGetDateTime(), everything stays quite vague.

I don't see how stopping the timer or not would affect RTC operation at all.
 

Code for RTC HT1380:

Code:
#include <AT89X52.H>  // Header file for IO operations
#include "intrins.h"
#include "Config_32.h"


#define CMD_SECOND	0x80
#define CMD_MINUTES	0x82
#define CMD_HOURS	0x84
#define CMD_DATE	0x86
#define CMD_MONTH	0x88
#define CMD_DAY		0x8A
#define CMD_YEAR	0x8C
#define CMD_WP		0x8E
#define CMD_BURST	0xBE

#define CMDMASK_WRITE	0x00
#define CMDMASK_READ	0x01

/*5 - 16		  //RESET - P3_6
6 - 21		  //IO - P2_0
7 - 22		  //CLK - P2_1
*/
#define RESET_HI  P3_6 = 1
#define RESET_LO  P3_6 = 0
#define IO_HI 	  P2_0 = 1
#define IO_LO 	  P2_0 = 0
#define SCLCK_HI  P2_1 = 1
#define SCLCK_LO  P2_1 = 0

#define IO_MODE_OUT P2_0 = 0	
#define IO_MODE_INP P2_0 = 1

unsigned char buffer[3];
int n;
unsigned char am_pm_val=0,init_rtc=0;

//unsigned char	year=13, month=12, date=31, day=1, hours=12, minutes=59, seconds=30, prev_sec=99,rawWP=0;
unsigned char year,month,date,day,hours,minutes,seconds,rawWP;

void clock_init(void);
void Initialize_RTC(void);
unsigned char ht1381read(unsigned char);
void rtcSetDateTime(void);
void Set_Time();
void Set_Date();
void rtcGetDateTime(void);
void Rtc_Write_Enable(void);
void Rtc_Write_Protect(void);
unsigned char rtcGetSeconds(void);
unsigned char rtcGetMinutes(void);
unsigned char rtcGetHours(void);
unsigned char rtcGetDate(void);
unsigned char rtcGetMonth(void);
unsigned char rtcGetYear(void);
unsigned char rtcGetDay(void);
void Send_Command_and_Data(unsigned char,unsigned char);

extern void _delay_us(unsigned int);
extern void Delay(unsigned int);
extern volatile unsigned char startdisp;
///////////////////////////////////////////////////////////////////////
void clock_init(void)
{
   RESET_LO;
   IO_LO;
   SCLCK_LO;
}

// Send pulse to SLCK line 
void SCLK_Pulse()
{
  SCLCK_LO;   		   // Set SCLK to low state
  //SCLCK_HI;		       // Set SCLK to high state (rising edge)
  _delay_us(1);       // Keep high state for 10 microseconds
  //SCLCK_LO;   		   // Set SCLK to low state (rising fall)
  //_delay_us(10);       // Keep low state for 10 microseconds
  SCLCK_HI;
}

// Send one byte to RTC (LSB first)
void Send_Byte(unsigned char addr)
{
  unsigned char i;

  IO_MODE_OUT ;		            // Set RE1 (I/O line) as output

  for (i=0;i<8;i++)         	// Start on LSB bit
  {       	    
	  if (addr&0x01)
    	IO_HI;
	  else
      	IO_LO;				    // Set RE1 (I/O line) state

      //SCLK_Pulse();               // Sent pulse on RE0 (SCLK)
	  SCLCK_LO;
	  SCLCK_HI;

	  addr>>=1;
   }
}

// Send Command and Data (2 bytes)
void Send_Command_and_Data(unsigned char addr, unsigned char dataval)
{
  SCLCK_LO;			      // Set SCLK (RE0) to low state
  RESET_HI;			      // Set /REST (RE2) to high state (init of read-cycle)
  Send_Byte(addr);        // Send Command byte
  Send_Byte(dataval);        // Send Data byte (LSB first)
  RESET_LO;               // Set /REST to low state (end of write-cycle)
}


// Send Command byte and read Data byte ..Read a byte from the RTC on the specified address
unsigned char ht1381read(unsigned char addr) 
{

  unsigned char i;
  unsigned char TmpByte=0;

  SCLCK_LO;			      // Set SCLK (RE0) to low state
  //_delay_us(2);
  RESET_LO;
  //_delay_us(2);
  RESET_HI;	 // Set /REST (RE2) to high state (init of read-cycle)
  //_delay_us(2); 

  Send_Byte(addr);        // Send Command byte

  SCLCK_LO;	//pull the clock low

  //_delay_us(1);

  IO_LO;
  
  IO_MODE_INP;		      // Set RE1 (I/O line) as input
  
  for (i=0;i<8;i++)       // Read data bits in I/O line (LSB first)
  {
  	  
	  TmpByte>>=1;

      if (P2_0==1)//(bit_is_set(PINA,6))
      {
	    TmpByte|=0x80;
	  }
	  	  
      //SCLK_Pulse();           // Send pulse on SCLK
	  SCLCK_HI;
	  SCLCK_LO;
  }

  RESET_LO;        			// Set /REST to low state (end of read-cycle)

  return TmpByte;
}

unsigned char rtcGetSeconds(void) {
  unsigned char value;
  value=ht1381read(0x81);  // read seconds
  return (((value>>4)&0x07)*10+(value&0x0f));
}

unsigned char rtcGetMinutes(void) { 
  unsigned char value;
  value=ht1381read(0x83);
  return (((value>>4)&0x07)*10+(value&0x0f));
}

unsigned char rtcGetHours(void) {
  unsigned char value;
  value=ht1381read(0x85);

  //#ifdef HOUR_MODE_12	

  	am_pm_val = ((value>>5)&0x01);

    switch(am_pm_val)//	if(am_pm_val==0)
	{
		case 0:
  		AM_HIGH(); //glow AM LED
		PM_LOW();
		break;
		
		default:
  		AM_LOW(); 
		PM_HIGH(); //glow PM LED
		break;
	 }
  
  	return (((value>>4)&0x01)*10+(value&0x0f));

  //#else 
  
  //	return (((value>>4)&0x03)*10+(value&0x0f));
  
  //#endif

}

unsigned char rtcGetDate(void) {
  unsigned char value;
  value=ht1381read(0x87);
  return (((value>>4)&0x03)*10+(value&0x0f));
}

unsigned char rtcGetMonth(void) {
  unsigned char value;
  value=ht1381read(0x89);
  return (((value>>4)&0x01)*10+(value&0x0f));
}

unsigned char rtcGetYear(void) {
  unsigned char value;
  value=ht1381read(0x8D);
  return (((value>>4)&0x0f)*10+(value&0x0f));
}

unsigned char rtcGetDay(void) {
  unsigned char value;
  value=ht1381read(0x8B);
  return (value&0x0f);  // 1..7
}

unsigned char rtcGetWp(void) {
  unsigned char value;
  value=ht1381read(0x8F);
  return (value&0x80);  // 1..7
}

void rtcGetDateTime(void) {
  seconds=rtcGetSeconds();
  minutes=rtcGetMinutes();
  hours=rtcGetHours();

//  day=rtcGetDay();
//  date=rtcGetDate();
//  month=rtcGetMonth();
//  year=rtcGetYear();
//  rawWP=rtcGetWp();

}

void rtcSetDateTime(void) 
{
	Set_Time();
	Set_Date();
	//Rtc_Write_Protect();
}

// Set time to RTC
void Set_Time()
{
  // Send values in bcd format
  Send_Command_and_Data(0x80, (seconds%10)|((seconds/10)<<4));   // Send seconds (and set CS flag to 0)
  Send_Command_and_Data(0x82, (minutes%10)|((minutes/10)<<4));   // Send minutes

  #ifdef HOUR_MODE_24

  Send_Command_and_Data(0x84, (hours%10)|((hours/10)<<4));       // Send hour (24 Hour mode)

  #else 
  	#ifdef HOUR_MODE_12	  

  	//Send_Command_and_Data(0x84, (0x80 | (hours%10)|((hours/10)<<4))); // Send hour (12 Hour mode)

	if (P3_2 == 1)//(bit_is_set(PINB,0))
	{
		Send_Command_and_Data(0x84, (AM_MODE | (0x80 | (hours%10)|((hours/10)<<4)))); // Set AM mode in hour (12 Hour mode)
	}
	else
	{
		if (P3_3 == 1)//(bit_is_set(PINB,1))
		{
			Send_Command_and_Data(0x84, (PM_MODE | (0x80 | (hours%10)|((hours/10)<<4)))); // Set PM mode in hour (12 Hour mode)
		}
	}

	#endif
  #endif
}

// Set date to RTC
void Set_Date()
{
  // Send values in bcd format
  Send_Command_and_Data(0x86, (date%10)|((date/10)<<4));   // Send Date (1..31)
  Send_Command_and_Data(0x88, (month%10)|((month/10)<<4)); // Send Month (1..12)
  Send_Command_and_Data(0x8A, day); // Send Day (1..7)
  Send_Command_and_Data(0x8C, (year%10)|((year/10)<<4));  // Send Year (0..99)
}


// Set date/tme registers in read-only mode
void Rtc_Write_Protect()
{
  // Set WP flag to high
  //Send_Command_and_Data(0x8E,0x80);
    SCLCK_LO;			      // Set SCLK (RE0) to low state
  _delay_us(2);
  RESET_LO;
  _delay_us(2);
  RESET_HI;	 // Set /REST (RE2) to high state (init of read-cycle)
  _delay_us(2); 
  
  Send_Byte(0x8E);        // Send Command byte
  Send_Byte(0x80); 

  _delay_us(2);

  RESET_LO;	
}

// Enable date/time registers write
void Rtc_Write_Enable()
{
  // Set WP flah to low
  Send_Command_and_Data(0x8E,0x00);
}

 // Set chip flags on first power-on.

void Initialize_RTC()
{
  // Set WP flag to 0 (enable all registers write)
  //Send_Command_and_Data(0x8E,0x00);

  SCLCK_LO;			      // Set SCLK (RE0) to low state
  _delay_us(2);
  RESET_LO;
  _delay_us(2);
  RESET_HI;	 // Set /REST (RE2) to high state (init of read-cycle)
  _delay_us(2); 
  
  Send_Byte(0x8E);        // Send Command byte
  Send_Byte(0x00); 

  _delay_us(2);

  RESET_LO;	
  
  
  rtcGetDateTime();
  if(seconds==0 && minutes==0 && hours==0 && date==1 && month==1 && year==0)
  {
  init_rtc=1; //initialization is done for new RTC first time
  // Set CH flag to 0 (enable crystal oscillator on pins 2 and 3)
  //Send_Command_and_Data(0x80,0x00);

  SCLCK_LO;			      // Set SCLK (RE0) to low state
  _delay_us(2);
  RESET_LO;
  _delay_us(2);
  RESET_HI;	
  _delay_us(2); // Set /REST (RE2) to high state (init of read-cycle)

  Send_Byte(0x80);        // Send Command byte
  Send_Byte(0x00); 
  
  _delay_us(2);

  RESET_LO;	

  // Wait 3 seconds while crystal oscillator become stable
  Delay(25000);
  }
}
 

Can I follow following approach:

1) Timer1 Interrupt of 1 sec to read the RTC values.
2) Timer0 Interrupt to refresh the display (multiplexing).

Regards,
Raj S.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top