You've broken one of the basic rules of using DOS interrupts: do as little as possible and return as quickly as possible. Calling functions like puts() and clrscr() can, depending on how they're implemented, do a fair amount of work involving other interrupts. If they take too long, another timer interrupt can occur before your interrupt handler returns, and interrupts are NOT reentrant.
Another problem is that i will eventually overflow, which yields (IIRC) unspecified behaviour.
A better way, in your case, would be to move most of the I/O out of the interrupt handler. For example;
Code:
/* Warning: untested code */
volatile unsigned long i;
unsigned long i2;
unsigned char action, last_action = -1;
void interrupt timer_isr(__CPPARGS)
{
i = (i + 1)%60;
}
int main()
{
old_timer_isr = getvect(TIMER);
i = 0;
setvect(TIMER, timer_isr);
while(!kbhit())
{
i2= i;
if (i2 >= 0 && i2 < 14) action = 0;
else if (i2 >= 14 && i2 < 29 || ) action = 1;
else if (i2 >= 29 && i2 < 44) action = 0;
else if (i2 >= 44 && i2 < 59) action = 2;
else action = 0;
if (action != last_action)
{
if (action == 0) clrscr();
else if (action == 1) puts("C++");
else if (action == 2) puts("C");
action = last_action;
}
}
setvect(TIMER, old_timer_isr);
return 0;
}
If you want to be a little more paranoid, you can look into disabling interrupts during your interrupt handler. The means of doing it are compiler dependent, as you need to use assembler. Something like;
Code:
/* Warning: untested code */
void interrupt timer_isr(__CPPARGS)
{
asm "cli"; /* Disable interrupts; method is compiler dependent */
++i;
i = i % 60;
asm "sti"; /* Reenable interrupts; method is compiler dependent */
}
I can't recall offhand if Borland 3.1 needs this (it is possible that the interrupt modifier implies this).