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

📄 isr_8250.cpp

📁 DOS下采用中断接收数据的串口通讯的例子,很难找到的好东西!
💻 CPP
字号:
//
//  ISR_8250.CPP
//
//  Source code from:
//
//  Serial Communications: A C++ Developer's Guide, 2nd Edition
//  by Mark Nelson, IDG Books, 1999
//
//  Please see the book for information on usage.
//
//  All of the code used in the 8250 interrupt service
//  routine is found in this file.  The Queue class inline
//  functions are pulled in from QUEUE.H

#include <dos.h>
#include "pc8250.h"
#include "_pc8250.h"
#include "ascii.h"

// Prototypes for the internal handlers called by the ISR.

void handle_modem_status_interrupt( struct isr_data_block *data );
void handle_tx_interrupt( struct isr_data_block *data );
void handle_rx_interrupt( struct isr_data_block *data );

// This is the main body of the 8250 interrupt handler.  It
// sits in a loop, repeatedly reading the Interrupt ID
// Register, and dispatching a handler based on the
// interrupt type.  The line status interrupt is so simple
// that it doesn't merit its own handler.

void isr_8250( struct isr_data_block * data )
{
    _enable();
    for ( ; ; ) {
        switch( inp( data->uart + INTERRUPT_ID_REGISTER ) & 7 ) {
            case IIR_MODEM_STATUS_INTERRUPT :
                handle_modem_status_interrupt( data );
                break;
            case IIR_TX_HOLDING_REGISTER_INTERRUPT :
                handle_tx_interrupt( data );
                break;
            case IIR_RX_DATA_READY_INTERRUPT :
                handle_rx_interrupt( data );
                break;
            case IIR_LINE_STATUS_INTERRUPT :
                data->ls_int_count++;
                data->line_status |= inp( data->uart + LINE_STATUS_REGISTER );
                break;
            default :
                return;
        }
    }
}

// The modem status interrupt handler has to do three
// things.  It has to handle RTS/CTS handshaking.  It has
// to handle DTR/DSR handshaking, and it has to update the
// modem_status member of the isr_data structure.

void handle_modem_status_interrupt( struct isr_data_block *data )
{
    data->ms_int_count++;
        data->modem_status =
            (unsigned int)
                inp( data->uart + MODEM_STATUS_REGISTER );
    if ( data->handshaking & rts_cts )
        if ( data->modem_status & MSR_DELTA_CTS ) // Has CTS changed?
            if ( data->modem_status & MSR_CTS ) {
                if ( data->blocked & rts_cts ) {
                    data->blocked &= ~rts_cts;
                    jump_start( data );
                }
            } else {
                if ( !( data->blocked & rts_cts ) )
                    data->blocked |= rts_cts;
            }
    if ( data->handshaking & dtr_dsr )
        if ( data->modem_status & MSR_DELTA_DSR )
            if ( data->modem_status & MSR_DSR ) {
                if ( data->blocked & dtr_dsr ) {
                    data->blocked &= ~dtr_dsr;
                    jump_start( data );
                }
            } else {
                if ( !( data->blocked & dtr_dsr ) )
                    data->blocked |= dtr_dsr;
            }
}

// The TX interrupt is fairly simple.  All it has to do is
// transmit the next character, if one is available.  Depending
// on whether or not a character is available, it will set or
// clear the tx_running member.  Note that here and in
// jump_start(), the handshake_char gets first shot at going
// out.  This is normally an XON or XOFF.

void handle_tx_interrupt( struct isr_data_block *data )
{
    int c;

    data->tx_int_count++;
    if ( data->send_handshake_char >= 0 ) {
        outp( data->uart + TRANSMIT_HOLDING_REGISTER,
                data->send_handshake_char );
        data->send_handshake_char = -1;
    } else if ( data->blocked ) {
        data->tx_running = 0;
    } else {
        c = data->TXQueue.Remove();
        if ( c >= 0 )
            outp( data->uart + TRANSMIT_HOLDING_REGISTER, c );
        else
            data->tx_running = 0;
    }
}

// The RX interrupt handler is divided into two nearly
// independent sections.  The first section just reads in the
// character that has just been received and stores it in a
// buffer.  If the UART type is a 16550, up to 16 characters
// might be read in.  The next section of code handles the
// possibility that a handshaking trigger has just occurred,
// modifies any control lines or sends an XOFF as needed.

void handle_rx_interrupt( struct isr_data_block *data )
{
    int c;
    int mcr;
    int lsr;

    data->rx_int_count++;
// The receive data section
    for ( ; ; ) {
        c = inp( data->uart + RECEIVE_BUFFER_REGISTER );
        if ( data->handshaking & xon_xoff ) {
            if ( c == XON ) {
                data->blocked &= ~xon_xoff;
                jump_start( data );
                return;
            } else if ( c == XOFF ) {
                data->blocked |= xon_xoff;
                return;
            }
        }
        if ( !data->RXQueue.Insert( (char) c ) )
            data->overflow = 1;
        if ( data->uart_type == UART_8250 )
            break;
        lsr = inp( data->uart + LINE_STATUS_REGISTER );
        data->line_status |= lsr;
        if ( ( lsr & LSR_DATA_READY ) == 0 )
            break;
    }

// The handshaking section

    if ( data->handshaking ) {
        if ( data->RXQueue.InUseCount() > HighWaterMark ) {
            if ( ( data->handshaking & rts_cts ) &&
                  !( data->blocking & rts_cts ) ) {
                mcr = inp( data->uart + MODEM_CONTROL_REGISTER );
                mcr &= ~MCR_RTS;
                outp( data->uart + MODEM_CONTROL_REGISTER, mcr );
                data->blocking |= rts_cts;
            }
            if ( ( data->handshaking & dtr_dsr ) &&
                  !( data->blocking & dtr_dsr ) ) {
                mcr = inp( data->uart + MODEM_CONTROL_REGISTER );
                mcr &= ~MCR_DTR;
                outp( data->uart + MODEM_CONTROL_REGISTER, mcr );
                data->blocking |= dtr_dsr;
            }
            if ( ( data->handshaking & xon_xoff ) &&
                 !( data->blocking & xon_xoff ) ) {
                data->blocking |= xon_xoff;
                if ( data->send_handshake_char == XON ) {
                    data->send_handshake_char = -1;
                } else {
                    data->send_handshake_char = XOFF;
                    jump_start( data );
                }
            }
        }
    }
}

// Any time transmit interrupts need to be restarted, this
// routine is called to do the job.  It gets the interrupts
// running again by sending a single character out the TX
// register manually.  When that character is done
// transmitting, the next TX interrupt will start.  The
// tx_running member of the class keeps track of when we can
// expect another TX interrupt and when we can't.

void jump_start( struct isr_data_block *data )
{
    int c;

// Both tx_running and blocked can change behind my back in the
// ISR, so I have to disable interrupts if I want to be able to
// count on them.

    _disable();
    if ( !data->tx_running ) {
        if ( ( c = data->send_handshake_char ) != -1 )
            data->send_handshake_char = -1;
        else if ( !data->blocked )
            c = data->TXQueue.Remove();
        if ( c >= 0 ) {
            outp( data->uart, c );
            data->tx_running = 1;
        }
    }
    _enable();
}

// *********************** END OF ISR_8250.CPP ***********************

⌨️ 快捷键说明

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