CODE: [Copy to clipboard]
polling.c
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#define PortBase 0x2F8
void com_putch(unsigned char);
int com_chkch(void);
main()
{
int c;
unsigned char ch;
outportb(PortBase + 1 , 0); /* Turn off interrupts - Port1 *//* Set COM1: 9600,8,N,1*/
outportb(PortBase + 3 , 0x80);
outportb(PortBase + 0 , 0x0C);
outportb(PortBase + 1 , 0x00);
outportb(PortBase + 3 , 0x03);
clrscr();
while(1) {
c = com_chkch();
if(c!=-1) {
c &= 0xff; putch(c);
if(c=='\n') putch('\r');
}
if(kbhit()) {
ch = getch(); com_putch(ch);
}
}
}
void com_putch(unsigned char ch) {
unsigned char status;
while(1) {
status = inportb(PortBase+5);
if(status&0x01) inportb(PortBase+0); else break;
}
outportb(PortBase,ch);
}
int com_chkch(void) {
unsigned char status;
status = inportb(PortBase+5);
status &= 0x01;
if(status) return((int)inportb(PortBase+0)); else return(-1);
}
使用查询方式的通讯程序适合9600bps以下的应用。CODE: [Copy to clipboard]
serial.c
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <bios.h>
#include "sercom.c"
COM *c;
main()
{
unsigned char ch;
c = ser_init( PORT_B,BAUD_9600,_COM_CHR8,_COM_NOPARITY,4096,4096 );
while(1) {
if( serhit(c)) {
ch = getser(c);
putchar(ch);
}
if(kbhit()) {
ch = getch();
putser(ch,c);
}
}
}
llio.c
#include <stdio.h>
#include <dos.h>
#include <bios.h>
#include <malloc.h>
#define CR 0x0d
#define TRUE 0xff
#define FALSE 0
#define PORT_A 0 /* COM1 */
#define PORT_B 1 /* COM2 */
#define BAUD_9600 _COM_9600
#define BAUD_4800 _COM_4800
#define BAUD_2400 _COM_2400
#define BAUD_1200 _COM_1200
#define BAUD_600 _COM_600
#define BAUD_300 _COM_300
#define BAUD_110 _COM_110
typedef struct {
char ready; /* TRUE when ready */
unsigned com_base; /* 8250 Base Address */
char irq_mask; /* IRQ Enable Mask */
char irq_eoi; /* EOI reply for this port */
char int_number; /* Interrupt # used */
void (_interrupt _far *old)( void ); /* Old Interrupt */
/* Buffers for I/O */
char *in_buf; /* Input buffer */
int in_tail; /* Input buffer TAIL ptr */
int in_head; /* Input buffer HEAD ptr */
int in_size; /* Input buffer size */
int in_crcnt; /* Input <CR> count */
char in_mt; /* Input buffer FLAG */
char *out_buf; /* Output buffer */
int out_tail; /* Output buffer TAIL ptr */
int out_head; /* Output buffer HEAD ptr */
int out_size; /* Output buffer size */
char out_full; /* Output buffer FLAG */
char out_mt; /* Output buffer MT */
} COM;
COM *ser_init( int port,int baud,int bit,int parity,int isize,int osize );
void ser_close( COM *c );
int getsers( COM *c,int len,char *str );
int putsers( char *str, COM *c );
char serline( COM *c );
int getser( COM *c );
char serhit(COM *c);
char putser(char outch,COM *c);
void cntl_rts(int flag,COM *c);
void cntl_dtr(int flag,COM *c);
void clean_ser( COM *c );
#define COM1_BASE 0x03F8
#define COM1_IRQ_MASK 0xEF /*11101111B IRQ 4 For COM1 */
#define COM1_IRQ_EOI 0x64 /* IRQ 4 Spec EOI */
#define COM1_INT_NUM 0x0C /* Int # for IRQ4 */
#define COM2_BASE 0x02F8
#define COM2_IRQ_MASK 0xF7 /*11110111B IRQ 3 For COM2 */
#define COM2_IRQ_EOI 0x63 /* IRQ 3 Spec EOI */
#define COM2_INT_NUM 0x0B /* Int # for IRQ3 */
/* 8250 ACE register defs */
#define THR 0 /* Offset to Xmit hld reg (write) */
#define RBR 0 /* Receiver holding buffer (read) */
#define IER 1 /* Interrupt enable register */
#define IIR 2 /* Interrupt identification reg */
#define LCR 3 /* Line control register */
#define MCR 4 /* Modem control register */
#define LSR 5 /* Line status register */
#define MSR 6 /* Modem status register */
#define SREG(x) ((unsigned)((unsigned)x + c->com_base))
/* 8259 Int controller registers */
#define INTC_MASK 0x21 /* Interrupt controller MASK reg */
#define INTC_EOI 0x20 /* Interrupt controller EOI reg */
#define MAX_PORTS 2 /* # I/O ports (DOS limit) */
static int count = 0;
static COM com_list[MAX_PORTS]; /* I/O data structure */
static COM *com1; /* Pointers for interrupt actions */
static COM *com2;
static COM *com_xfer; /* Transfer interrupt data structure */
COM *ser_init0(int port,char *ibuf,int isize, char *obuf,int osize);
void ser_close0( COM *c );
void (_interrupt _far int_ser1)( void ); /* Int rtn for serial I/O COM 1 */
void (_interrupt _far int_ser2)( void ); /* Int rtn for serial I/O COM 2 */
void (_interrupt _far int_ser_sup)( void ); /* Support int actions */
COM *ser_init( int port,int baud,int bit,int parity,int isize,int osize )
{
unsigned status;
char ch;
COM *c;
char *in_buf,*out_buf;
status = _bios_serialcom(_COM_INIT,port,(bit | parity | _COM_STOP2| baud ));
in_buf = malloc( isize );
if( in_buf == NULL ) return( NULL );
out_buf = malloc( osize );
if( out_buf == NULL ) return( NULL );
c = ser_init0(port,in_buf,isize,out_buf,osize );
clean_ser(c);
return( c );
}
void ser_close(COM *c)
{
int i;
if( !c->ready ) return;
ser_close0(c);
free( c->in_buf );
free( c->out_buf );
}
char serline( COM *c )
{
if( !c->ready ) return(FALSE);
if( c->in_crcnt > 0 ) return( TRUE );
else return( FALSE );
}
int getsers( COM *c,int len,char *str )
{
char ch;
int i;
i = 0;
while( i<len ) {
while( !serhit(c) ) {
if(kbhit()) return( -1 );
}
ch = 0x7f & getser(c);
switch( ch ) {
case 0x0d: str[i++] = '\0';
return( i );
case 0x00:
case 0x0a: break;
default: str[i++] = ch;
break;
}
}
str[i] = '\0';
return( len );
}
int putsers( char *str, COM *c )
{
int n,i,j;
n = strlen( str );
for( i=0; i<n; i++ ) {
while( !putser( str[i],c ) );
}
return( n );
}
char putser( char outch, COM *c )
{
char val;
if( !c->ready ) return(FALSE);
while( !c->out_mt && (c->out_head == c->out_tail) );
if( !c->out_full ) {
c->out_buf[c->out_head++] = outch;
if( c->out_head == c->out_size )
c->out_head = 0; /* Reset buffer circularly */
}
if( c->out_head == c->out_tail ) {
c->out_full = TRUE;
return( FALSE );
} else c->out_full = FALSE;
val = inp( SREG(LCR) ); /* Reset DLAB for IER access */
val &= 0x7F; /* Clear IER access bit */
outp(SREG(LCR),val);
val = inp( SREG(IER) );
if( !(val & 0x02) ) /* Interrupt ON ? */
{
c->out_mt = FALSE; /* Not MT now */
_disable(); /* Interrupts OFF NOW */
outp(SREG(IER),0x03); /* RX & TX interrupts ON */
_enable(); /* Interrupts ON again */
}
return( TRUE );
}
char serhit( COM *c )
{
if( !c->ready ) return(FALSE);
if( !c->in_mt ) return( TRUE );
else return( FALSE );
}
int getser( COM *c )
{
int ch;
if( !c->ready ) return(FALSE);
if( !serhit(c) ) return( 0 );
_disable();
ch = 0xff & c->in_buf[c->in_tail++];
if( c->in_tail == c->in_size ) c->in_tail = 0;
if( c->in_tail == c->in_head ) c->in_mt = TRUE;
if( ch == CR ) /* Keep track of CR's */
c->in_crcnt--;
_enable();
return( ch );
}
void clean_ser( COM *c )
{
_disable();
c->in_head = 0;
c->in_tail = 0;
c->in_mt = TRUE;
c->in_crcnt = 0;
_enable();
}
void cntl_dtr( int flag,COM *c )
{
char val;
if( !c->ready ) return;
val = inp(SREG(MCR));
if( flag ) val |= 1;
else val &= ~1;
outp(SREG(MCR),val);
}
void cntl_rts( int flag, COM *c )
{
char val;
if( !c->ready ) return;
val = inp(SREG(MCR));
if( flag ) val |= 2;
else val &= ~2;
outp(SREG(MCR),val);
}
COM *ser_init0(int port,char *ibuf,int isize, char *obuf,int osize)
{
int i;
char val;
COM *c;
while( port >= MAX_PORTS ) /* Get port # in range */
port--;
for( i=0; i<MAX_PORTS; i++ ) /* Select data structure */
{
if( !com_list[i].ready ) {
c = &(com_list[i]);
break;
}
}
if( i == MAX_PORTS ) /* Not found */
return( NULL );
c->in_buf = ibuf;
c->in_size = isize;
c->in_mt = TRUE;
c->in_head = 0;
c->in_tail = 0;
c->in_crcnt = 0;
c->out_buf = obuf;
c->out_size = osize;
c->out_full = FALSE;
c->out_mt = TRUE;
c->out_head = 0;
c->out_tail = 0;
switch( port ) {
case 0: /* Here set up for COM1 */
c->ready = TRUE;
c->com_base = COM1_BASE;
c->irq_mask = COM1_IRQ_MASK;
c->irq_eoi = COM1_IRQ_EOI;
c->int_number = COM1_INT_NUM;
_disable();
com1 = c;
c->old = _dos_getvect( c->int_number );
_dos_setvect(c->int_number,int_ser1);
break;
case 1: /* Here set up for COM1 */
c->ready = TRUE;
c->com_base = COM2_BASE;
c->irq_mask = COM2_IRQ_MASK;
c->irq_eoi = COM2_IRQ_EOI;
c->int_number = COM2_INT_NUM;
_disable();
com2 = c;
c->old = _dos_getvect( c->int_number );
_dos_setvect(c->int_number,int_ser2);
break;
default: return(NULL); /* Bad port SKIP */
}
val = inp( INTC_MASK );
val &= c->irq_mask;
outp( INTC_MASK, val );
val = inp( SREG(LSR) ); /* Read and discard STATUS */
val = inp( SREG(RBR) ); /* Read and discard DATA */
val = inp( SREG(LCR) ); /* Rst DLAB for IER access */
val &= 0x7F; /* 01111111B */
outp( SREG(LCR),val );
outp( SREG(IER),1); /* Enable Data READY INT */
outp( SREG(MCR),0xB ); /* Enable OUT2,RTS & DTR */
_enable();
return( c );
}
void ser_close0( COM *c )
{
char val;
if( !c->ready ) return;
_disable();
val = inp(INTC_MASK);
val |= ~c->irq_mask;
outp(INTC_MASK,val);
val = inp( SREG(LCR) ); /* Reset DLAB for IER access */
val &= 0x7F; /* Clear IER access bit */
outp(SREG(LCR),val);
val = inp( SREG(RBR) );
val = inp( SREG(LSR));
val = inp(SREG(IIR) );
val = inp(SREG(IER) );
outp(SREG(IER),0); /* Disable 8250 Interrupts */
outp(SREG(MCR),0); /* Disable RTS,DTR and OUT2 */
outp(SREG(MCR),0); /* Disable OUT2 */
_dos_setvect(c->int_number, c->old );
_enable();
c->ready = FALSE;
}
void _interrupt _far int_ser1( void )
{
com_xfer = com1;
_chain_intr( int_ser_sup );
}
void _interrupt _far int_ser2( void )
{
com_xfer = com2;
_chain_intr( int_ser_sup );
}
void _interrupt _far int_ser_sup( void )
{
char val;
char ch;
int ptr;
COM *c;
c = com_xfer;
while( TRUE ) {
val = inp( SREG(LSR) ); /* Read and discard STATUS */
val = inp( SREG(IIR) ); /* Get interrupt status register */
if( val & 0x04 ) /* Receive Interrupt */
{
ptr = c->in_head;
ch = inp( SREG(RBR) );
if( c->in_mt || ptr != c->in_tail ) {
c->in_buf[ptr++] = ch;
if( ptr == c->in_size ) ptr = 0;
c->in_head = ptr;
c->in_mt = FALSE;
if( ch == CR ) /* Count lines */
c->in_crcnt++;
}
} else {
if( val & 0x02 ) /* Transmit Interrupt */
{
if( (!c->out_full) && (c->out_head == c->out_tail) ) {
c->out_mt = TRUE;
val = inp( SREG(LCR) );
val &= 0x7F;
outp(SREG(LCR),val);
outp(SREG(IER),0x01);
/* RX interrupts ON */
} else {
outp(SREG(THR),
c->out_buf[c->out_tail++]);
if( c->out_tail == c->out_size ) c->out_tail = 0;
}
} else return; /* No Interrupt */
}
outp(INTC_EOI,c->irq_eoi);
}
}