一个封装的不错的串口类

前一段时间做项目,要用到串口操作,参考了网上不少的例子,就自己封装了一个串口类。

串口类接口,也就是头文件,类名CRs232.

Rs232.h

#pragma once
#define RS232_H
#define RXQUEUE         4096  // 接收缓冲区大小
#define TXQUEUE         1024    // 发送缓冲区大小
#define MAXBLOCK        1024
class CRs232
{
public: 
 CRs232(  ); 
 ~CRs232(  ); 
 BOOL  IsConnected( ); // 判断串口是否已经打开
 int ReadCommBlock(unsigned char* lpszBlock, int nMaxLength);// 从串口读数据
 HANDLE m_hComDev;// 串口设备句柄
 OVERLAPPED m_osRead,m_osWrite;
 HANDLE m_hThreadTerm;  // 事件句柄:控制通讯线程是否终止的同步对象
 BOOL m_bConnected;//    串口是否已经打开
 int OpenConnection(LPCTSTR szComPort ="COM1",DWORD dwBaudRate =9600,BYTE cBycByteSize=8,BYTE cStopBits=ONESTOPBIT,BYTE cParity=NOPARITY,BOOL bDTR_DSR=0,BOOL bRTS_CTS=0,BOOL bXON_XOFF=0);// 打开并配置串口 
 BOOL CloseConnection( );  // 关闭、释放串口 
 int WriteCommBlock( LPCVOID lpByte, UINT nBytesToWrite); //往串口写数据 
};

Rs232.cpp文件

#include  "StdAfx.h"
#include  "rs232.h"

CRs232::CRs232(void)
{

 memset(  &m_osWrite,  0,  sizeof(OVERLAPPED)  )  ;
 memset(  &m_osRead,  0,  sizeof(OVERLAPPED)  )  ;
 m_bConnected  =  FALSE;

 m_hThreadTerm  =  CreateEvent(  NULL,  FALSE,  FALSE,  NULL  ); 

 m_osRead.hEvent  =  CreateEvent(  NULL,  TRUE,  FALSE,  NULL  );  
 m_osWrite.hEvent  =  CreateEvent(  NULL,  TRUE,  FALSE,  NULL  ); 

  }

