📄 serialportctrl.cpp
字号:
// SerialPortCtrl.cpp: implementation of the CSerialPortCtrl class.
//
#include "stdafx.h"
#include "SerialPortCtrl.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSerialPortCtrl::CSerialPortCtrl()
{
m_hCom = NULL;
m_strPort = "COM0";
m_bComOpen = false;
m_cInBuf = NULL;
m_InBufSz = INBUFSZ;
m_OutBufSz = OUTBUFSZ;
m_dwEvt = EV_RXCHAR;//;//EV_RXFLAG |
//端口设备控制块,m_Dcb;
//超时结构,m_ComTimeOuts;
memset(&m_OLRead,0,sizeof(OVERLAPPED));
memset(&m_OLWrite,0,sizeof(OVERLAPPED));
}
CSerialPortCtrl::~CSerialPortCtrl()
{
CloseCom();
}
bool CSerialPortCtrl::OpenCom(LPCTSTR port/* = "COM1"*/)
{
if(m_strPort == port&&(m_hCom||m_bComOpen))
return true; //指定的端口已经打开
if((m_hCom||m_bComOpen)&&m_strPort != port)
CloseCom();//正打开的端口不是指定的,则先关闭
m_hCom = CreateFile(port,
GENERIC_READ |GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |FILE_FLAG_OVERLAPPED, //支持重叠操作
NULL);
if(m_hCom == INVALID_HANDLE_VALUE)
{ //打开端口失败
AfxMessageBox("打开端口"+CString(port)+"失败.");
DWORD dwError = GetLastError();
//进行相应处理.....
return m_bComOpen;
}
else
{ //成功打开指定端口
m_bComOpen = true; //更新端口状态
m_strPort = port;
m_ComTimeOuts.ReadIntervalTimeout = MAXDWORD;//
m_ComTimeOuts.ReadTotalTimeoutMultiplier = 0;//
m_ComTimeOuts.ReadTotalTimeoutConstant = 0;
m_ComTimeOuts.WriteTotalTimeoutMultiplier= 10;
m_ComTimeOuts.WriteTotalTimeoutConstant = 50;
m_OLRead.hEvent = CreateEvent(NULL,true,false,NULL);
m_OLWrite.hEvent = CreateEvent(NULL,true,false,NULL);
GetCommState(m_hCom, &m_Dcb);
m_Dcb.DCBlength = sizeof(DCB);
m_Dcb.BaudRate = 9600;
m_Dcb.ByteSize = 8;
// m_Dcb.EvtChar = '\r';
//设置输入、输出缓冲大小
// m_InBufSz = INBUFSZ;
// m_OutBufSz = OUTBUFSZ;
SetCom(); //用默认参数,设置端口
}
return m_bComOpen;
}
bool CSerialPortCtrl::CloseCom()
{ //关闭已经打开的端口
if(!m_hCom || !m_bComOpen)//没有端口被打开
return true;
FlushFileBuffers(m_hCom);
if(m_cInBuf)
{
delete[] m_cInBuf;
m_cInBuf = NULL;
}
bool bre,bwe; //关闭异步事件
if(m_OLRead.hEvent)
bre = CloseHandle(m_OLRead.hEvent);
if(m_OLWrite.hEvent)
bwe = CloseHandle(m_OLWrite.hEvent);
SetCommMask(m_hCom,0); //清楚端口事件标志
m_bComOpen = !CloseHandle(m_hCom); //关闭端口,并更新端口状态
if(!m_bComOpen&&bre&&bwe)
{
m_strPort = "COM0";
memset(&m_OLRead,0,sizeof(OVERLAPPED));
memset(&m_OLWrite,0,sizeof(OVERLAPPED));
}
else
AfxMessageBox("关闭端口"+m_strPort+"失败.");
return (!m_bComOpen&&bre&&bwe);
}
bool CSerialPortCtrl::SetCom()
{ //需要事先填充相关结构
//m_hCom,m_Dcb,m_InBufSz,m_OutBufSz,m_dwEvt,m_ComTimeOuts.
bool btouts = SetCommTimeouts(m_hCom,&m_ComTimeOuts);
bool bstate = SetCommState(m_hCom,&m_Dcb);
bool bbufsz = SetupComm(m_hCom,m_InBufSz,m_OutBufSz);
if(m_cInBuf) delete[] m_cInBuf;
m_cInBuf = new DTIN[m_InBufSz];
if(m_cInBuf) memset(m_cInBuf,0,m_InBufSz*sizeof(DTIN));
PurgeComm(m_hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
bool bdwevt = SetCommMask(m_hCom,m_dwEvt);
bool bres = btouts&&bstate&&bbufsz&&m_OLRead.hEvent&&m_OLWrite.hEvent&&bdwevt;
if(!bres)
{
AfxMessageBox("端口设置失败,若端口未打开,请先打开端口.");
DWORD dwError = GetLastError();
//进行相应处理......
return !CloseCom();
}
else
{
ResetEvent(m_OLRead.hEvent);
ResetEvent(m_OLWrite.hEvent);
}
return bres;
}
DWORD CSerialPortCtrl::WriteCom(DTOUT outbuf,DWORD towrite)
{
if( !m_bComOpen || m_hCom == NULL )
{
// AfxMessageBox("端口未打开,无法完成写操作。");
return 0;
}
DWORD dwErrFlags;
DWORD dwWritten;
COMSTAT comStat;
ClearCommError(m_hCom,&dwErrFlags,&comStat);
dwWritten = 0;
for(DWORD i=0; i<towrite; i++)
{
WriteComByte(outbuf[i]);
dwWritten++;
}
return dwWritten; //返回实际写入的字节数
}
bool CSerialPortCtrl::WriteComByte(DTOUTB uc)
{
BOOL bWriteStat;
DWORD dwBytesWritten;
bWriteStat = WriteFile( m_hCom,(LPSTR) &uc,1, &dwBytesWritten, &m_OLWrite );
if( !bWriteStat && ( GetLastError() == ERROR_IO_PENDING ) )
{
if( WaitForSingleObject(m_OLWrite.hEvent,1000))
dwBytesWritten = 0;
else
{
GetOverlappedResult(m_hCom, &m_OLWrite, &dwBytesWritten,true);
m_OLWrite.Offset += dwBytesWritten;
}
}
return true;
}
DWORD CSerialPortCtrl::ReadCom(DTIN* pinbuf,DWORD toread)
{ //m_hCom非空,根据当前缓冲区中的实际数据,调整要读取的数据数量
if( !m_bComOpen || m_hCom == NULL )
{
// AfxMessageBox("端口未打开,无法完成读操作。");
return 0;
}
DWORD dwErrFlags;
COMSTAT comStat;
ClearCommError(m_hCom,&dwErrFlags,&comStat);
DWORD dwbnum = min(toread,comStat.cbInQue);
if(dwbnum == 0) return dwbnum; //端口无数据
memset(m_cInBuf,0,m_InBufSz*sizeof(DTIN));//
DWORD onereaded = 0,allreaded = 0;
for(DWORD i = 0;i<dwbnum;i++)
{
bool brf = ReadFile(m_hCom,m_cInBuf+i,sizeof(DTIN),&onereaded,&m_OLRead);
//*
if(!brf)
{ //
DWORD dwLastError = GetLastError();
if(dwLastError == ERROR_IO_PENDING)
{
if(WaitForSingleObject(m_OLRead.hEvent,INFINITE))
allreaded += onereaded;
}
}
else
allreaded += onereaded;
//*/
}
if(pinbuf) pinbuf = m_cInBuf;
return allreaded;
}
//* 多线程有效,线程间通信有效,可以监测到SetCommMask创建的EV_RXCHAR事件,但读取端口错误
UINT SPWatcher(LPVOID SPWatInfo)
{
OVERLAPPED OlWce; //用于通信事件监视函数的重叠结构
SPWATCHINFO* pWatInfo = (SPWATCHINFO*)SPWatInfo;
CSerialPortCtrl* pCom = pWatInfo->pSP; //端口句柄
if(!pCom->m_hCom)
{
AfxMessageBox("端口监视线程: 端口句柄无效.");
return 1;
}
memset(&OlWce,0,sizeof(OVERLAPPED));
OlWce.hEvent = CreateEvent(NULL,true,false,NULL);
if(!OlWce.hEvent)
{
AfxMessageBox("端口监视线程: 创建事件句柄失败.");
return 1;
}
DWORD dwLength;
DWORD dwLastErr;
DWORD dwEvtMask;
COMSTAT ComStat;
DWORD dwErrorFlags;
while(pCom->m_bComOpen)//true
{ //端口打开时,循环监视
ClearCommError(pCom->m_hCom, &dwErrorFlags, &ComStat);
if(ComStat.cbInQue)//
{//
WaitForSingleObject(pWatInfo->hEvt,INFINITE);//
ResetEvent(pWatInfo->hEvt);//
//
dwLength = pCom->ReadCom();
// Beep(1000, 50);
SendMessage(pWatInfo->hParent,WK_EVT_SPIN,dwEvtMask, min(dwLength, ComStat.cbInQue));
// SetEvent(pWatInfo->hEvt);
continue;
}//
dwEvtMask = 0;
if(!WaitCommEvent(pCom->m_hCom,&dwEvtMask,&OlWce))
{ //出现端口事件则稍作处理,通知主线程读取端口数据
dwLastErr = GetLastError();
if(dwLastErr == ERROR_IO_PENDING)
{ //等待监视函数成功完成并返回
DWORD dwTrans = 0;
GetOverlappedResult(pCom->m_hCom, &OlWce, &dwTrans, true);
}
else
{
CloseHandle(OlWce.hEvent);
return 0;//
}
}
}
//线程结束,则销毁相应资源
CloseHandle(OlWce.hEvent);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -