c语言的串口封装类和测试模块

1、说明

       整理电脑,看到很久以前用C写的基于DOS中断的串口封装类,编译器应该是BC31。贴出来供参考。

2、SERIAL.H定义

#ifndef _head_file_serial_h_
#define _head_file_serial_h_

/*  File:  Serial.H
 *  Declare Serial grobal utilities routine.
 */
#define COM1 0
#define COM2 1

#define WAINT      0x04
#define TRUE 1
#define FALSE 0

/* Address of BIOS data area (segment 40h, offset 0) */
#define BIOS_DATA       (0x40)

/* The address of the comm port is in the integer
 * 'comport'. This variable is initialized by reading from
 * the BIOS data area at segment 0x40.
 */
#define IER       (comport + 1)   /* Interrupt Enable Register */
#define IIR       (comport + 2)   /* Interrupt Identification  */
#define LCR       (comport + 3)   /* Line Control Register     */
#define MCR       (comport + 4)   /* Modem Control Register    */
#define LSR       (comport + 5)   /* Line Status Register      */
#define MSR       (comport + 6)   /* Modem Status  Register    */

/* Individual Interrupt Enable Numbers */
#define RDAINT  1
#define THREINT 2
#define RLSINT  4
#define MSINT   8

/* Definitions for the 8259 Programmable Interrupt Controller   */
#define p8259_0 0x20      /* Address of int control register    */
#define p8259_1 0x21      /* Address of int mask register       */
#define END_OF_INT 0x20   /* Nonspecific EOI                    */

/* Line Status Register values */
#define OVERRUN 0x02           /* Over run error                */

/* Modem Control Register value */
#define MCRALL  15             /* (DTR, RTS, OUT1, and OUT2 = 1)*/
#define MCROFF  0              /* Everything off                */

/* Interrupt Enable Register value to turn on/off all int. */
#define IERALL  3  //(RDAINT+THREINT/*+MSINT*/)
#define IEROFF  0

/* Some masks for turning interrupts off */
#define THREOFF 0xfd

/* Interrupt identification numbers */
#define MDMSTATUS       0
#define TXREGEMPTY      2
#define RXDATAREADY     4
#define RLINESTATUS     6

/* Function to get bit 0 of an integer */
#define bit0(i)         (i & 0x0001)

/* Function to turn on interrupt whose "Interrupt Enable Number"
 * is 'i', in case it has been disabled. For example, the
 * THRE interrupt is disabled when an XOFF is received from the
 * remote system.
 */

#define BAUD300     0x0180
#define BAUD600     0x00C0
#define BAUD1200    0x0060
#define BAUD2400    0x0030
#define BAUD3600    0x0020
#define BAUD4800    0x0018
#define BAUD7200    0x0010
#define BAUD9600    0x000C
#define BAUD19200   0x0006
#define BAUD38400   0x0003
#define BAUD57600   0x0002
#define BAUD115200  0x0001

#define DATABITS5   0x00
#define DATABITS6   0x01
#define DATABITS7   0x02
#define DATABITS8   0x03

#define STOPBITS1   0x00
#define STOPBITS15  0x04  //Data Bits = 5
#define STOPBITS2   0x04  //Data Bits != 5

#define PARITYNONE  0x00
#define PARITYODD   0x08
#define PARITYEVEN  0x18

typedef struct comm {
    int comm_port;      // COM1: 0; COM2: 1
    int baud_rate;      // 300 ~ 115200
    int data_bits;      // 5,6,7,8
    int parity;         // None , odd ,even
    int stop_bits;      // 1, 1.5, 2
} COMM;

// Functions accessible by user
int s_setup(int port);                       //初始化
int s_sendchar(int port ,unsigned char ch);  //发送一个字符
int s_rcvchar(int port,unsigned char *ch);   //接收一个字符
int s_cleanup(int port);                     //关闭串口

#endif //_head_file_serial_h_

3、Serial.c实现类

//    串口通信函数库
//    版本 V2.1 , yuming 2001/07/17
//    支持两个串口(COM1 & COM2)同时通信,最高速率115200
//    发送缓冲100字节,接收缓冲1024字节
//    修改记录:
//      2001/12/18 余明 新增支持自定义端口号和自定义中断号的串口,中断号限制在3~7之间
//
#include <dos.h>
#include "serial.h"       // use macro WAINT

#define COMSENDMAXSIZE 100   //串口发送缓冲区长度
#define COMRECEMAXSIZE 1024  //串口接收缓冲区长度

char  Com1ReceBuf[COMRECEMAXSIZE];//COM1 接收缓冲区
char  Com1SendBuf[COMSENDMAXSIZE];//COM1 发送缓冲区
char  *pcom1recebufread;   // 从 COM1 接收缓冲区读一个字符
char  *pcom1recebufwrite;  // 向 COM1 接收缓冲区写一个字符
char  *pcom1sendbufread;   // 从 COM1 接收缓冲区读一个字符
char  *pcom1sendbufwrite;  // 向 COM1 接收缓冲区写一个字符
int   com1recebufcount = 0; //COM1 接收缓冲区中已收到但还没取走的字符个数
int   com1sendbufcount = 0; //已送到COM1 发送缓冲区中但还没发送的字符个数

char  Com2ReceBuf[COMRECEMAXSIZE];//COM2 接收缓冲区
char  Com2SendBuf[COMSENDMAXSIZE];//COM2 发送缓冲区
char  *pcom2recebufread;   // 从 COM2 接收缓冲区读一个字符
char  *pcom2recebufwrite;  // 向 COM2 接收缓冲区写一个字符
char  *pcom2sendbufread;   // 从 COM2 接收缓冲区读一个字符
char  *pcom2sendbufwrite;  // 向 COM2 接收缓冲区写一个字符
int   com2recebufcount = 0; //COM2 接收缓冲区中已收到但还没取走的字符个数
int   com2sendbufcount = 0; //已送到COM2 发送缓冲区中但还没发送的字符个数
int   _IsCom1Open = 0;       // Com1 是否已经打开(初始化)
int   _IsCom2Open = 0;       // Com2 是否已经打开(初始化)

// Communication parameters
//Com1
COMM q_comm1 = {
    COM1,         //    int comm_port;      // COM1: 0; COM2: 1
    BAUD9600,     //    int baud_rate;      // 300 ~ 115200
    DATABITS8,    //    int data_bits;      // 5,6,7,8
    PARITYNONE,   //    int parity;         // None , odd ,even
	STOPBITS1     //    int stop_bits;      // 1, 1.5, 2
};

//Com2
COMM q_comm2 = {
    COM2, BAUD9600, DATABITS8, PARITYNONE, STOPBITS1
};


static void turnon_int(int port ,int i);
static void s_intoff(int port);
static void interrupt   scom1_inthndlr (void );
static void interrupt   scom2_inthndlr (void );

static void interrupt   scom1_inthndlr ( void );
static void interrupt   (*com1oldvector) ();

static void interrupt   scom2_inthndlr ( void );
static void interrupt   (*com2oldvector) ();

// Port Address
//#define NOT_USES_BIOS_DATA
static int       comport[4] = {0x3f8,0x2f8,0x3e8,0x2e8};
static int pckd_comparams = 0x83;

//Communication IRQs, 3,4,5,7
int irq_number1 = 4, irq_number2 = 3; //IRQs

// Machine Parameter Configure
static unsigned char    int_number1,
int_enable_mask1 ,
int_disable_mask1;
// Machine Parameter Configure
static unsigned char    int_number2,
int_enable_mask2 ,
int_disable_mask2 ;

//-------------------------------------------------------------------
unsigned char getIntNo(unsigned char  irq_no)
{
  unsigned char int_tbl[16]={
  0xff,0xff,0xff,0x0b,0x0c,0x0d,0x0e,0x0f,
  0xff,0x71,0x72,0x73,0x74,0xff,0xff,0x77
  };
  return int_tbl[irq_no];
}

//-------------------------------------------------------------------
//  S _ s e t u p
//  Sets up everything for communication. Call this routine
//  after parameter values have been specified (by s_setparams).
//  Return 0 if setup successful, else there were problems.
//
int s_setup(int port)
{
	unsigned char params,intmask;

	COMM q_comm;
	if ( port == COM1 )
	q_comm = q_comm1;
	else
	q_comm = q_comm2;

	if (q_comm.comm_port !=COM1 && q_comm.comm_port != COM2)
	return 1; //Invalid port number.

	// Get port address from BIOS data area and save in 'comport'
#ifndef NOT_USES_BIOS_DATA
	comport[port] = *((int far *)MK_FP(BIOS_DATA, 2*(q_comm.comm_port)));
#endif
	if (comport[port] == 0)
	{
	return 2;//BIOS could not find port.
	}

	//初始化接收发送缓冲区
	if ( port == COM1 )
	{
	pcom1recebufread = Com1ReceBuf;
	pcom1recebufwrite = Com1ReceBuf;
	com1recebufcount = 0;
	pcom1sendbufread = Com1SendBuf;
	pcom1sendbufwrite = Com1SendBuf;
	com1sendbufcount = 0;
	}
	else
	{
	pcom2recebufread = Com2ReceBuf;
	pcom2recebufwrite = Com2ReceBuf;
	com2recebufcount = 0;
	pcom2sendbufread = Com2SendBuf;
	pcom2sendbufwrite = Com2SendBuf;
	com2sendbufcount = 0;
	}

	// Set up masks for 8259A PIC. To enable interrupt from the
	// port this mask is ANDed with the mask register at 21h.
	// To disable, OR the disable mask with the mask register.
	// The interupt number is 8+the IRQ level of the interupt.
	// Com port 1 has IRQ 4, port 2 has IRQ 3.
	if (q_comm.comm_port == COM1)
	{
	   int_number1 = getIntNo(irq_number1);
	   int_disable_mask1 = 0x01 << irq_number1;
	   int_enable_mask1 = ~int_disable_mask1;
	}

	if (q_comm.comm_port == COM2)
	{
	   int_number2 = getIntNo(irq_number2);
	   int_disable_mask2 = 0x01 << irq_number2;
	   int_enable_mask2 = ~int_disable_mask2;
	}


    if ( port == COM1 )
	{
	// Get old interrupt vector and save it.
	com1oldvector = getvect (int_number1);
	// Install new interrupt service routine.
	setvect (int_number1, scom1_inthndlr);
	}
	else
	{
	// Get old interrupt vector and save it.
	com2oldvector = getvect (int_number2);
	// Install new interrupt service routine.
	setvect (int_number2, scom2_inthndlr);
	}

	// Set up communication parameters
	// Configure parameters
	params  = q_comm.data_bits;
	params |= q_comm.parity;
	params |= q_comm.stop_bits;

	outportb(comport[port]+3,0x80);                  //使用除法寄存器
	outportb(comport[port]+1,q_comm.baud_rate/256);  //波特率高8位
	outportb(comport[port]+0,q_comm.baud_rate%256);  //波特率低8位
	outportb(comport[port]+3,params);                //数据位,停止位,奇偶校验位

	// Turn on interrupts from the comm port and setup 8259A
	outportb (comport[port] + 4, MCRALL & 0x0d);   // set up for specified net card

	// Enable all interrupts on the serial card (port = IER)
	outportb (comport[port] + 1, IERALL);

	// Read 8259A's interrupt mask register and write it back after
	// ANDing with int_enable_mask.
	if ( port == COM1 )
		intmask = inportb(p8259_1) & int_enable_mask1; //bit=0 mean enable interrupt
	else
		intmask = inportb(p8259_1) & int_enable_mask2;
	outportb (p8259_1, intmask);

	if ( port == COM1 )
		_IsCom1Open = TRUE;
	else
		_IsCom2Open = TRUE;

	return (0);
}

