📄 commport.cpp
字号:
// CommPort.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "CommPort.h"
//----------------------------------------------------------------
//类构造函数
CCommPort::CCommPort()
{
hComm = 0;
m_eEvent = EEventNone;
m_hevtOverlapped = 0;
lpszPort="COM1"; //初始化串口
eBaudrates=EBaud9600; //初始化波特率
nFrameHead=0x12;
nTimePerByte=1;
}
//---------------------------------------------------------------
//类析构函数
CCommPort::~CCommPort ()
{
Flush();
if (hComm)
ClosePort();
}
//---------------------------------------------------------------------------
// 串口属性设置函数
//入口参数:波特率、数据位、校验位、停止位
//函数功能:
// 一、设置波特率
// 二、设置数据位
// 三、设置较验位
// 四、设置停止位
//返回值:调用成功返回值为0;失败返回失败码
//--------------------------------------------------------------------------
int CCommPort::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
{
if (hComm ==0)
return 102; //操作串口时,串口未打开
ZeroMemory(&m_dcb, sizeof (DCB));
m_dcb.DCBlength = sizeof (DCB);
m_dcb.BaudRate = DWORD(eBaudrate);
m_dcb.ByteSize = BYTE(eDataBits);
m_dcb.Parity = BYTE(eParity);
m_dcb.StopBits = BYTE(eStopBits);
m_dcb.fParity = (eParity != EParNone);
m_dcb.fBinary = 1;
m_dcb.fDtrControl = 0;
m_dcb.fRtsControl = 0;
m_dcb.XonLim = 2048;
m_dcb.XoffLim = 512;
m_dcb.XonChar = 17;
m_dcb.XoffChar = 19;
if (!::SetCommState(hComm,&m_dcb)) //不能设置DCB结构
return 202;
return 0;
}
//-----------------------------------------------------------
// 超时设置函数
//入口参数:超时种类
//函数功能:
// 超时设置
//-----------------------------------------------------------
int CCommPort::SetupReadTimeouts (int nBlockRead)
{
if (hComm == 0)
return 102;
COMMTIMEOUTS cto;
if (!::GetCommTimeouts(hComm,&cto))
return 203; //不能获得超时结构
//设置超时结构
if(!nBlockRead){
cto.ReadIntervalTimeout = 0;
cto.ReadTotalTimeoutConstant = 0;
cto.ReadTotalTimeoutMultiplier =0;
}else{
cto.ReadIntervalTimeout = 0;
cto.ReadTotalTimeoutConstant = 0;
cto.ReadTotalTimeoutMultiplier =nBlockRead;
}
if (!::SetCommTimeouts(hComm,&cto))
return 204; //不能设置超时结构
return 0;
}
//-----------------------------------------------------------------------------
// 写串口函数
//入口参数:所写数据缓冲区地址、所写数据长度、
//-----------------------------------------------------------------------------
int CCommPort::Write ( BYTE* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
{
DWORD dwWritten;
if (pdwWritten == 0)
pdwWritten = &dwWritten;
*pdwWritten = 0;
if (hComm == 0)
return 102; //操作串口时,串口未打开
OVERLAPPED ovInternal;
if (lpOverlapped == 0){
memset(&ovInternal,0,sizeof(ovInternal));
ovInternal.hEvent = m_hevtOverlapped;
lpOverlapped = &ovInternal;
}
if (!::WriteFile(hComm,pData,iLen,pdwWritten,lpOverlapped)){
long lLastError = ::GetLastError();
if (lLastError != ERROR_IO_PENDING)
return 104; //写串口出错
if (lpOverlapped == &ovInternal){
switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout)){
case WAIT_OBJECT_0:
if (!::GetOverlappedResult(hComm,lpOverlapped,pdwWritten,FALSE))
return 104; //写串口出错
break;
case WAIT_TIMEOUT:
::CancelIo(hComm);
return 104; //读串口出错
default:
return 104; //读串口出错
}
}
}
return 0;
}
//---------------------------------------------------------------------
// 读串口函数
//入口参数:所读数据存放地址、所读数据长度
//----------------------------------------------------------------------
int CCommPort::Read (BYTE* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
{
DWORD dwRead;
if (pdwRead == 0)
pdwRead = &dwRead;
*pdwRead = 0;
if (hComm == 0)
return 102; //操作串口时,串口已打开
OVERLAPPED ovInternal;
if (lpOverlapped == 0){
memset(&ovInternal,0,sizeof(ovInternal));
ovInternal.hEvent = m_hevtOverlapped;
lpOverlapped = &ovInternal;
}
if(!ReadFile(hComm,pData,iLen,pdwRead,lpOverlapped)){
long lLastError = ::GetLastError();
if (lLastError != ERROR_IO_PENDING)
return 1031; //读串口失败
if (lpOverlapped == &ovInternal){
switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout)){
case WAIT_OBJECT_0:
{
if (!::GetOverlappedResult(hComm,lpOverlapped,pdwRead,TRUE))
return 1032; //读串口失败
}
break;
case WAIT_TIMEOUT:
::CancelIo(hComm);
return 1033; //读串口失败
default:
return 1034; //读串口失败
}
}
}
return 0;
}
//-------------------------------------------------------------------------------
// 设置通信事件掩码
//函数功能:设置通信事件的掩码
//入口参数: dwMask — 所要设置的事件掩码
//返回值:成功时,返回值为0;失败后,返回失败码
//-----------------------------------------------------------------------------
int CCommPort::SetMask (DWORD dwMask)
{
if (hComm == 0)
return 102; //操作串口时,串口没打开
if (!::SetCommMask(hComm,EEventRecv))
return 208; //不能设置事件掩码
return 0;
}
//-----------------------------------------------------------------------------
// 清除缓冲区函数
//函数功能:清除当前缓冲区所有已接收的数据或欲发送的数据
//入口参数: 无
//返回值:成功时,返回值为0;失败后,返回失败码
//-----------------------------------------------------------------------------
int CCommPort::Flush()
{
if (hComm == 0)
return 102; //操作串口时,串口没打开
if (!::PurgeComm(hComm, PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_TXABORT|PURGE_RXABORT))
return 207; //清除缓冲区出错
return 0;
}
//-------------------------------------------------------------------------------
int CCommPort::WaitEvent (BYTE* pAckBuff,int nTimeOuts)
{
COMSTAT ComStat;
DWORD dwErrorFlags;
DWORD dwEvtMask,dwTrans ;
OVERLAPPED os ;
memset( &os, 0, sizeof( OVERLAPPED ) ) ;
os.hEvent = CreateEvent( NULL, // no security
TRUE, // explicit reset req
FALSE, // initial event reset
NULL ) ; // no name
if (os.hEvent == NULL)
return 1;
SetMask();
dwEvtMask=0;
if(!WaitCommEvent(hComm, &dwEvtMask, &os)){ // 重叠操作
if(GetLastError()==ERROR_IO_PENDING){
// 无限等待重叠操作结果
// GetOverlappedResult(hComm, &os, &dwTrans, true);
switch (::WaitForSingleObject(os.hEvent,nTimeOuts)){
case WAIT_OBJECT_0:
if (!::GetOverlappedResult(hComm,&os, &dwTrans, TRUE))
return 209; //监视串口出错
break;
case WAIT_TIMEOUT:
ClearCommError(hComm,&dwErrorFlags,&ComStat);
if(ComStat.cbInQue == 0){
::CancelIo(hComm);
return 209; //监视串口出错
}
default:
return 209; //监视串口出错
}
}else
return 209; //监视串口出错
}//else
//return 0;
CloseHandle(os.hEvent);
int nThreshold=0;
int CommEro=0;
BYTE StartBuff=0x0;
while(StartBuff!=nFrameHead && nThreshold<3){
CommEro=Read(&StartBuff,1,0,0,300);
nThreshold++;
if(CommEro)
return 1;
}
pAckBuff [0]=StartBuff;
BYTE OrdAndLenBuff[4]={0x0};
int nAndBgn=nFrameHead & 0xC0;
int nAlreadyRead=0;
int nFrameLen=0;
//判断接收长度
switch(nAndBgn){
case 0x0: //当命令码长度为1、参数长度为1时
CommEro=Read(OrdAndLenBuff,2,0,0,nTimeOuts);
if(CommEro)
return CommEro;
pAckBuff[1]=OrdAndLenBuff[0];
pAckBuff[2]=OrdAndLenBuff[1];
nFrameLen=OrdAndLenBuff[1];
nAlreadyRead=3;
break;
case 0x40: //当命令码长度为1、参数长度为2时
CommEro=Read(OrdAndLenBuff,3,0,0,nTimeOuts);
if(CommEro)
return CommEro;
pAckBuff[1]=OrdAndLenBuff[0];
pAckBuff[2]=OrdAndLenBuff[1];
pAckBuff[3]=OrdAndLenBuff[2];
nFrameLen=OrdAndLenBuff[1]*256+OrdAndLenBuff[2];
nAlreadyRead=4;
break;
case 0x80: //当命令码长度为2、参数长度为1时
CommEro=Read(OrdAndLenBuff,3,0,0,nTimeOuts);
if(CommEro)
return CommEro;
pAckBuff[1]=OrdAndLenBuff[0];
pAckBuff[2]=OrdAndLenBuff[1];
pAckBuff[3]=OrdAndLenBuff[2];
nFrameLen=OrdAndLenBuff[1];
nAlreadyRead=4;
break;
case 0xC0: //当命令码长度为2、参数长度为2时
CommEro=Read(OrdAndLenBuff,4,0,0,nTimeOuts);
if(CommEro)
return CommEro;
pAckBuff[1]=OrdAndLenBuff[0];
pAckBuff[2]=OrdAndLenBuff[1];
pAckBuff[3]=OrdAndLenBuff[2];
pAckBuff[4]=OrdAndLenBuff[3];
nFrameLen=OrdAndLenBuff[2]*256+OrdAndLenBuff[3];
nAlreadyRead=5;
break;
}
BYTE *LeaveBuff;
LeaveBuff=new BYTE[nFrameLen];
CommEro=Read(LeaveBuff,nFrameLen,0,0,nTimeOuts);
if(CommEro)
return CommEro;
for(int i=0;i<nFrameLen;i++)
pAckBuff[i+nAlreadyRead]=LeaveBuff[i];
//清空掩码
SetCommMask(hComm,0);
return 0;
}
//-------------------------------------------------------------------------------
// 设置帧头函数
//函数功能:设置通信时,命令/响应帧的帧头
//入口参数: nHead — 帧头参数,值为0-255之间
// 当 0<=nHead<0x40 时, 帧参数长度用1个字节表示,命令字符用1个字节表示
// 当 0x40<=nHead<0x80 时, 帧参数长度用2个字节表示,命令字符用1个字节表示
// 当 0x80<=nHead<0xC0 时, 帧参数长度用1个字节表示,命令字符用2个字节表示
// 当 0xC0<=nHead<=0xFF 时,帧参数长度用1个字节表示,命令字符用1个字节表示
//返回值:设置成功后,返回值为TRUE; 否则返回值为FALSE
//-----------------------------------------------------------------------------
BOOL CCommPort::SetFrameHead(int nHead)
{
if(nHead>256||nHead<0)
return FALSE;
nFrameHead=nHead;
return TRUE;
}
//-----------------------------------------------------------------------------
// 设置串口号函数
//函数功能:选择所要打开的串口号
//入口参数: ePort — 串口号,1-4各代表COM1-COM4,其它值无意义.
//返回值:成功后,返回值为TRUE, 否则为 FALSE
//-----------------------------------------------------------------------------
BOOL CCommPort::SetCommPort(int ePort)
{
switch(ePort){
case 1:
lpszPort="COM1";
break;
case 2:
lpszPort="COM2";
break;
case 3:
lpszPort="COM3";
break;
case 4:
lpszPort="COM4";
break;
case 5:
lpszPort="COM5";
break;
case 6:
lpszPort="COM6";
break;
default:
lpszPort="COM1";
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// 设置通信波特率函数
//函数功能:设置通信过程中所使用的波特率
//入口参数: eBaud — 波特率值,如9600代表9600bit/s
//返回值:成功后,返回值为TRUE, 否则为 FALSE
//-----------------------------------------------------------------------------
BOOL CCommPort::SetCommBaud(int eBaud)
{
switch(eBaud){
case 110:
eBaudrates=EBaud110;
break;
case 300:
eBaudrates=EBaud300;
break;
case 600:
eBaudrates=EBaud600;
break;
case 1200:
eBaudrates=EBaud1200;
break;
case 2400:
eBaudrates=EBaud2400;
break;
case 4800:
eBaudrates=EBaud4800;
break;
case 9600:
eBaudrates=EBaud9600;
break;
case 14400:
eBaudrates=EBaud14400;
break;
case 19200:
eBaudrates=EBaud19200;
break;
case 38400:
eBaudrates=EBaud38400;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -