EmbeddedRelated.com
Forums

microcontroller AT89S52 programing advice

Started by bromio July 9, 2006
im required to make a digital clock , i made several codes using
iteration for delay which give not perfect delay. So i want to have
suggestion about how to use timer interrupts to have perfect 1 sec
delay each time. ive written code please see am i using interrupts
correctly..

#include <reg51.h>
#include <stdio.h>
unsigned char
LED[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,125,0x07,0x7F,111};
unsigned char AMPM[2]={119,115};
long int
x,sec=0,min=0,hour=0,lmin=0,hmin=0,c=0;hhour=0,lhour=0,le=0,am=0;
sbit a=P3^0;
sbit b=P3^1;
sbit d=P3^4;
sbit e=P3^7;
sbit f=P3^6;
void init_timer()
{
ET1=1;
TMOD=0x20;
TH1=0x6;
EA=1;
TR1=1;
}

timer1() interrupt 3
{
hmin=min/10;
lmin=min%10;
hhour=hour/10;
lhour=hour%10;
	  while(c<=4000)
	  {
	  le++;
	  c++;
	  switch(le)
      {
         case 1:
            a=0;
            b=1;
            d=1;
            e=1;
			f=1;
		    P0=~LED[hhour];
			break;

		 case 2:
            a=1;
			b=0;
			d=1;
			e=1;
			f=1;
			P0=~LED[lhour];
			break;

		 case 3:
			a=1;
			b=1;
			d=0;
			e=1;
			f=1;
			P0=~LED[hmin];
			break;

		 case 4:
			a=1;
			b=1;
			d=1;
			e=0;
			f=1;
			P0=~LED[lmin];
			break;
		 case 5:
		    a=1;
			b=1;
			d=1;
			e=1;
			f=0;
			P0=~AMPM[am];
			le=0;
			break;
	  }
	  }c=0;
	  sec++;
	  if(sec==60)
	  {sec=0;
	  min++;
	  }
	  if(min==60)
	  {min=0;
	  hour++;
	  }

}
main()
{

   EA=1;
   am=0;
   le=0;
   sec = 0;
   min = 0;
   hour= 0;
   c=0;	   
   init_timer();
   for(;;)
   {}
}

bromio wrote:
> im required to make a digital clock , i made several codes using > iteration for delay which give not perfect delay. So i want to have > suggestion about how to use timer interrupts to have perfect 1 sec > delay each time. ive written code please see am i using interrupts > correctly.. >
<snip code> I take it C is the required language? The timer is a snap in assembler - less than 10 lines. I'm not a C guy but that interrupt routine looks all wrong to me. Oh well. GG
bromio wrote:
> im required to make a digital clock , i made several codes using > iteration for delay which give not perfect delay. So i want to have > suggestion about how to use timer interrupts to have perfect 1 sec > delay each time. ive written code please see am i using interrupts > correctly.. > > #include <reg51.h> > #include <stdio.h> > unsigned char > LED[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,125,0x07,0x7F,111}; > unsigned char AMPM[2]={119,115}; > long int > x,sec=0,min=0,hour=0,lmin=0,hmin=0,c=0;hhour=0,lhour=0,le=0,am=0; > sbit a=P3^0; > sbit b=P3^1; > sbit d=P3^4; > sbit e=P3^7; > sbit f=P3^6; > void init_timer() > { > ET1=1; > TMOD=0x20; > TH1=0x6; > EA=1; > TR1=1; > } > > timer1() interrupt 3 > { > hmin=min/10; > lmin=min%10; > hhour=hour/10; > lhour=hour%10; > while(c<=4000) > { > le++; > c++; > switch(le) > { > case 1: > a=0; > b=1; > d=1; > e=1; > f=1; > P0=~LED[hhour]; > break; > > case 2: > a=1; > b=0; > d=1; > e=1; > f=1; > P0=~LED[lhour]; > break; > > case 3: > a=1; > b=1; > d=0; > e=1; > f=1; > P0=~LED[hmin]; > break; > > case 4: > a=1; > b=1; > d=1; > e=0; > f=1; > P0=~LED[lmin]; > break; > case 5: > a=1; > b=1; > d=1; > e=1; > f=0; > P0=~AMPM[am]; > le=0; > break; > } > }c=0; > sec++; > if(sec==60) > {sec=0; > min++; > } > if(min==60) > {min=0; > hour++; > } > > } > main() > { > > EA=1; > am=0; > le=0; > sec = 0; > min = 0; > hour= 0; > c=0; > init_timer(); > for(;;) > {} > }
A loop in an interrupt service routine? No. Interrupt service routines should do what is needed at that time and nothing more. They should be as quick as possible.
bromio wrote:
> im required to make a digital clock , i made several codes using > iteration for delay which give not perfect delay. So i want to have > suggestion about how to use timer interrupts to have perfect 1 sec > delay each time. ive written code please see am i using interrupts > correctly.. > > #include <reg51.h> > #include <stdio.h> > unsigned char > LED[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,125,0x07,0x7F,111}; > unsigned char AMPM[2]={119,115}; > long int > x,sec=0,min=0,hour=0,lmin=0,hmin=0,c=0;hhour=0,lhour=0,le=0,am=0; > sbit a=P3^0; > sbit b=P3^1; > sbit d=P3^4; > sbit e=P3^7; > sbit f=P3^6; > void init_timer() > { > ET1=1; > TMOD=0x20; > TH1=0x6; > EA=1; > TR1=1; > } > > timer1() interrupt 3 > { > hmin=min/10; > lmin=min%10; > hhour=hour/10; > lhour=hour%10; > while(c<=4000) > { > le++; > c++; > switch(le) > { > case 1: > a=0; > b=1; > d=1; > e=1; > f=1; > P0=~LED[hhour]; > break; > > case 2: > a=1; > b=0; > d=1; > e=1; > f=1; > P0=~LED[lhour]; > break; > > case 3: > a=1; > b=1; > d=0; > e=1; > f=1; > P0=~LED[hmin]; > break; > > case 4: > a=1; > b=1; > d=1; > e=0; > f=1; > P0=~LED[lmin]; > break; > case 5: > a=1; > b=1; > d=1; > e=1; > f=0; > P0=~AMPM[am]; > le=0; > break; > } > }c=0; > sec++; > if(sec==60) > {sec=0; > min++; > } > if(min==60) > {min=0; > hour++; > } > > } > main() > { > > EA=1; > am=0; > le=0; > sec = 0; > min = 0; > hour= 0; > c=0; > init_timer(); > for(;;) > {} > } >
Too much in the interrupt. Set a flag or inc a counter in the interrupt. Do the work in main. I assume this is a school project. CPU Xtals are do not have the tolerance to keep time very well. It can be off by several minutes a month.
On Sun, 09 Jul 2006 16:44:34 -0700, GaryKato@aol.com wrote:

> > bromio wrote: >> >> LED[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,125,0x07,0x7F,111}; >> unsigned char AMPM[2]={119,115}; >> >> timer1() interrupt 3 >> { >> hmin=min/10; >> lmin=min%10; >> hhour=hour/10; >> lhour=hour%10; >> while(c<=4000) >> { >> le++; >> c++; >> switch(le) >> { >> <case stmt deleted> >> } >> }c=0; >> sec++; >> if(sec==60) >> {sec=0; >> min++; >> } >> if(min==60) >> {min=0; >> hour++; >> } >> >> } >> main() >> { >> >> EA=1; >> am=0; >> le=0; >> sec = 0; >> min = 0; >> hour= 0; >> c=0; >> init_timer(); >> for(;;) >> {} >> } > > A loop in an interrupt service routine? No. Interrupt service routines > should do what is needed at that time and nothing more. They should be > as quick as possible.
He's using the loop to refresh the LEDs and provide a delay, I think. Commented code is usually required for assignments--Profs and TAs hate to guess what code is supposed to do. That code should not be in the ISR. If you are trying to adjust the ISR rate to once per second this way, give up. There are other ways to get a one second (more or less) tick for your clock, and none of them involve running off a second in your ISR. Hint: think in terms of averages for one approach. How does am ever change? How do you expect to reset this clock--wait until midnight and plug it in? Why do you use different bases for values in LED? Why does LED use a different base than (some of) AMPM? The if-clauses at the end of the ISR should logically be nested--only if sec==60 does min need to be checked for 60. I wouldn't expect much of a grade out of this effort. :-/ _Rethink_ then rewrite. ~Dave~
On 9 Jul 2006 14:29:00 -0700, "bromio" <bromio_47@yahoo.com> wrote:

>im required to make a digital clock , i made several codes using >iteration for delay which give not perfect delay. So i want to have >suggestion about how to use timer interrupts to have perfect 1 sec >delay each time. ive written code please see am i using interrupts >correctly.. >
[Code Snipped]
> >timer1() interrupt 3 >{ >hmin=min/10; >lmin=min%10; >hhour=hour/10; >lhour=hour%10; > while(c<=4000) > { > le++; > c++; > switch(le)
[more code snipped] Doing devides on a 8051 in an interrupt routine is not a good idea. Using a switch statement in an interrupt routine on a 8051 using many of the 8051 compilers not a good idea. (Switch statement code is not re-entrant, so if you use a switch statement anywhere else you will have very strange bugs) Do the minimum in the interrupt routine. In stead of doing a divide and a mod, rather have a timer counter that you increment every interrupt. You then increment the "second" interrupt every n number of timer interrupts. something like: int_counter++; if(int_count>=NUMBER_OF_INTS_PER_SECOND) { int_counter=0; sec_counter++; if(sec_counter>=60) { sec_counter=0; min_counter++; } } Remember that if you are reading these variables from outside the interrupt routine, they should be volatile. Regards Anton Erasmus