//--------------------------------------------------------------
//  S _ c l e a n u p
//  Cleanup after comm session is done. Turns off all interrupts.
//
int s_cleanup(int port)
{

	if ( port == COM1 && _IsCom1Open == FALSE)
		return 0;
	else if (  _IsCom2Open == FALSE)
		return 0;

	// Turn off interrupts from serial card
	disable();
	s_intoff(port);
	enable();

	// Restore orginal interrupt vectors
	if ( port == COM1 )
		setvect (int_number1, com1oldvector);
	else
		setvect (int_number2, com2oldvector);

	if ( port == COM1 )
		_IsCom1Open = FALSE;
	else
		_IsCom2Open = FALSE;

	return (1);
}

//打开发送中断请求
static void turnon_int(int port ,int i)
{
	int j;
	if ( port != COM1 && port != COM2 )
		return;

	if (((j=inportb( comport[port]+1 ))&i)==0) //#define IER       (comport + 1)   // Interrupt Enable Register
		outportb( comport[port]+1 ,(j|i));
	return;
}

//-------------------------------------------------------------------
//  S _ i n t o f f
//  Turn off all interrupts after comm session is done.
//  Should be called with interrupts cleared.
//
//关闭发送中断请求
static void s_intoff(int port)
{
	int intmask;

	if ( port != COM1 && port != COM2 )
	return ;
	// First reset the Interrupt Enable Register on the comm card
	outportb(comport[port] + 1, IEROFF);

	// Turn off all bits of Modem Control Register
	outportb(comport[port] + 4, MCROFF);

	// Next disable 8259A from recognizing ints at this IRQ level
	if ( port == COM1 )
		intmask = inportb (p8259_1) | int_disable_mask1;
	else
	   intmask = inportb (p8259_1) | int_disable_mask2;
	outportb(p8259_1, intmask);

	return;
}


//-------------------------------------------------------------------
//  S _ s e n d c h a r
//  Puts a character into transmit queue. Returns 1 if all's ok,
//  0 if there were problems.
//

int s_sendchar(int port ,unsigned char ch)
{
	int int_ie;

	if ( port == COM1 )
	{
	if ( com1sendbufcount >= COMSENDMAXSIZE || _IsCom1Open == FALSE )
		return 0;
	*pcom1sendbufwrite++ = ch;
	if ( pcom1sendbufwrite == Com1SendBuf+COMSENDMAXSIZE )
		pcom1sendbufwrite = Com1SendBuf;
	com1sendbufcount++;
	}
	else
	{
	if ( com2sendbufcount >= COMSENDMAXSIZE || _IsCom2Open == FALSE )
		return 0;
	*pcom2sendbufwrite++ = ch;
	if ( pcom2sendbufwrite == Com2SendBuf+COMSENDMAXSIZE )
		pcom2sendbufwrite = Com2SendBuf;
	com2sendbufcount++;
	}
	turnon_int(port, THREINT);
	return 1;
}

//-------------------------------------------------------------------
//  S _ r c v c h a r
//  Returns a character from the receive queue.
//  Returns -1 if queue is empty.
//

int s_rcvchar(int port,unsigned char *ch)
{
	if (port != COM1 && port != COM2 )
	return FALSE;
	if ( port == COM1 )
	{
	if ( com1recebufcount <= 0 || _IsCom1Open == FALSE ) //缓冲区为空或端口还没打开
		return FALSE;
	*ch = *pcom1recebufread++;
	if ( pcom1recebufread >= Com1ReceBuf + COMRECEMAXSIZE )
		pcom1recebufread = Com1ReceBuf;
	com1recebufcount --;
	return TRUE;
	}
	else
	{
	if ( com2recebufcount <= 0 || _IsCom2Open == FALSE )
		return FALSE;
	*ch = *pcom2recebufread++;
	if ( pcom2recebufread >= Com2ReceBuf + COMRECEMAXSIZE )
		pcom2recebufread = Com2ReceBuf;
	com2recebufcount --;
	return TRUE;
	}
}

static void interrupt   scom1_inthndlr (void )
{
	register int int_flag , intmask,ierval;
	char ch;
	//    intmask = inportb(p8259_1) | int_disable_mask;
	//    outportb (p8259_1, intmask);

	while(TRUE)
	{
	int_flag = inp( comport[COM1] + 2 );    //#define IIR       (comport + 2)   // Interrupt Identification
	if ((int_flag & 0x0001) == 1)
		break;
	switch(int_flag) {
	case RXDATAREADY :
		ch = inportb(comport[COM1]);
		if ( com1recebufcount > COMRECEMAXSIZE )
		break;//缓冲区溢出
		*pcom1recebufwrite++ = ch;
		if ( pcom1recebufwrite >= Com1ReceBuf + COMRECEMAXSIZE )
		pcom1recebufwrite = Com1ReceBuf;
		com1recebufcount++;
		break;

	case TXREGEMPTY  :
		if ( com1sendbufcount > 0  )
		{
		ch = *pcom1sendbufread++ ;
		outportb(comport[COM1], ch);
		if ( pcom1sendbufread >= Com1SendBuf+COMSENDMAXSIZE )
			pcom1sendbufread = Com1SendBuf;
		com1sendbufcount--;
		}

		// Nothing to send -- turn off THRE interrupts
		if ( com1sendbufcount == 0 )
		{
		ierval = inp(comport[COM1]+1);
		if (ierval & THREINT) outportb(comport[COM1]+1, ierval & THREOFF);
		}
		break;
	}
	}
	outportb (p8259_0, END_OF_INT);
}

static void interrupt   scom2_inthndlr (void )
{
	register int int_flag , intmask,ierval;
	char ch;
	//    intmask = inportb(p8259_1) | int_disable_mask;
	//    outportb (p8259_1, intmask);

	while(TRUE)
	{
	int_flag = inp( comport[COM2] + 2 );    //#define IIR       (comport + 2)   // Interrupt Identification
	if ((int_flag & 0x0001) == 1) //
		break;
	switch(int_flag) {
	case RXDATAREADY :
		ch = inportb(comport[COM2]);
		if ( com2recebufcount > COMRECEMAXSIZE )
		break;//缓冲区溢出
		*pcom2recebufwrite++ = ch;
		if ( pcom2recebufwrite >= Com2ReceBuf + COMRECEMAXSIZE )
		pcom2recebufwrite = Com2ReceBuf;
		com2recebufcount++;
	    break;

	case TXREGEMPTY  :
	    if ( com2sendbufcount > 0  )
	    {
		ch = *pcom2sendbufread++ ;
		outportb(comport[COM2], ch);
		if ( pcom2sendbufread >= Com2SendBuf+COMSENDMAXSIZE )
			pcom2sendbufread = Com2SendBuf;
		com2sendbufcount--;
		}
		// Nothing to send -- turn off THRE interrupts
		if ( com2sendbufcount == 0 )
		{
		ierval = inp(comport[COM2]+1);
		if (ierval & THREINT) outportb(comport[COM2]+1, ierval & THREOFF);
		}
		break;
	}
	}
	outportb (p8259_0, END_OF_INT);
}

4、Com.c测试主程序

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>

#include "serial.h"
main()
{
  long sc=0,rc=0,i;
  char ch;

  puts("\n\n\n Serial communication test, com1 send and com2 receive.");
  puts(" press any key start test, ESC exit this program!");
  if ( getch() == 27 )
    return;

  clrscr();
  s_setup(COM1);
  while ( 1 )
  {
    ch = rand()%94+' ';
    s_sendchar ( COM1, ch);
    sc++;
    if ( s_rcvchar( COM1, &ch ) )
     {
      putchar(ch);
      rc++;
      }
    if ( kbhit() ) if ( getch() == 27 ) break;

  }


 s_cleanup(COM1);
 printf("\nTotal Send: %ld, Rece: %ld",sc,rc);
 getch();
 return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值