📄 pserialport.cpp
字号:
// PSerialPort.cpp: implementation of the CPSerialPort class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SerialPort.h"
#include "PSerialPort.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPSerialPort::CPSerialPort()
{
m_hComm=INVALID_HANDLE_VALUE;
m_hReadThread=NULL;
m_bReceiving=FALSE;
m_nBufferSize=256; //缓冲大小
}
CPSerialPort::~CPSerialPort()
{
ClosePort();
}
/* 事件驱动
//串口读线程函数
DWORD CCESeries::ReadThreadFunc(LPVOID lparam)
{
CCESeries *ceSeries = (CCESeries*)lparam;
DWORD evtMask;
BYTE * readBuf = NULL;//读取的字节
DWORD actualReadLen=0;//实际读取的字节数
DWORD willReadLen;
DWORD dwReadErrors;
COMSTAT cmState;
// 清空缓冲,并检查串口是否打开。
ASSERT(ceSeries->m_hComm !=INVALID_HANDLE_VALUE);
//清空串口
PurgeComm(ceSeries->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR );
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
while (TRUE)
{
if (WaitCommEvent(ceSeries->m_hComm,&evtMask,0))
{
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR ); //此句可省略
//表示串口收到字符
if (evtMask & EV_RXCHAR)
{
ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
willReadLen = cmState.cbInQue ;
if (willReadLen <= 0)
{
continue;
}
readBuf = new BYTE[willReadLen];
ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,0);
//如果读取的数据大于0,
if (actualReadLen>0)
{
//触发读取回调函数 ,将所读内容显示在方框中
ceSeries->m_OnSeriesRead(ceSeries->m_pPortOwner,readBuf,actualReadLen);
}
}
}
//如果收到读线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hReadCloseEvent,500) == WAIT_OBJECT_0)
{
break;
}
}
return 0;
}
//*/
DWORD WINAPI CPSerialPort::ReadPortThread(LPVOID lpParameter) //参数指向串口类
{
DWORD evtMask; //事件驱动变量WaitCommEvent()用
DWORD dwReadErrrors; //保存出错状态用
COMSTAT cmState;
CPSerialPort* m_pSerial;
m_pSerial=(CPSerialPort*)lpParameter;
if(m_pSerial->m_hComm!=INVALID_HANDLE_VALUE)
{
PurgeComm(m_pSerial->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR ); //清空串口
SetCommMask (m_pSerial->m_hComm, EV_RXCHAR); //设置响应事件
}
while((m_pSerial->m_hComm!=INVALID_HANDLE_VALUE)&&(m_pSerial->m_bReceiving))
{
if(WaitCommEvent(m_pSerial->m_hComm,&evtMask,NULL)) //等接收信号
{ //有数据
ClearCommError(m_pSerial->m_hComm,&dwReadErrrors,&cmState); //清错误并查询,保证下一次的waitcommEvent();
m_pSerial->ReceiveChar(m_pSerial,cmState); //读数据
}
}
return 0;
}
//读并保存串口数据
void CPSerialPort::ReceiveChar(CPSerialPort *port, COMSTAT comstat)
{
BOOL bResult=TRUE;
DWORD dwError=0;
DWORD dwWantRead;
BOOL fReadState;
DWORD dwLength;
char* buf=new char[port->m_nBufferSize]; //生成缓存区
for(;;) //读数
{
bResult=ClearCommError(port->m_hComm,&dwError,&comstat);
if(comstat.cbInQue==0 || !port->m_bReceiving) //无数据或按退出则退出程序
{
break; //返回
}
//确定读数长度
if(comstat.cbInQue<9) dwWantRead=9;//小于9个字符
else dwWantRead=comstat.cbInQue;
if(dwWantRead> (DWORD)port->m_nBufferSize) dwWantRead=port->m_nBufferSize;
fReadState=ReadFile(port->m_hComm,buf,dwWantRead,&dwLength,NULL);
if(!fReadState)
{
//AfxMessageBox(_T("无法从串口读取数据!"));
}
else
{
if(dwLength!=0)
{
//回送数据
if(port->m_lpDataArriveProc!=NULL)
{
port->m_lpDataArriveProc(buf,dwLength,port->m_dwUserData);
}
}
}
}
delete[] buf;
}
BOOL CPSerialPort::OpenPort(LPCTSTR Port,int BaudRate,int DataBits,int StopBits,int Parity,LPDataArriveProc proc,DWORD userdata)
{
m_lpDataArriveProc=proc; //接收线程用的回调函数
m_dwUserData=userdata; //用户参数(指向调用OpenPort()的窗口
if(m_hComm==INVALID_HANDLE_VALUE)
{
m_hComm=CreateFile(Port,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0); //打开串口
if(m_hComm==INVALID_HANDLE_VALUE )
{
AfxMessageBox(_T("无法打开端口!请检查是否已被占用。"));
return FALSE;
}
GetCommState(m_hComm,&dcb);
dcb.BaudRate=BaudRate;
dcb.ByteSize=DataBits;
dcb.Parity=Parity;
dcb.StopBits=StopBits;
dcb.fParity=FALSE;
dcb.fBinary=TRUE;
dcb.fDtrControl=0;
dcb.fRtsControl=0;
dcb.fOutX=dcb.fInX=dcb.fTXContinueOnXoff=0;
//设置状态参数
SetCommMask(m_hComm,EV_RXCHAR); //设置"接收到一个字符"事件
SetupComm(m_hComm,16384,16384); //设置接收,发送缓存大小为16384byte
if(!SetCommState(m_hComm,&dcb)) //将设置的参数写入串口
{
AfxMessageBox(_T("无法按当前参数配置端口,请检查参数!"));
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除串口发送接收
ClosePort(); //关闭
return FALSE;
}
//设置超时参数
GetCommTimeouts(m_hComm,&CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout=100; //查询方式读数时的时间间隔
CommTimeOuts.ReadTotalTimeoutMultiplier=1; //读一个字节时的时间超时上限
CommTimeOuts.ReadTotalTimeoutConstant=100; //总超时量
CommTimeOuts.WriteTotalTimeoutMultiplier=0;
CommTimeOuts.WriteTotalTimeoutConstant=0;
if(!SetCommTimeouts(m_hComm,&CommTimeOuts)) //写入串口
{
AfxMessageBox(_T("无法设置超时参数!"));
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除串口发送接收区
ClosePort();
return FALSE;
}
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除串口发送接收区
return TRUE;
}
return FALSE;
}
BOOL CPSerialPort::ClosePort()
{
Deactivate();
if(m_hComm!=INVALID_HANDLE_VALUE)
{
SetCommMask(m_hComm,0); //清事件
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除串口发送接收区
CloseHandle(m_hComm);
m_hComm=INVALID_HANDLE_VALUE;
return TRUE;
}
return TRUE;
}
BOOL CPSerialPort::Activate()
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return FALSE;
}
if(!m_bReceiving)
{
//开始接收线程
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
m_bReceiving=TRUE;
m_hReadThread=CreateThread(NULL,0,ReadPortThread,this,0,NULL);
}
if(m_hReadThread!=NULL)
{
return TRUE;
}
else
{
m_bReceiving=FALSE;
return FALSE;
}
return FALSE;
}
BOOL CPSerialPort::Deactivate()
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return FALSE;
}
//停止接收线程
if(m_bReceiving)
{
m_bReceiving=FALSE; //关串口读数线程
SetCommMask(m_hComm,0); //退出等待线程
WaitForSingleObject(m_hReadThread,1000);
CloseHandle(m_hReadThread);
m_hReadThread=NULL;
return TRUE;
}
return FALSE;
}
BOOL CPSerialPort::IsActive()
{
return m_bReceiving;
}
DWORD CPSerialPort::WritePort(char *data,int length)
{
DWORD fg;
COMSTAT cmstat;
if(m_hComm==INVALID_HANDLE_VALUE)
{
return 0;
}
ClearCommError(m_hComm,&fg,&cmstat); //清错并查询状态
BOOL fWriteState;
DWORD dwBytesWritten=0;
fWriteState=WriteFile(m_hComm,data,length*sizeof(char),&dwBytesWritten,NULL);
return dwBytesWritten;
}
DWORD CPSerialPort::ReadPort(char *data,int length)
{
BOOL fReadState;
DWORD dwLength,dwBytesRead;
int TimeOutCount;
dwBytesRead=0;
TimeOutCount=0;
while(m_hComm!=INVALID_HANDLE_VALUE)
{
char* buf=new char[length];
fReadState=ReadFile(m_hComm,data,length,&dwLength,NULL);
if(!fReadState)
{
break;
}
else
{
dwBytesRead+=dwLength;
data+=dwLength;
}
if(dwBytesRead==(DWORD)length)
{
break;
}
if(dwLength!=0)
{
TimeOutCount=0;
}
else
{
TimeOutCount++;
Sleep(5);
}
if(TimeOutCount==5)
{
break;
}
}
return dwBytesRead;
}
DWORD CPSerialPort::WriteFileToPort(LPCTSTR FileName)
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return 0;
}
CFile cf;
BOOL fWriteState;
DWORD dwBytesWritten;
DWORD dwCharToWrite;
dwCharToWrite=0;
if(!cf.Open(FileName,CFile::modeRead))
{
//AfxMessageBox(_T("无法打开Hex文件!"));
return 0;
}
dwCharToWrite=(DWORD)cf.GetLength();
cf.Seek(0,CFile::begin);
dwBytesWritten=0;
if(m_hComm!=INVALID_HANDLE_VALUE&&dwCharToWrite!=0)
{
char* buf=new char[dwCharToWrite];
cf.Read(buf,dwCharToWrite);
fWriteState=WriteFile(m_hComm,buf,dwCharToWrite*sizeof(char),&dwBytesWritten,NULL);
if(!fWriteState)
{
//AfxMessageBox(_T("无法向端口写入数据!"));
}
delete[] buf;
}
cf.Close();
return dwBytesWritten;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -