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

📄 rcomm.c

📁 一个演示串口通讯的例子
💻 C
字号:
#include <stdio.h>
#include <dos.h>
#include <int.h>
#include <malloc.h>
#include <memory.h>

#define TRUE          1
#define FALSE         0

typedef unsigned char BYTE;
typedef unsigned char BOOL;

#include "rcomm.h"

#define  THR        0
#define  RDR        0
#define  BRDL       0
#define  BRDH       1
#define  IER        1
#define  IIR        2
#define  LCR        3
#define  MCR        4
#define  LSR        5
#define  MSR        6

void COM_ISR( int nPort );

int COM1_ISR( struct INT_DATA *pID )
{
    COM_ISR(CP_COM1);
    return( 1 );
}

int COM2_ISR( struct INT_DATA *pID )
{
    COM_ISR(CP_COM2);
    return( 1 );
}

int COM3_ISR( struct INT_DATA *pID )
{
    COM_ISR(CP_COM3);
    return( 1 );
}

int COM4_ISR( struct INT_DATA *pID )
{
    COM_ISR(CP_COM4);
    return( 1 );
}

typedef struct tagCYCLIC_BUFFER
{
    BYTE        *pBuffer;
    int         nLength;
    int         nCount;
    BYTE        *pHead, *pTail, *pLimit;
} CYCLIC_BUFFER;

typedef struct tagSERIAL_PORT
{
    BOOL            bEnabled;
    CYCLIC_BUFFER   inBuffer;
    CYCLIC_BUFFER   outBuffer;
} SERIAL_PORT;

static volatile SERIAL_PORT     Ports[4];
static volatile unsigned int    wIOPortBase[4]={ 0x03f8, 0x02f8, 0x03e8, 0x02e8 };
static volatile unsigned int    wPortVector[4]={ 0x0c,   0x0b,   0x0c,   0x0b   };
static volatile unsigned int    wPortIRQ[4]   ={ 0x04,   0x03,   0x04,   0x03   };
static BYTE                     cbIRQMask[4];
static int                      (*dwCOMISRs[4])(struct INT_DATA *pID)={ COM1_ISR,COM2_ISR,COM3_ISR,COM4_ISR };

static BOOL CycCreateBuffer( CYCLIC_BUFFER *pCyc,int nSize )
{
    /*  Create and initialise buffer  */

    if ( (pCyc->pBuffer=(BYTE *)malloc(nSize))==NULL ) return( FALSE );
    pCyc->nLength = nSize;
    pCyc->pLimit  = pCyc->pBuffer + nSize - 1;
    pCyc->pHead   = pCyc->pTail = pCyc->pBuffer;
    pCyc->nCount  = 0;

    return( TRUE );
}

static void CycDeleteBuffer( CYCLIC_BUFFER *pCyc )
{
    free( pCyc->pBuffer );
}

static void CycFlushBuffer( CYCLIC_BUFFER *pCyc )
{
    /*  Flush contents of cyclic buffer  */

    pCyc->pHead   = pCyc->pTail = pCyc->pBuffer;
    pCyc->nCount  = 0;
}

static int  CycReadBuffer( CYCLIC_BUFFER *pCyc,void *pBuffer,int nCount )
{
    /*  Read nCount bytes from cyclic buffer  */

    register BYTE   *pDest=(BYTE *)pBuffer;
    int             nRead=0;

    while ( pCyc->nCount && nRead<nCount )
    {
        *pDest++ = *pCyc->pHead++;
        pCyc->nCount--;
        nRead++;
        if ( pCyc->pHead>pCyc->pLimit ) pCyc->pHead=pCyc->pBuffer;
    }

    return( nRead );
}

static int  CycWriteBuffer( CYCLIC_BUFFER *pCyc,void *pBuffer,int nCount )
{
    /*  Write nCount bytes to cyclic buffer  */

    register BYTE   *pSource=(BYTE *)pBuffer;
    int             nWritten=0;

    while ( pCyc->nCount<pCyc->nLength && nWritten<nCount )
    {
        *pCyc->pTail++ = *pSource++;
        pCyc->nCount++;
        nWritten++;
        if ( pCyc->pTail>pCyc->pLimit ) pCyc->pTail=pCyc->pBuffer;
    }

    return( nWritten );
}

