//--------------------------------------------------------------------------- // L352.C // Program that uses the 80C206 (8254A) Counter 0 to generate a // periodic interrupt. LED-7 of PC is toggled with each interrupt // 20-times. // // C/C++ code for the SBC188 boards. // C.P. Diduch, March 1999. //--------------------------------------------------------------------------- #define ICW1_MAST 0x0020 // Port Addresses for the 82C206 Interrupt #define ICW2_MAST 0x0021 // cascaded 8259A interrupt controllers. #define ICW3_MAST 0x0021 // MASTER. IR0 of the MASTER is connected #define ICW4_MAST 0x0021 // COUNTER 0 is part of an 8254A timer also #define OCW1_MAST 0x0021 // IR0 of the SLAVE is internally connected #define OCW2_MAST 0x0020 // Real Time Clock. The Real Time Clock also #define MAST_TYPE 0x00F0 // equivalent to the MC146818. #define TIMER_CON 0x0043 // Addresses of the 82C206 Timer Control #define TIMER_0 0x0040 // Register and COUNTER 0. #define KEY_PA 0x0138 // Parallel port 'KEY BOARD' addresses. #define KEY_PB 0x013A #define KEY_PC 0x013C #define KEY_CON 0x013E #define I0CON 0xFF38 // 80C188XL interrupt control register 0. #define EOI 0xFF22 // 80C188XL EOI register. #define I0_TYPE 12 // 80C188XL INT0 TYPE NO. #define TRUE 1 #include #include void int_vect_init(void); // Function prototypes. void ppi_init(void); void int_con_init(void); void timer_8254_init(void); void delay(unsigned MILLISECS); void interrupt far timer_8254_int_handler(void); void interrupt far spurious_master_int_handler(void); void interrupt far spurious_slave_int_handler(void); int N, M; //--------------------------------------------------------------------------- void main(void) { disable(); // Clear interrupt flag. N = 0; // Number of times handler is entered. M = 0; // Number of times LED-7 is toggled. ppi_init(); // Initialize parallel ports. int_vect_init(); // Initialize interrupt vector table. enable(); // Set interrupt flag. timer_8254_init(); // Init COUNTER 0 for interrupt generation. int_con_init(); // Initialize interrupt controllers. while(TRUE) { // Main program simply waits delay(5000); // for interrupts to occur. } } //--------------------------------------------------------------------------- void interrupt far timer_8254_int_handler(void) { N++; if (N > 20) { outportb(KEY_PC, 0x80^inportb(KEY_PC)); // Toggle LED 7 once every // 20 interrupts. N = 0; if ((M++) > 20) { outportb(OCW1_MAST, 0xFF); // Mask off interrupts at master and outport(I0CON, 0x0038); // mask off interrupts at INT0. } } timer_8254_init(); // Reset timer for another interrupt. outportb(OCW2_MAST, 0x60); // Send specific EOI to MASTER for IR0. outport(EOI, 12); // Send EOI to 80C188XL for INT0. } //--------------------------------------------------------------------------- void interrupt far spurious_master_int_handler(void) { outportb(KEY_PC, 0x02^inportb(KEY_PC)); // Toggle LED 1. outportb(OCW2_MAST, 0x67); // Send specific EOI to MASTER for IR7. outportb(EOI, 12); // Send EOI to 80C188XL for INT0. } //--------------------------------------------------------------------------- void int_vect_init(void) { asm { push ds push bx push ax mov ax, 0 mov ds, ax mov bx, 4*MAST_TYPE mov word ptr [bx], offset timer_8254_int_handler mov word ptr [bx+2], seg timer_8254_int_handler mov bx, 4*(MAST_TYPE+7) mov word ptr [bx], offset spurious_master_int_handler mov word ptr [bx+2], seg spurious_master_int_handler pop ax pop bx pop ds } } //--------------------------------------------------------------------------- void timer_8254_init(void) { // Program COUNTER 0 for binary counting and outportb(TIMER_CON, 0x30); // interrupt on Terminal Count. outportb(TIMER_0, 0xFF); // Load CNTR0 with 0xFFFF. This will produce outportb(TIMER_0, 0xFF); // an INTERRUPT after approx = 30 ms, i.e., } // 65535/1.8432 MHz. //--------------------------------------------------------------------------- void ppi_init(void) { // Inititialize 8255A KEYBOARD port outportb(KEY_CON, 0x92); // PA as output. } //--------------------------------------------------------------------------- void int_con_init(void) { outportb(ICW1_MAST, 0x19); // Program master 8259A for level triggered, // cascade operation. outportb(ICW2_MAST, MAST_TYPE); // Program interrupt base type for the // 8259A MASTER as 0xF0 - 0xF7. outportb(ICW3_MAST, 0x04); // Slave controller is connected to IR2. outportb(ICW4_MAST, 0x01); // Program MASTER for single and normal EOI. outportb(OCW1_MAST, 0xFF); // Mask off all MASTER 8259A interrupts. outport(I0CON, 0x0031); // Program 80C188 INT0 for high level trigger, // cascade mode, not special function nested mode, // with priority 000, (highest). outportb(OCW1_MAST, 0xFE); // Unmask IR0 in the MASTER 8259A. } //--------------------------------------------------------------------------- void delay(unsigned MILLISECS) { int M; while (MILLISECS != 0) { M = 375; while (M != 0) { M--; } MILLISECS--; } }