CRs232::~CRs232(void)
{
 if(  m_bConnected  )          //    如果已打开串口
     CloseConnection();      //    关闭、释放串口
 CloseHandle(  m_hThreadTerm  ); 
 CloseHandle(  m_osRead.hEvent)  ;
 CloseHandle(  m_osWrite.hEvent)  ;
}
int  CRs232::OpenConnection(  LPCTSTR  szComPort,DWORD  dwBaudRate,BYTE  cByteSize,   
            BYTE  cStopBits,BYTE  cParity,BOOL  bDTR_DSR,BOOL  bRTS_CTS,BOOL  bXON_XOFF  )
{
 BOOL e_InitializeComm =TRUE;
 BOOL e_OpenComm =FALSE;
 if(  m_bConnected  )        //  已经打开 
 return  0;   
 SetEvent(m_osWrite.hEvent);  
    m_hComDev  =  CreateFile(  szComPort,  GENERIC_READ  |  GENERIC_WRITE,  0,  NULL,  OPEN_EXISTING,  FILE_FLAG_OVERLAPPED,  NULL  );
 if(  m_hComDev  ==  INVALID_HANDLE_VALUE  ) 
  return  e_OpenComm;    //  返回不能打开串口错误代码
    DCB  dcb;
    dcb.DCBlength  =  sizeof(DCB);   
 GetCommState(m_hComDev,&dcb  );       
 
 dcb.BaudRate  =  dwBaudRate;  
 dcb.ByteSize  =  cByteSize; 
 dcb.Parity  =  cParity;    
 dcb.StopBits  =  ONESTOPBIT;     
 //  硬件流控制.  bDTR_DSR、bRTS_CTS一般取默认值0,有Modem时应取1 
 dcb.fOutxDsrFlow  =  (  bDTR_DSR!=0);    //   
 if(bDTR_DSR)   
  dcb.fDtrControl  =  DTR_CONTROL_HANDSHAKE  ;    // 
 else   
  dcb.fDtrControl  =  DTR_CONTROL_ENABLE  ;
      dcb.fOutxCtsFlow   =  (bRTS_CTS!=0)  ; 
        if  (bRTS_CTS)   
  dcb.fRtsControl  =  RTS_CONTROL_HANDSHAKE  ; 
 else   
  dcb.fRtsControl  =  RTS_CONTROL_ENABLE  ;
      dcb.fInX  =  dcb.fOutX  =  (bXON_XOFF!=0);    //  软件流控制 
        dcb.fBinary  =  TRUE  ;    //  
      dcb.fParity  =  TRUE  ;   
      if(  SetCommState(m_hComDev,&dcb)  ) 
        {   
  //  配置串口参数成功   
  SetCommMask(m_hComDev,EV_RXCHAR);
//  设置接收、发送缓冲区大小   
  SetupComm(m_hComDev,4096,4096);
  COMMTIMEOUTS    CommTimeOuts  ;
  CommTimeOuts.ReadIntervalTimeout  =  MAXDWORD;       
  CommTimeOuts.ReadTotalTimeoutMultiplier  =  0  ;  
  CommTimeOuts.ReadTotalTimeoutConstant  =  10;       
  CommTimeOuts.WriteTotalTimeoutMultiplier  =  0;       
  CommTimeOuts.WriteTotalTimeoutConstant  =  0;      
 SetCommTimeouts(  m_hComDev,  &CommTimeOuts  );  
        m_bConnected  =  TRUE  ;   
   return  TRUE;
 
 } 
 m_bConnected  =  FALSE  ;
 CloseHandle(  m_hComDev  )  ; 
 return FALSE;
}

int  CRs232::ReadCommBlock(  unsigned char*  lpszBlock,  int  nMaxLength  )

 COMSTAT  ComStat;    //  串口状态结构 
 DWORD  dwLength,  dwErrorFlags; 
 ClearCommError(m_hComDev,&dwErrorFlags,&ComStat);
 dwLength = min((DWORD)  nMaxLength,  ComStat.cbInQue);  //    将要读取的数据字节数
    //dwLength = nMaxLength;
 if(dwLength> 0  ) 
 { 
    if(  !ReadFile(m_hComDev, lpszBlock,dwLength,&dwLength,&m_osRead))    //  从串口读入数据     
        if(  GetLastError()  ==  ERROR_IO_PENDING)      
        if(  !GetOverlappedResult(m_hComDev,  &m_osRead,  &dwLength,  TRUE)  )  //  挂起,直到操作完成       
        ClearCommError(  m_hComDev,  &dwErrorFlags,  &ComStat  );   
 }
 return  dwLength;    //  返回已读入的数据字节数 
}
int CRs232::WriteCommBlock(  LPCVOID  lpByte,  UINT  nBytesToWrite)

    int e_NotConnected =0;
 int  e_TransmitError =0;
 int e_TransmitNotFinished =0;
 DWORD   dwBytesWritten,  dwErrorFlags;
 COMSTAT  ComStat;
     if(  !m_bConnected  )  //  串口没有打开     
       return  e_NotConnected; 
        if(WaitForSingleObject(m_osWrite.hEvent,0)  !=  WAIT_OBJECT_0)     
       return  e_TransmitNotFinished;   
        ResetEvent(m_osWrite.hEvent); 
 if(!WriteFile(m_hComDev,lpByte,nBytesToWrite,&dwBytesWritten,&m_osWrite))
 {
  //  往串口发送数据
  if(  GetLastError()  ==  ERROR_IO_PENDING  )     
   return  0;    //  正在后台发送   
  ClearCommError(  m_hComDev,  &dwErrorFlags,  &ComStat  )  ;  //  出现错误,清除错误标志 
    return    e_TransmitError;    //  发送出错 
 } 
 return  0;  //  WriteFile返回1,发送成功}
}
BOOL CRs232::CloseConnection( )
{
 if( !m_bConnected )
  return FALSE; 
 SetEvent(m_hThreadTerm);
 m_bConnected = FALSE; 
 SetCommMask( m_hComDev, 0 ); 
 
 EscapeCommFunction(m_hComDev,CLRDTR );
 CloseHandle(m_hComDev);//  关闭、释放串口
 return ( TRUE ) ;
}

BOOL CRs232::IsConnected( )
{
 if( !m_bConnected )
  return FALSE;
 else
 return TRUE;
}

好了,类已经封装好了,我们就可以是使用它了。例如,我们建立了一个基于对话框的工程,在对话框的头文件里我们声明一个改串口类的对象。CRs232 SerialPort; 在程序中,我们可以这样使用

SerialPort.OpenConnection("COM1",57600,8,0,0,0,0,0);打开COM1,波特率;57600,数据位8,停止位1。无校验

SerialPort.CloseConnection();关闭改串口

当然,我们还得创建一个辅助线程,专门侦测串口接受到的数据。线程侦测一旦有数据传来,;立即读到缓冲区里。辅助线程必须声明为类的静态成员函数。

这样声明;static UINT CommThreadProc(LPVOID pParam);//辅助线程要执行的函数,必须声明为静态类函数

UINT YourDlg::CommThreadProc(LPVOID pParam)
{
 YourDlg* hwndTemp = (YourDlg*)(pParam);//强制转换对话框对象指针
 DWORD   dwEvtMask;   
 HANDLE  aEvent[2];   
 OVERLAPPED  os;
 int i, nLength; 
 hwndTemp->Totollen=0;                                  //声明成局部变量

 unsigned char abIn[MAXBLOCK+1]; 
 memset(hwndTemp->TotalBuf,0,sizeof(hwndTemp->TotalBuf));//初始化
    memset(&os,0,sizeof(OVERLAPPED));                        //  初始化 
    os.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);            //生成事件
 aEvent[0] = os.hEvent;
 aEvent[1] = hwndTemp->SerialPort.m_hThreadTerm;
    while(hwndTemp->SerialPort.m_bConnected)
      {   
       WaitCommEvent(hwndTemp->SerialPort.m_hComDev, &dwEvtMask,&os); 
       if(WaitForMultipleObjects(2,aEvent,FALSE,INFINITE) == WAIT_OBJECT_0) 
       {
                                                    //  等待通讯事件发生     
        if( (dwEvtMask & EV_RXCHAR) == EV_RXCHAR )  //  是接收字符触发了该事件
         do{
          if((nLength=hwndTemp->SerialPort.ReadCommBlock(abIn,MAXBLOCK)))//
          {    
                             abIn[nLength]  =  0; 
                              for(i = hwndTemp->Totollen;i< hwndTemp->Totollen+nLength;i++)
         { 
          hwndTemp->TotalBuf[i] =abIn[i- hwndTemp->Totollen]; 
         }
          hwndTemp->Totollen +=nLength;
         Sleep(300);                //超时控制
       }          
             } 
      while(nLength > 0); 

    memset(abIn,0,sizeof(abIn));
        ResetEvent(os.hEvent);  
         } 
      } 
      CloseHandle(os.hEvent);  //释放事件句柄资源 
      return  0;
}

TotalBuf是我定义的全局变量,用来存放从串口接受到的数据。Totollen是缓冲区长度。 这样一个串口类就完成了,呵呵。如果大家对我这个类有什么问题或者bug 请于我联系。我的QQ:18910845,MSN:taojingtao163com@163.com

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

independently

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值