static void COM_ISR( int wPort )
{
    volatile int            wBase;
    volatile BYTE           cbChar;
    volatile CYCLIC_BUFFER  *pCyc;

    outp( 0x20,0x20 );

    if ( Ports[wPort].bEnabled )
    {
        wBase   = wIOPortBase[wPort];
        cbChar  = inp(wBase+IIR)&0x06;

        switch( cbChar )
        {
            case 0x04:
                /*  Character received  */
                pCyc = &Ports[wPort].inBuffer;
                if ( pCyc->nCount<pCyc->nLength )
                {
                    *pCyc->pTail++ = (BYTE)(unsigned int)inp(wBase+RDR);
                    pCyc->nCount++;
                    if ( pCyc->pTail>pCyc->pLimit ) pCyc->pTail=pCyc->pBuffer;
                }
                break;
            case 0x02:
                /*  Transmit  */
                pCyc = &Ports[wPort].outBuffer;
                if ( pCyc->nCount==0 )
                {
                    /*  Empty - disable THR empty interrupt  */

                    outp( wBase+IER,0x01 );
                }
                else
                {
                    outp( wBase+THR,(unsigned int)*pCyc->pHead );
                    pCyc->nCount--;
                    if ( ++pCyc->pHead>pCyc->pLimit ) pCyc->pHead=pCyc->pBuffer;
                }
                break;
        }

        /*  Edge-trigger IER  */

        cbChar = (BYTE)inp(wBase+IER);
        outp( wBase+IER,0x00 );
        outp( wBase+IER,(unsigned int)cbChar );
    }
}

BOOL COM_Open( COM_PORT cpPort,unsigned long nBaud,COM_DATA_BITS cdbBits,COM_STOP_BITS csbStop,COM_PARITY cbParity,int nBuffSize )
{
    int     wBase;

    if ( cpPort<CP_COM1 || cpPort>CP_COM4 ) return( FALSE );
    if ( Ports[cpPort].bEnabled ) return( FALSE );
    if ( cdbBits!=CDB_8_BITS && cdbBits!=CDB_7_BITS ) return( FALSE );
    if ( csbStop!=CSB_1_BIT && csbStop!=CSB_2_BIT ) return( FALSE );
    if ( cbParity!=CP_NO_PARITY && cbParity!=CP_ODD_PARITY && cbParity!=CP_EVEN_PARITY ) return( FALSE );
    if ( nBuffSize==0 || nBaud<300 ) return( FALSE );

    if ( !CycCreateBuffer(&Ports[cpPort].inBuffer,nBuffSize) ) return( FALSE );
    if ( !CycCreateBuffer(&Ports[cpPort].outBuffer,nBuffSize) )
    {
        CycDeleteBuffer( &Ports[cpPort].inBuffer );
        return( FALSE );
    }

    Ports[cpPort].bEnabled = TRUE;

    /*  Record original interrupt enable mask  */

    cbIRQMask[cpPort] = inp(0x21)&(0x01<<wPortIRQ[cpPort]);

    /*  Intercept the vector  */

    int_intercept( wPortVector[cpPort],dwCOMISRs[cpPort],0 );

    /*  Enable interrupts in PIC  */

    _asm    cli

    if ( cbIRQMask[cpPort] )
    {
        outp( 0x21,inp(0x21)&((~cbIRQMask[cpPort])&0xff) );
    }

    /*  Enable UART to interrupt on data ready  */

    wBase = wIOPortBase[cpPort];
    outp( wBase+LCR,inp(wBase+LCR)&0x7f );

    /*  Test the UART  */

    outp( wBase+IER,0x00 );
    if ( inp(wBase+IER)!=0x00 )
    {
        _asm  sti
        COM_Close( cpPort );
        return( FALSE );
    }

    /*  Clear UART status and data registers  */

    do
    {
        inp( wBase+RDR );
        inp( wBase+LSR );
        inp( wBase+MSR );
    }
    while ( !(inp(wBase+IIR)&CS_RX_READY) );

    /*  Enable MCR interrupts  */

    outp( wBase+MCR,inp(wBase+MCR)|0x08 );

    /*  Set baud rate  */

    nBaud = 0x0001C200L / nBaud;

    outp( wBase+LCR,0xff );
    outp( wBase+BRDL,nBaud&0xff );
    outp( wBase+BRDH,(nBaud>>8)&0xff );
    outp( wBase+LCR,(cbParity|cdbBits|csbStop)&0x7f );
    _asm sti

    /*  Flush out buffers before return  */

    COM_Flush( cpPort,TRUE,TRUE );

    return( TRUE );
}

BOOL COM_Close( COM_PORT cpPort )
{
    int     wBase;

    if ( CP_COM1<=cpPort && cpPort<=CP_COM4 && Ports[cpPort].bEnabled )
    {
        BYTE    cbMask=cbIRQMask[cpPort]&(0x01<<wPortIRQ[cpPort]);

        /*  Restore interrupt in PIC  */

        if ( cbMask ) outp( 0x21,inp(0x21)|cbMask );

        /*  Disable UART interrupts  */

        wBase = wIOPortBase[cpPort];

        outp( wBase+LCR,inp(wBase+LCR)&0x7f );
        outp( wBase+IER,0x00 );
        outp( wBase+MCR,inp(wBase+MCR)&0xf7 );

        /*  Restore interrupt handler  */

        int_restore( wPortVector[cpPort] );

        /*  Free buffers  */

        CycDeleteBuffer( &Ports[cpPort].inBuffer );
        CycDeleteBuffer( &Ports[cpPort].outBuffer );

        Ports[cpPort].bEnabled = FALSE;

        return( TRUE );
    }

    return( FALSE );
}

BOOL COM_Flush( COM_PORT cpPort, BOOL bFlushInput, BOOL bFlushOutput )
{
    if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
    {
        if ( Ports[cpPort].bEnabled )
        {
            if ( bFlushInput ) CycFlushBuffer( &Ports[cpPort].inBuffer );
            if ( bFlushOutput) CycFlushBuffer( &Ports[cpPort].outBuffer );
            return( TRUE );
        }
    }
    return( FALSE );
}

int COM_Write( COM_PORT cpPort,void *pBuffer,int nCount )
{
    if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
    {
        if ( Ports[cpPort].bEnabled )
        {
            nCount = CycWriteBuffer(&Ports[cpPort].outBuffer,pBuffer,nCount);
            if ( nCount )
            {
                /*  Enable THR empty interrupt  */

                outp( wIOPortBase[cpPort]+IER,0x03 );
            }
            return( nCount );
        }
    }
    return( 0 );
}

int COM_Read( COM_PORT cpPort,void *pBuffer,int nCount )
{
    if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
    {
        if ( Ports[cpPort].bEnabled )
        {
            return( CycReadBuffer(&Ports[cpPort].inBuffer,pBuffer,nCount) );
        }
    }
    return( 0 );
}

BOOL COM_IOCtrl( COM_PORT cpPort,BOOL bAssertRTS, BOOL bAssertDTR )
{
    if ( CP_COM1<=cpPort && cpPort<=CP_COM4 && Ports[cpPort].bEnabled )
    {
        int     nHandshake=0x08;

        if ( bAssertRTS ) nHandshake|=0x02;
        if ( bAssertDTR ) nHandshake|=0x01;

        outp( wIOPortBase[cpPort]+MCR,nHandshake );

        return( TRUE );
    }
    return( FALSE );
}

int COM_InQueue( COM_PORT cpPort )
{
    if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
    {
        if ( Ports[cpPort].bEnabled ) return( Ports[cpPort].inBuffer.nCount );
    }
    return( 0 );
}

int COM_OutQueue( COM_PORT cpPort )
{
    if ( CP_COM1<=cpPort && cpPort<=CP_COM4 )
    {
        if ( Ports[cpPort].bEnabled ) return( Ports[cpPort].outBuffer.nCount );
    }
    return( 0 );
}

COM_STATUS COM_Status( COM_PORT cpPort )
{
    if ( CP_COM1<=cpPort && cpPort<=CP_COM4 && Ports[cpPort].bEnabled )
    {
        int     wBase=wIOPortBase[cpPort];

        return( (inp(wBase+MSR)<<8)|inp(wBase+LSR) );
    }

    return( 0 );
}

⌨️ 快捷键说明

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