TC串口通信程序的设计与实现

        串口通信是一个讨论了很久的问题,我曾经用VC6.0,VS2003, VS2005开发过串口程序。同样也写过单片机的串口通信程序。这次用纯C语言写了一个,放上来与大家分享。
         该程序实现的原理是利用TC库函数outportb与inportb来读写对串口芯片的寄存器进行读写和配置,由于我一起开发过单片机的串口通信程序,所以这种方法我比较容易理解。我参考了网上很多资料,所以代码中有跟网上类似的地方,其中也做了一些优化和修改。
         程序利用中断接收串口数据,利用查询方式来发送数据,可以自发自收。详细源代码如下:
#include  < stdio.h >
#include 
< conio.h >
#include 
< stdlib.h >
#include 
< dos.h >

#define  MAXBUFFERSIZE 1024                     /* 数据缓冲区大小 */
unsigned 
char  DataBuffer[MAXBUFFERSIZE];        /* 数据缓冲区 */
int  regBASE;                                    /* 串口基地址 */
int  inBuffer  =   0 ;                               /* 接收计数 */
int  outBuffer  =   0 ;                              /* 发送计数 */
/* 以下枚举为串口相关设置选项 */
typedef 
enum   {COM1,COM2}  COM;                   /* 串口号 */
/* 奇偶校验类型 */
typedef 
enum   {NONE=0,ODD=1,EVEN=3,MARK=5,SPACE=7}  PARITY;
/* 数据位 */
typedef 
enum   {BIT5,BIT6,BIT7,BIT8}  DATABIT;
/* 停止位 */
typedef 
enum   {BIT1=0,BIT15=1,BIT2=1}  STOPBIT;
/* 自定义bool数据类型 */
typedef 
enum   {false,true}   bool ;
/* 8250寄存器偏移地址 */
typedef 
enum   {RXR=0,TXR=0,IER=1,IIR=2,LCR=3,MCR=4,LSR=5,MSR=6,LSB=0,MSB=1}
              regSeriesCOMM;
/* 串口结构体 */
typedef 
struct
{
    COM     comNumber;              
/* 串口号 */
    
long    comBps;                 /* 波特率 */
    PARITY  comParity;              
/* 奇偶校验类型 */
    DATABIT comDataBit;             
/* 数据位 */
    STOPBIT comStopBit;             
/* 停止位 */
}
 SeriesCOMM;

/* 设置波特率 */
bool  SettingBPS( long  bps);
/* 获取波特率 */
long  GettingBPS();
/* 初始化串口 */
bool  InitSeriesCOMM(  long  bps,
                     DATABIT databit,
                     PARITY paritycheck,
                     STOPBIT stopbit);
/* 打开串口 */
bool  OpenCOMM( COM com,
               
long  bps,
               DATABIT databit,
               PARITY paritycheck,
               STOPBIT stopbit);
/* 关闭串口 */
void  CloseCOMM();
/* 发送数据 */
void  SendByte(unsigned  char  data);
/* 中断服务程序 */
void  interrupt far asyncint();
/* 中断向量表 */
void  interrupt( * asyncoldvect)();
/* 读取数据 */
unsigned 
char  ReadData( void );

int  main()
{
    unsigned 
char temp;         /* 临时变量 用于缓存接收数据            */
    
char buffer[10];            /* 临时缓冲区 用于接收控制台输入数据    */
    
char * pParme;              /* 控制台输入字符串指针                 */
    
char sendBuffer[1024];      /* 发送数据缓冲区                       */
    SeriesCOMM thisComm;        
/* 串口结构 保存当前操作串口数据        */

    
/********************************************************************/
    
/* 该段程序用于向用户获取串口初始化配置 */
    
/* 根据用户输入的数据来配置串口 */
    printf(
"Enter the Seriec COM Number(COM1:1,COM2):");  /* 获取要使用的串口 */
    pParme 
= cgets(buffer);
    
if( atoi(pParme) == 2)
        thisComm.comNumber 
= COM2;
    
else
        thisComm.comNumber 
= COM1;
    
/* 获取波特率 */
    printf(
" Enter the Seriec COM BPS(eg:2400):");
    pParme 
= cgets(buffer);
    thisComm.comBps 
= atol(pParme);
    
/* 获取数据位位数 */
    printf(
" Please Choice the Data Bits: ");
    printf(
"5 bits:  0 6 bits:  1 7 bits:  2 8 bits:  3 ");
    pParme 
= cgets(buffer);
    
if ( atoi(pParme) == 0)
        thisComm.comDataBit 
= BIT5;
    
else if ( atoi(pParme) == 1)
        thisComm.comDataBit 
= BIT6;
    
else if ( atoi(pParme) == 2)
        thisComm.comDataBit 
= BIT7;
    
else
        thisComm.comDataBit 
= BIT8;
    
/* 获取奇偶校验模式 */
    printf(
" Please Choice the Parity Check Mode: ");
    printf(
"NONE:    0 ODD:     1 EVEN:    2 MARK:    3 SPACE:   4 ");
    pParme 
= cgets(buffer);
    
if ( atoi(pParme) == 1)
        thisComm.comParity 
= ODD;
    
else if ( atoi(pParme) == 2)
        thisComm.comParity 
= EVEN;
    
else if ( atoi(pParme) == 3)
        thisComm.comParity 
= MARK;
    
else if ( atoi(pParme) == 4)
        thisComm.comParity 
= SPACE;
    
else
        thisComm.comParity 
= NONE;
    
/* 获取停止位位数 */
    printf(
" Please Choice the Stop Bits: ");
    printf(
"1 bits:      0 1.5 bits:    1 2 bits:      2 ");
    pParme 
= cgets(buffer);
    
if ( atoi(pParme) == 1)
        thisComm.comStopBit 
= BIT15;
    
else if ( atoi(pParme) == 2)
        thisComm.comStopBit 
= BIT2;
    
else
        thisComm.comStopBit 
= BIT1;
    
/* 根据用户配置打开串口 */
    
if(OpenCOMM(thisComm.comNumber,thisComm.comBps,thisComm.comDataBit,
            thisComm.comParity,thisComm.comStopBit))
        printf(
"The Series COMM Is Start... ");
    
else
        printf(
"The Series COMM Opened False. ");

    printf(
"The Series COMM Ready To Receive Data. ");
    
/* 如果是接收数据,将下面while语句注释取消,将发送语句注释掉
       如果是发送数据,将while注释掉,取消发送语句注释 
*/

    
/* 接收数据 */

    
while(1)
    
{
        temp 
= ReadData();
        
if (temp != 0xFF)               /* 如果接收的不是0xff 则打印接收结果 */
            printf(
"%c",temp);
    }


    
/*
    while(1)
    {
        SendByte('a');
    }
    CloseCOMM();
    getch(); 
*/

    
return 0;
}

/*******************************************************************
    函数名   : SettingBPS
    参数功能 : 设置串口波特率
    参数列表 :  long bps :  输入 串口波特率
    返回值   :  如果设置成功 返回   true
                如果设置失败 返回   false
    备注     :  波特率时钟为数据时钟的1/16,而INS8250频率为1.8432MHZ
                所以有如下等式:
                预置数 = (主时钟频率/16)/波特率=115200/波特率
*******************************************************************
*/

bool  SettingBPS( long  bps)
{
     unsigned 
char regBPSMSB;           /* 波特率寄存器高8位 */
     unsigned 
char regBPSLSB;           /* 波特率寄存器低8位 */
     unsigned 
int  regBPS;              /* 波特率寄存器值 */

     regBPS 
= 115200/bps;               /* 获取波特率寄存器预置数 */
     regBPSMSB 
= regBPS >> 8;           /* 将预置数分解为高8位与低8位 */
     regBPSLSB 
= regBPS & 0x00FF;

     
/* LCR控制寄存器的最高位D7为0时 地址 regBASE 与 regBASE+1 为接收/发送、
        中断控制寄存器,当D7为1时,地址regBASE与regBASE+1 为波特率LSB、MSB
        寄存器,所以设置波特率寄存器应先将LCR寄存器最高位置1
*/

     outportb((regBASE
+LCR),0x80);      /* 置D7为1 */
     outportb((regBASE
+LSB),regBPSLSB); /* 先设波特率寄存器低8位 */
     outportb((regBASE
+MSB),regBPSMSB); /* 设置波特率寄存器高8位 */

     
/* 读取波特率寄存器,如果读取值与设置值相等,表示设置成功
        返回 true, 否则返回 false 
*/

     
if(((inportb(regBASE+MSB)<< 8| inportb(regBASE+LSB)) == regBPS)
        
return true;
     
else
        
return false;
}

/*******************************************************************
    函数名   : GettingBPS
    参数功能 : 获取串口波特率
    参数列表 :  空
    返回值   :  long bps : 当前串口设置的波特率
    备注     :  波特率 = 115200/波特率寄存器值
*******************************************************************
*/

long  GettingBPS()
{
    
long bps;
    outportb((regBASE
+LCR),0x80);   /* 置D7为1表示操作波特率寄存器 */
    bps 
= 115200 / ((inportb(regBASE+MSB)<< 8| inportb(regBASE+LSB));
    
return bps;
}

/*******************************************************************
    函数名   : InitSeriesCOMM
    参数功能 : 初始化串口
    参数列表 :  long bps            输入    波特率
                DATABIT databit     输入    数据位位数
                PARITY paritycheck  输入    奇偶校验模式
                STOPBIT stopbit     输入    停止位位数
    返回值   :  如果设置成功 返回   true
                如果设置失败 返回   false
    备注     :  D7  :与串口初始化无关,D7为1表示操作波特率寄存器
                     D7为0表示操作RXT/TXT、IEE寄存器
                D6  :当D6为1时,允许发送器空闲一个完整的发送周期


                      D5D4D3         |        含义
                    --------------------------------------
                    000/010/100/110  |   无奇偶校验
                    --------------------------------------
                         001         |   奇校验
                    --------------------------------------
                         011         |   偶校验
                    --------------------------------------
                         101         |标志(MARK)奇偶校验
                                     |奇偶位恒为1
                    --------------------------------------
                         111         |空白(SPACE)奇偶校验
                                     |奇偶位恒为0
                    --------------------------------------

                D2  :停止位设置,当该位为0时,停止位为1位,该位为1时,
                     当D1D0=00时,停止位为1.5位,否则停止位为2位

                         D1D0  |  数据位数
                       ----------------------
                           00  |     5
                       ----------------------
                           01  |     6 
                       ----------------------
                           10  |     7
                       ----------------------
                           11  |     8
                       ------------------------
*******************************************************************
*/

bool  InitSeriesCOMM(  long  bps,
                     DATABIT databit,
                     PARITY paritycheck,
                     STOPBIT stopbit)
{
    unsigned 
char parme;

    
/* 组合参数 */
    parme 
= paritycheck<<3 | stopbit<<2 | databit;
    
/* 设置波特率 */
    SettingBPS(bps);

    outportb((regBASE
+LCR),0x00);             /* 置LCR最高位为0 */
    outportb((regBASE
+LCR),parme);            /* 根据参数设置LCR寄存器 */

    
/* 读取控制寄存器的值,如果和设置值相同,说明设置成功
       返回 true,否则设置失败,返回false。 
*/

    
if(inportb(regBASE+LCR) == parme)
        
return true;
    
else
        
return false;
}

/*******************************************************************
    函数名   : OpenCOMM
    参数功能 : 打开串口进行串行通信
    参数列表 :  COM  com            输入    串口号
                long bps            输入    波特率
                DATABIT databit     输入    数据位位数
                PARITY paritycheck  输入    奇偶校验模式
                STOPBIT stopbit     输入    停止位位数
    返回值   :  如果设置成功 返回   true
                如果设置失败 返回   false
    备注     :  系统中断表:
                INT | (Hex)   |      IRQ  Common Uses 
                ---------------------------------------
                08  |   0     |       System Timer 
                --------------------------------------- 
                09  |    1     |        Keyboard 
                --------------------------------------- 
                0A  |    2     |        Redirected 
                --------------------------------------- 
                0B  |    3     | Serial Comms. COM2/COM4 
                --------------------------------------- 
                0C  |    4     | Serial Comms. COM1/COM3  
                --------------------------------------- 
                0D  |    5     |   Reserved/Sound Card  
                --------------------------------------- 
                0E  |    6     | Floppy Disk Controller  
                --------------------------------------- 
                0F  |    7     |    Parallel Comms.  
                --------------------------------------- 
                70  |    8     |    Real Time Clock 
                --------------------------------------- 
                71  |    9     |      Reserved 
                --------------------------------------- 
                72  |    10    |      Reserved 
                --------------------------------------- 
                73  |    11    |      Reserved 
                --------------------------------------- 
                74  |    12    |      PS/2 Mouse 
                --------------------------------------- 
                75  |    13    |   Maths Co-Processor
                ---------------------------------------  
                76  |    14    |      Hard Disk Drive 
                --------------------------------------- 
                77  |    15    |   Reserved  
                ---------------------------------------
*******************************************************************
*/

bool  OpenCOMM( COM com,
               
long  bps,
               DATABIT databit,
               PARITY paritycheck,
               STOPBIT stopbit)
{
    unsigned 
char temp;
    
/* 根据用户选择的串口设置寄存器基地址
       如果选择串口1,基地址为0x03F8
       如果选择串口2,基地址为0x02F8 
*/

    
if(com)
        regBASE 
= 0x2F8;
    
else
        regBASE 
= 0x3F8;

    asyncoldvect 
= getvect(0x0C);           /* 获取中断向量表 */
    disable();                              
/* 禁止系统中断 */
    outportb((regBASE
+LCR),0x00);           /* 选择设置中断寄存器*/
    outportb((regBASE
+IER),0x01);           /* 允许串口接收中断 */
    temp 
= inportb(0x21& 0xef;            /* 读取当前中断设置 */
    outportb(
0x21,temp);                    /* 注册串口中断 */
    setvect(
0x0C,asyncint);                 /* 设置中断向量表 */
    enable();                               
/* 允许系统中断 */

    
/* 调用串口初始化函数初始化串口,如果调用成功,表示
       打开端口成功,返回 true,否则打开端口失败,返回false。 
*/

    
if(InitSeriesCOMM(bps,databit,paritycheck,stopbit))
        
return true;
    
else
        
return false;
}

/*******************************************************************
    函数名   : SendByte
    参数功能 : 利用串口发送1字节数据
    参数列表 :  unsigned char data     输入    发送字节数据
    返回值   :  void
    备注     :
*******************************************************************
*/

void  SendByte(unsigned  char  data)
{
    
/* 查询LSR寄存器,如果数据准备好,则发送1字节数据 */
    
while (((inportb(regBASE+LSR)) & 0x40== 0);
    
/* 将数据写入RTX寄存器发送 */
    outportb((regBASE
+TXR),data);
}

/*******************************************************************
    函数名   : CloseCOMM
    参数功能 : 关闭串口
    参数列表 :  空
    返回值   :  void
    备注     :
*******************************************************************
*/

void  CloseCOMM()
{
    disable();                              
/* 禁止全部中断 */
    outportb((regBASE
+LCR),0x00);           /* 清串口控制寄存器 */
    outportb((regBASE
+IER),0x00);           /* 清串口中断寄存器 */
    outportb((regBASE
+MCR),0x00);           /* 清串口MODEM寄存器 */
    outportb(
0x21,inportb(0x21)&0x10);      /* 禁止串口全局中断 */
    enable();                               
/* 开全局中断 */
    setvect(
0x0C,asyncoldvect);             /* 重设中断向量表 */
}

/*******************************************************************
    函数名   : asyncint
    参数功能 : 串口接收中断服务程序,通过中断接收串口数据
    参数列表 :  空
    返回值   :  void
    备注     :
*******************************************************************
*/

void  interrupt far asyncint()
{
    
/* 接收数据 */
    DataBuffer[inBuffer
++= inportb(regBASE);
    
/* 如果接收到最大数据量,重设数据指针*/
    
if (inBuffer >= MAXBUFFERSIZE)
        inBuffer 
= 0;

    outportb(
0x20,0x20);                /* 中断完成,返回主程序 */
}

/*******************************************************************
    函数名   : ReadData
    参数功能 : 从接收缓冲区读取数据
    参数列表 :  空
    返回值   :  unsigned char temp : 读取数据成功
                0xff               : 读取数据失败
    备注     :
*******************************************************************
*/

unsigned 
char  ReadData( void )
{
    unsigned 
char temp;

    
if (outBuffer != inBuffer)
    
{
        temp 
= DataBuffer[outBuffer++];
        
/* 如果读取到最最后一个数据,重设读取数据指针*/
        
if (outBuffer >= MAXBUFFERSIZE)
            outBuffer 
= 0;
        
return temp;
    }
                                      /* 返回读取数据 */
    
else
        
return 0xff;                       /* 读取失败,返回0xff*/
}

             程序在TC2.0 下编译运行通过。希望对大家有所帮助和启发。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值