⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 timer.c

📁 一个演示时间中断的例子
💻 C
字号:
/*====================================================================*/
/*                                                                    */
/*  NOTE: Ensure this program is compiled for LARGE model.            */
/*        Non-ANSI stuff is pertinent to Microsoft QuickC v2.5.       */
/*        Porting to another compiler should not be too hard!         */
/*                                                                    */
/*====================================================================*/

/*  What we are going to demonstrate here is the use of two methods of  */
/*  hooking into the timer interrupt mechanism. All PCs have a timer    */
/*  chip with 3 channels. 1 channel is programmed to provide an tick    */
/*  interrupt 18.2 times a second. This is generally refered to as the  */
/*  hardware timer. This timer tick is serviced by an interrupt routine */
/*  accessed by vector 0x08. DOS typically provides the service routine */
/*  so that it can update the DOS clock, etc. What DOS also does is to  */
/*  also route each timer tick through another interrupt vector 0x1C.   */
/*  This is called the user timer. It toos counts at 18.2 times a sec   */
/*  with the idea that it is indenpendant of vector 0x08.               */
/*                                                                      */
/*  What we will do is to use the user vector at 0x1C to control a very */
/*  simple animated cursor (text mode) while the hardware timer at      */
/*  vector 0x08 is re-programmed to provide a faster interrupt rate     */
/*  that we will manage with our own interrupt handler before passing   */
/*  on control to the original DOS handler, and therefore our 0x1C      */
/*  handler, whenever we deem it appropriate.                           */

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <memory.h>

#define FALSE         0
#define TRUE          1

typedef unsigned char BOOL;
typedef unsigned char BYTE;
typedef unsigned int  WORD;

BYTE    *pVideo=(BYTE *)0xB8000000L;       /*  Ptr to base of VGA text RAM  */

/*  As with all interrupt service routines any variables used should be   */
/*  declared either globally or statically. It is NOT a good idea to use  */
/*  variables directly off of the stack - we won't know the state of the  */
/*  stack when we are invoked...                                          */

/*  Global place holders for original vector routines  */

void (interrupt *OldDirectTimer)( void );
void (interrupt *OldUserTimer)( void );

long lCounter;              /*  Simple counter for more accurate delays    */
int  nTickRate;             /*  The actual rate we are getting interrupts  */
int  nTickLimit;            /*  The number of ticks before we call DOS ISR */
int  nTickCount;            /*  Current DOS tick counter                   */
int  nCursorX,nCursorY;     /*  Cursor position                            */

/*===================== Our Interrupt Service Routines ======================*/

void interrupt OurDirectTimer( void )
{
    /*  Decrement our count down timer  */

    if ( lCounter ) lCounter--;         /*  Don't go negative though!  */

    /*  Determine if we call the original DOS handler  */

    if ( --nTickCount<=0 )
    {
        nTickCount = nTickLimit;        /*  Reset ticks to wait  */
        _chain_intr( OldDirectTimer );  /*  Go to old handler!   */
    }

    /*  If we haven't called the original handler, we find ourselves here.    */
    /*  The DOS handler would take care of telling the Programable Interrupt  */
    /*  Controller (PIC) that the interrupt has been serviced. This is called */
    /*  acknowledging the interrupt and MUST be done. If not, the PIC cannot  */
    /*  generate another interrupt for the timer chip or anything else...     */

    outp( 0x20,0x20 );
}

void interrupt OurUserTimer( void )
{
    /*  This routine is guaranteed to be called at approx 18 times per sec.  */
    /*  We will use that fact to control the timing of our animated cursor   */

#define NUM_OF_CURSORS      4       /*  4 cursors to display      */
#define FRAME_DELAY         2       /*  Approx 1/8 sec per frame  */

    static  BYTE    cbFrame=0, cbDelay=0, cbColour=0;
    static  BYTE    cbCursors[NUM_OF_CURSORS]={ '-','/','|','\\' };
    static  WORD    wOffset;

    /*  Are we ready to animate next frame...  */

    if ( cbDelay--==0 )
    {
        cbDelay = FRAME_DELAY;
        if ( ++cbFrame>=NUM_OF_CURSORS ) cbFrame=0;
        if ( ++cbColour>15 )             cbColour=1;
        wOffset = nCursorY*160 + nCursorX*2;
        *(pVideo+wOffset)   = cbCursors[cbFrame];
        *(pVideo+wOffset+1) = cbColour;
    }

    /*  Call the original handler...  */

    _chain_intr( OldUserTimer );
}

void SetTimerRate( int nNewRate )
{
    /*  Reprogram the timer chip to give interrupts at the new rate.  */
    /*  Bear in mind that 18.2 times per sec is the minimum...        */

    _asm   cli              /*  Disable interrupts while we change these  */
                            /*  variables. They are used within the ISR   */
                            /*  itself so may cause problems!             */

    if ( nNewRate<18 ) nNewRate=18;

    nTickRate    = nNewRate;
    nTickLimit   = nNewRate/18;         /*  Number of ticks to give original  */
                                        /*  18 ticks per second               */
    nTickCount   = 0;

    /*  Calculate the 'count down' value for the timer chip itself...  */

    nNewRate     = (nNewRate==18) ? 0 : ((unsigned int) ( 1193180L / ((unsigned long)nNewRate) ));

    /*  Re-program the timer chip...  */

    _asm    mov    dx, 43H
    _asm    mov    al, 34H
    _asm    out    dx, al
    _asm    mov    dx, 40H
    _asm    mov    ax, nNewRate
    _asm    out    dx, al
    _asm    mov    al, ah
    _asm    out    dx, al

    /*  Re-enable interrupts before we finish...  */

    _asm    sti
}

void GetCursorPosition( int *col, int *row )
{
    /*  Ask the video BIOS to give us the current position of the cursor  */

    unsigned char r=0, c=0;

    _asm    mov    ah, 03H
    _asm    mov    bh, 00H
    _asm    int    10H
    _asm    mov    r, dh
    _asm    mov    c, dl

    *row = (int) r;
    *col = (int) c;
}

/*========================= main program ====================================*/

void main( void )
{
    int         i;

    printf( "\n\nTimer Demo\n==========\n\nPress ESCape to abort, or\n\n" );
    printf( "Press 0 to set timer to 18.2Hz\n" );
    for ( i=1; i<10; i++ )
    {
        printf( "Press %d to set timer to %dHz\n",i,i*1000 );
    }
    printf( "\n" );

    /*  Determine the current position of the cursor. We only really want the */
    /*  row since we shall show it in the centre of the line...               */

    GetCursorPosition( &nCursorX,&nCursorY );
    nCursorX = 39;                              /*  Set to centre column  */

    /*  Set things up by installing our handlers  */

    OldDirectTimer  = _dos_getvect( 0x08 );
    OldUserTimer    = _dos_getvect( 0x1C );

    SetTimerRate( 18 );         /*  Initialise our variables  */

    _dos_setvect( 0x08,OurDirectTimer );
    _dos_setvect( 0x1C,OurUserTimer );

    /*  Away we go  */

    while ( 1 )
    {
        /*  Look for a get out  */

        i=0;
        if ( kbhit() && (i=getch())==27 ) break;

        /*  Has something been pressed  */

        if ( i>='0' && i<='9' )
        {
            if ( i=='0' ) SetTimerRate(18); else SetTimerRate( (i-'0')*1000 );
            lCounter = (long)nTickRate;
        }

        /*  If the counter has reached zero, reset it...  */

        if ( lCounter==0L ) lCounter=(long)nTickRate;

        /*  Display message showing counter counting down and confirmation  */
        /*  of tick rate. Note, that \r is used to not cause a line feed... */

        printf( "\r%-8lu Timer Rate: %-6d",lCounter,nTickRate );
    }

    /*  Reinstate the original handlers  */

    SetTimerRate( 18 );             /*  Ensures correct rate!  */

    _dos_setvect( 0x08,OldDirectTimer );
    _dos_setvect( 0x1C,OldUserTimer );

    printf( "\n\nTimer Demo Coded by CyberFrog 8:)\n\n" );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -