home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_07_05 / v7n5086a.txt < prev    next >
Text File  |  1989-04-17  |  9KB  |  328 lines

  1.  
  2.  
  3. +-----+       +------------+       +---------+     +-----------+
  4. | OSC |------>| various    |------>| PIT     |---->| interrupt |
  5. |     |  14   | components | 1.19  | timer 0 |  18 | 8 and 1C  |
  6. +-----+ Mhz   +------------+  Mhz  +---------+  Hz +-----------+
  7.  
  8.                             Figure 1
  9.  
  10.  
  11.  
  12. /* -------------------------------------------------------------------------
  13. ** TIMER.H contains the variable declarations and definitions used among
  14. ** timer interrupts.
  15. ** ------------------------------------------------------------------------- */
  16.  
  17.     typedef void (interrupt far * IVEC) (void);
  18.  
  19.     IVEC int1c_dosvec;        /* DOS int 1C vector */
  20.     volatile long countdown_timer;
  21.  
  22.     IVEC int08_dosvec;        /* DOS int 8 vector */
  23.     int int8_passcount;        /* Current interrupt downcounter */
  24.     volatile int timer_count;    /* Application countdown clock timer */
  25.  
  26. #if defined (DEFINE_EXTERNALS)
  27.  
  28. /* Defined interrupt 8 vector table address and port addresses for the
  29. ** master i8259 programmable interrupt controller and the i8253 programmable
  30. ** interval timer.                                 */
  31.  
  32.     const unsigned char **vector_table =    /* 80x86 interrupt table */
  33.         (unsigned char **) 0;
  34.  
  35.     const unsigned isr_8259 = 0x0020;    /* i8259 in-service reg addr */
  36.     const int eoi_8259 = 0x20;        /* i8259 end-of-intrpt instr */
  37.  
  38.     const unsigned cwr_8253 = 0x0043;    /* control word reg addr */
  39.     const unsigned ctr0_8253 = 0x0040;    /* timer 0 counter addr */
  40.     const unsigned set_ctr0_8253 = 0x0036;    /* Binary mode 3 ctr 0 */
  41.  
  42. /* Define speedup factor and the corresponding i8253 counter values.
  43. ** The normal timer 0 interrupt occurs every 54.9 ms. The frequency of that
  44. ** interrupt is increased by a factor of 16 for this application so
  45. ** interrupts occur every 3.43 ms.                         */
  46.  
  47.     const int int8_passcount_reset = 16;
  48.  
  49. /* The input clock frequency is 1.19318 MHz on the PC; the corresponding
  50. ** downcount values for 54.9ms and 3.43ms follow.                 */
  51.  
  52.     const unsigned char int8_newct_msb = 0x10;
  53.     const unsigned char int8_newct_lsb = 0x00;
  54.     const unsigned char int8_dosct_msb = 0x00;
  55.     const unsigned char int8_dosct_lsb = 0x00;
  56.  
  57. #else
  58.  
  59.     const unsigned char **vector_table;
  60.  
  61.     const unsigned isr_8259;
  62.     const int eoi_8259;
  63.  
  64.     const unsigned cwr_8253;
  65.     const unsigned ctr0_8253;
  66.     const unsigned set_ctr0_8253;
  67.  
  68.     const int int8_passcount_reset;
  69.     const unsigned char int8_newct_msb;
  70.     const unsigned char int8_newct_lsb;
  71.     const unsigned char int8_dosct_msb;
  72.     const unsigned char int8_dosct_lsb;
  73.  
  74. #endif
  75.  
  76. /* A macro to convert some number of milliseconds to a downcount value for
  77. ** clock tick interrupt 8.                             */
  78.  
  79. #define COUNTMS(x) ((x * int8_passcount_reset) / 55)
  80.  
  81. /* --------------------------------------------------------------------------
  82. ** LISTING 1 contains examples of changing interrupt vectors safely and the
  83. ** use of 55 ms precision timing.
  84. ** ------------------------------------------------------------------------- */
  85.  
  86. #include <dos.h>
  87. #include <conio.h>
  88. #include <timer.h>
  89.     .
  90.     .
  91.     .
  92.     unsigned int1c = 0x001C;
  93.     extern void interrupt far i1chndlr(void);
  94.     .
  95.     .
  96.     .
  97.  
  98. /* Get the DOS vector for interrupt 1C. Then install the new vector.         */
  99.  
  100.     int1c_dosvec = _dos_getvect(int1c);
  101.     _dos_setvect(int1c, (IVEC) i1chndlr);
  102.     .
  103.     .
  104.     .
  105.  
  106. /* Example: delay for 200 ms.                             */
  107.  
  108.     for (countdown_timer = 200L / 55L; countdown_timer > 0; );
  109.  
  110.     .
  111.     .
  112.     .
  113.  
  114. /* Example: wait for a keyboard stroke for 2 seconds.                 */
  115.  
  116.     for (countdown_timer = 2000L / 55L;
  117.         (countdown_timer > 0) && !kbhit(); )
  118.  
  119.     if (countdown_timer <= 0)    /* Time out on keyboard */
  120.     {
  121.     .
  122.     .
  123.     .
  124.     }
  125.  
  126. /* Restore the interrupt 1C vector.                         */
  127.  
  128.     _dos_setvect(int1c, int1c_dosvec);
  129.     .
  130.     .
  131.     .
  132.  
  133. /* ---------------------------------------------------------------------------
  134. ** LISTING 2 is an interrupt handler for the user timer tick (1C) interrupt.
  135. ** The BIOS time tick interrupt (int 8) service routine (TIMER_INT) updates
  136. ** the time of day clock, checks the diskette motor counter for timeout, and
  137. ** issues a user time tick interrupt (int 1C). This routine decrements a count-
  138. ** down timer maintained in external memory where it may be set and polled by
  139. ** functions within the program.
  140. ** ------------------------------------------------------------------------- */
  141.  
  142. #include <dos.h>
  143. #include <timer.h>            /* Time interrupt decls */
  144.  
  145. #pragma check_stack(off)        /* Don't call chkstk() at entry */
  146. #pragma intrinsic(_enable)
  147.  
  148. void interrupt far i1chndlr()
  149. {
  150.     _enable();            /* Enable interrupts */
  151.     countdown_timer--;        /* Decrement external timer */
  152. }
  153.  
  154. /* --------------------------------------------------------------------------
  155. ** LISTING 3 contains examples of changing the int 8 timing scheme and using
  156. ** increased timing precision.
  157. ** ------------------------------------------------------------------------- */
  158.  
  159. #include <dos.h>
  160. #include <conio.h>
  161. #include <timer.h>
  162.     .
  163.     .
  164.     .
  165.     unsigned char reply;
  166.     unsigned int8 = 0x08;
  167.     int ms300 = COUNTMS(300);
  168.  
  169.     extern void  interrupt far i8swapin(void);
  170.     .
  171.     .
  172.     .
  173.  
  174. /* Get the DOS vector for interrupt 8. Then install a vector to the function
  175. ** that swaps in the new int 8 timing scheme at the next interrupt.         */
  176.  
  177.     int08_dosvec = _dos_getvect(int8);
  178.     _dos_setvect(int8, i8swapin);
  179.     .
  180.     .
  181.     .
  182.  
  183. /* Example: wait 300 ms for pin 2 on LPT1: to go low (0).             */
  184.  
  185.     for (timer_count = ms300, reply = 0x01;
  186.         (timer_count > 0) && (reply == 0x01; )
  187.     {
  188.         reply = inp(0x03BC);        /* Read the port */
  189.         reply &= 0x01;            /* Mask the desired bit */
  190.     }
  191.  
  192.     if (timer_count <= 0)        /* Time out on keyboard */
  193.     {
  194.     .
  195.     .
  196.     .
  197.     }
  198.  
  199. /* Install a vector to the function that reprograms the PIT and restores the
  200. ** DOS handler at the next interrupt.                         */
  201.  
  202.     _dos_setvect(int8, i8swapout);
  203.     .
  204.     .
  205.     .
  206.  
  207. /* ---------------------------------------------------------------------------
  208. ** LISTING 4 is an interrupt handler for the DOS time tick interrupt (int 8).
  209. ** This handler swaps in a new handler for more frequent hardware interrupts
  210. ** while maintaining the normal 54.9 ms system clock updating. The swap occurs
  211. ** at interrupt time so that no system clock tick are lost.
  212. ** ------------------------------------------------------------------------- */
  213.  
  214. #include <dos.h>
  215. #include <conio.h>
  216.  
  217. #include <timer.h>
  218.  
  219. #pragma check_stack(off)
  220. #pragma intrinsic(inp, outp, _enable)
  221.  
  222. void interrupt far i8swapin()
  223. {
  224.  
  225. /* Declare external functions.                             */
  226.  
  227.     extern void interrupt far i08hndlr(void);
  228.  
  229. /* i8259 interrupts are disabled upon entry; re-enable interrupts.
  230. ** Configure the i8253 to run in mode 3 (square wave) with a new 16 bit
  231. ** binary countdown value.                             */
  232.  
  233.     _enable();
  234.  
  235.     outp(cwr_8253, set_ctr0_8253);
  236.     outp(ctr0_8253, int8_newct_lsb);
  237.     outp(ctr0_8253, int8_newct_msb);
  238.  
  239. /* Swap in the new time tick interrupt handler vector. DOS interrupts shouldn't
  240. ** be used within an interrupt handler.                      */
  241.  
  242.     *(vector_table + 8) = (unsigned char *) i08hndlr;
  243.  
  244. /* Initialize pass counter for int 8 handler.                     */
  245.  
  246.     int8_passcount = int8_passcount_reset;
  247.  
  248. /* Go perform DOS time services. DOS does the eoi for the i8259 and the iret.*/
  249.  
  250.     _chain_intr(int08_dosvec);
  251.  
  252. }
  253.  
  254. /* ---------------------------------------------------------------------------
  255. ** LISTING 5 is an interrupt handler for the DOS time tick interrupt (int 8).
  256. ** This handler processes more frequent hardware clock interrupts while
  257. ** maintaining the normal 54.9 ms system clock updating.
  258. ** ------------------------------------------------------------------------- */
  259.  
  260. #include <dos.h>
  261. #include <conio.h>
  262. #include <timer.h>
  263.  
  264. #pragma check_stack(off)
  265. #pragma intrinsic(_enable, outp)
  266.  
  267. void interrupt far i08hndlr()
  268. {
  269.  
  270. /* Enable i8259 interrupts and decrement the application countdown timer.    */
  271.  
  272.     _enable();
  273.     timer_count--;
  274.  
  275. /* If it is time to do the system time chores, reset the pass counter and
  276. ** chain to the normal DOS interrupt vector.
  277. ** The normal DOS handler does an sti and reenables the i8259.             */
  278.  
  279.     if (--int8_passcount == 0)
  280.     {
  281.         int8_passcount = int8_passcount_reset;
  282.         _chain_intr(int08_dosvec);
  283.     }
  284.  
  285.     outp(isr_8259, eoi_8259);
  286. }
  287.  
  288. /* ---------------------------------------------------------------------------
  289. ** LISTING 6 is an interrupt handler for the DOS time tick interrupt (int 8).
  290. ** This handler swaps out the new handler and restores the DOS handler.
  291. ** The swap occurs at interrupt time so that no system clock ticks are lost.
  292. ** ------------------------------------------------------------------------- */
  293.  
  294. #include <dos.h>
  295. #include <conio.h>
  296. #include <timer.h>
  297.  
  298. #pragma check_stack(off)
  299. #pragma intrinsic(inp, outp, _enable)
  300.  
  301. void interrupt far i8swapout()
  302. {
  303. /* i8259 interrupts are disabled at entry; re-enable.
  304. ** Restore the normal DOS operation of i8253 timer 0: mode 3 with a binary
  305. ** downcounter.                                  */
  306.  
  307.     _enable();
  308.     timer_count--;
  309.  
  310.     if (--int8_passcount == 0)
  311.     {
  312.  
  313.         outp(cwr_8253, set_ctr0_8253);
  314.         outp(ctr0_8253, int8_dosct_lsb);
  315.         outp(ctr0_8253, int8_dosct_msb);
  316.  
  317. /* Restore vector for interrupt 8 and do the DOS time service.             */
  318.  
  319.         *(vector_table + 8) = (unsigned char *) int08_dosvec;
  320.         _chain_intr(int08_dosvec);
  321.  
  322.     }
  323.  
  324. /* Restore i8259 interrupts.                             */
  325.  
  326.     outp(isr_8259, eoi_8259);
  327. }
  328.