Industrial Training




A tsr clock



A TSR Clock

A clock which would continuously display the current time at the top right corner of the screen which you have came across in number of applications. For this we will have to first understand how the computer keeps track of time. It has got a timer which keeps ticking. For XTs the timer stops ticking when the computer is put off, whereas form AT onwards it keeps ticking even when the computer is put off. The timer ticks at a rate of 18.2 times per second. Or 1092 times per minute and 65520 times per hour. Whenever the timer an interrupt 8 occurs and the timer routine in ROM-BIOS gets called. This routine increments the tick count which is placed at location number 0x46C to 0x46F in BIOS data area. At the stroke of midnight this count is reset to zero.



In AT onwards when the computer is put off though the contents of 0x46C to 0x46F are lost the time is continuously updated in CMOS RAM since it has a battery backup. When the computer is rebooted the current time is read back into locations 0x46C to 0x46F.
So to display the current time on the screen our TSR should pick up the current tick count from locations 0x46C to 0x46C to 0x46F and the convert it to the corresponding hours, minutes and seconds. Since the time displayed should get continuously updated irrespective of what we are working with, these calculations must be performed in the TSR as shown below.



#include "dos.h"



void interrupt ( *prevtimer )( ) ;
void interrupt mytimer( ) ;



int running = 0 ;
unsigned long far *time = ( unsigned long far * ) 0x46C ;
char far *scr ;
char far *mode ;



main( )
{

/* peek into location 0:410h and determine video mode */
if ( ( *mode & 0x30 ) == 0x30 )

scr = ( char far * ) 0xB0000000 ;

else

scr = ( char far * ) 0xB8000000 ;



prevtimer = getvect ( 8 ) ;
setvect ( 8, mytimer ) ;
keep ( 0, 1000 ) ;

}



void interrupt mytimer( )
{

unsigned char hours, sec, min ;

if ( running == 0 )
{

running = 1;



hours = ( *time / 65520 ) ;
min = ( *time - hours * 65520 ) / 1092 ;
sec = ( *time - hours * 65520 - min * 1092 ) * 10 / 182 ;



if ( sec >= 60 )
{

sec -= 60 ;
min++ ;

if ( min == 60 )
{

min = 0 ;
hours++ ;



if ( hours == 24 )

hours = 0 ;

}

}



/* display digital clock */
writechar ( 48 + hours / 10, 0, 72, 112 ) ;
writechar ( 48 + hours % 10, 0, 73, 112 ) ;
writechar ( ':', 0, 74, 112 ) ;
writechar ( 48 + min / 10, 0, 75, 112 ) ;
writechar ( 48 + min % 10, 0, 76, 112 ) ;
writechar ( ':', 0, 77, 112 ) ;
writechar ( 48 + sec / 10, 0, 78, 112 ) ;
writechar ( 48 + sec % 10, 0, 79, 112 ) ;



running = 0 ;

}



( *prevtimer )( ) ;

}



writechar ( char ch, int row, int col, int attr )
{

*( scr + row * 160 + col * 2 ) = ch ;
*( scr + row * 160 + col * 2 + 1 ) = attr ;

}



This utility works properly only in the text mode. Since the time is to be displayed by directly writing it into VDU memory it is necessary to find out the base address of the VDU memory. This address depends on the initial video mode in which the computer has booted. The initial video mode is stored at bits 4 and 5 location 0x410. If both the bits are on then the computer must have booted in monochrome text mode, otherwise in CGA text mode. Hence, to begin with, in main( ) the initial video mode is determined and the corresponding base address is stored in scr. Next the contents of IVT are changed such that the routine mytimer( ) would get called whenever the timer ticks, and the program is made resident by calling keep( ).



In the function mytimer( ) the value at locations 0x46C to 0x46F is used to calculate hours, minutes and seconds. Since we perform integer arithmetic to calculate these values we may end up with a situation where the value of seconds turns out to be equal to 60. In such a case seconds are reset to 0 and minutes are incremented by 1. A similar adjustment is made in case of minutes and hours. Finally, these values are displayed on the screen using several calls (for each digit ) to the function writechar( ). writechar( ) is capable of writing ASCII value of a digit into VDU memory. Hence while passing any digit 48 is added to it to obtain its ASCII value.



You must have noticed the use of a variable running in mytimer( ). Imagine a situation where the timer has ticked and the calculations are in progress. If at this moment the timer ticks once again (which in all probability it will ) then yet again mytimer( ) would get called and all calculations would begin all over again. Again in the middle of these calculations the timer may tick, mytimer( ) may get called and calculations will be fired third time around. To avoid this situation we can adopt a strategy whereby if the calculations are in progress and the timer ticks we would simply let the normal timer routine get called. This can be achieved by using the variable running as a flag to indicate whether the calculations are being performed or are over. This flag is set to 1 at the beginning of the calculations and reset to 0 after displaying the time.



Hi I am Pluto.