📄 cecomm.cpp
字号:
//////////////////////////////////////////////////////////////////////
// CEComm.cpp: implementation of the CCEComm class.
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CEComm.h"
//类CVCCom构造函数
CCEComm::CCEComm()
{
m_hComm = INVALID_HANDLE_VALUE;
m_pPortOwner = NULL;
m_nPort = 0;
m_hReadThread = NULL;
m_hReadCloseEvent = NULL;
m_hWriteThread = NULL;
m_hWriteCloseEvent = NULL;
m_nCloseDelayTime = 1000;
}
//类CVCCom析构函数
CCEComm::~CCEComm()
{
ClosePort();
}
/*
*函数介绍:设置串口读取、写入超时
*入口参数:CommTimeOuts : 指向COMMTIMEOUTS结构
*出口参数:(无)
*返回值:TRUE:设置成功;FALSE:设置失败
*/
BOOL CCEComm::SetSeriesTimeouts(COMMTIMEOUTS* pCommTimeOuts)
{
ASSERT(m_hComm != INVALID_HANDLE_VALUE);
if (!SetCommTimeouts(m_hComm,pCommTimeOuts))
{
TRACE(_T("SetCommTimeouts error"));
return FALSE;
}
return TRUE;
}
BOOL CCEComm::GetSeriesState(DCB* pCommParam)
{
ASSERT(m_hComm != INVALID_HANDLE_VALUE);
if (!GetCommState(m_hComm,pCommParam))
{
TRACE(_T("GetCommState error"));
return FALSE;
}
return TRUE;
};
BOOL CCEComm::SetSeriesState(DCB* pCommParam)
{
ASSERT(m_hComm != INVALID_HANDLE_VALUE);
if (!SetCommState(m_hComm, pCommParam))
{
TRACE(_T("SetCommState error"));
return FALSE;
}
return TRUE;
};
void CCEComm::ConfigPort()
{
/* DCB dcb;
TCHAR szPort[15];
wsprintf(szPort, _T("COM%d"), m_nPort);
GetSeriesState(&dcb);
COMMCONFIG comm;
comm.dwSize = sizeof(COMMCONFIG);
CopyMemory(&comm.dcb,&dcb,sizeof(DCB));
CommConfigDialog(szPort,m_pPortOwner->GetSafeHwnd(),&comm);
SetSeriesState(&comm.dcb);
*/}
/*
*函数介绍:关闭串口
*入口参数:(无)
*出口参数:(无)
*返回值: (无)
*/
void CCEComm::CloseRead()
{
if(m_hComm!=INVALID_HANDLE_VALUE)
{
//关闭读线程
if(m_hReadCloseEvent!=NULL) SetEvent(m_hReadCloseEvent);
//设置所有事件无效无效
SetCommMask(m_hComm, 0);
//清空所有将要读的数据
PurgeComm( m_hComm, PURGE_RXCLEAR );
//等待10秒,如果读线程没有退出,则强制退出
if (WaitForSingleObject(m_hReadThread,m_nCloseDelayTime) == WAIT_TIMEOUT)
{
TerminateThread(m_hReadThread,0);
}
if(m_hReadCloseEvent!=NULL)
{
CloseHandle(m_hReadCloseEvent);
m_hReadCloseEvent = NULL;
}
if(m_hReadThread!=NULL)
{
CloseHandle(m_hReadThread);
m_hReadThread = NULL;
}
}
}
void CCEComm::CloseWrite()
{
if(m_hComm!=INVALID_HANDLE_VALUE)
{
//关闭写线程
if(m_hWriteCloseEvent!=NULL) SetEvent(m_hWriteCloseEvent);
//清空所有将要写的数据
PurgeComm( m_hComm, PURGE_TXCLEAR );
//等待10秒,如果读线程没有退出,则强制退出
if (WaitForSingleObject(m_hWriteThread,m_nCloseDelayTime) == WAIT_TIMEOUT)
{
TerminateThread(m_hWriteThread,0);
}
if(m_hWriteCloseEvent!=NULL)
{
CloseHandle(m_hWriteCloseEvent);
m_hWriteCloseEvent = NULL;
}
if(m_hWriteThread!=NULL)
{
CloseHandle(m_hWriteThread);
m_hWriteThread = NULL;
}
}
}
void CCEComm::ClosePort()
{
if(m_hComm!=INVALID_HANDLE_VALUE)
{
//关闭读线程
CloseRead();
//关闭写线程
CloseWrite();
//关闭串口
CloseHandle (m_hComm);
m_hComm = INVALID_HANDLE_VALUE;
m_nPort = 0;
}
}
void CCEComm::SetCloseDelayTime(UINT t)
{
if(t<1000) t=1000;
m_nCloseDelayTime = t;
}
/*
*函数介绍:向串口发送数据
*入口参数:buf : 将要往串口写入的数据的缓冲区
bufLen : 将要往串口写入的数据的缓冲区长度
*出口参数:(无)
*返回值:TRUE:表示成功地将要发送的数据传递到写线程消息队列。
FALSE:表示将要发送的数据传递到写线程消息队列失败。
注视:此处的TRUE,不直接代表数据一定成功写入到串口了。
*/
BOOL CCEComm::SendPort(const BYTE *buf,int bufLen)
{
//将要发送的数据传递到写线程消息队列
BYTE * bufsend = new BYTE[bufLen]; //传送完成后自动释放内存
CopyMemory(bufsend,buf,bufLen);
if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
WPARAM(bufLen), LPARAM(bufsend)))
{
return TRUE;
};
return FALSE;
}
BOOL CCEComm::SendPort(LPCTSTR szSend)
{
CString tmpstr = szSend; //复制要发送的字符串
int charlen = WideCharToMultiByte( //转换Unicode到Ansi
CP_ACP,
WC_COMPOSITECHECK | WC_DEFAULTCHAR,
tmpstr.GetBuffer(tmpstr.GetLength()),
-1,
NULL, //转换到缓冲区中
0,
0,
0
);
tmpstr.ReleaseBuffer();
charlen-=1;
if(charlen<=0) return FALSE;
BYTE * buf = new BYTE[charlen];//传送完成后自动释放内存
ZeroMemory(buf,charlen); //缓冲区清零
WideCharToMultiByte( //转换Unicode到Ansi
CP_ACP,
WC_COMPOSITECHECK | WC_DEFAULTCHAR,
tmpstr.GetBuffer(tmpstr.GetLength()),
-1,
(char*)buf, //转换到缓冲区中
charlen,
0,
0
);
tmpstr.ReleaseBuffer();
if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
WPARAM(charlen), LPARAM(buf)))
{
return TRUE;
};
return FALSE;
}
BOOL CCEComm::SendPortU(LPCTSTR szSend)
{
CString tmpstr = szSend; //复制要发送的字符串
int charlen = tmpstr.GetLength();
charlen*=2;
if(charlen<=0) return FALSE;
BYTE * buf = new BYTE[charlen];//传送完成后自动释放内存
ZeroMemory(buf,charlen); //缓冲区清零
_tcscpy((WCHAR*)buf,tmpstr);
if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
WPARAM(charlen), LPARAM(buf)))
{
return TRUE;
};
return FALSE;
}
void CCEComm::SetPortReceive(CWnd* pWnd,ONSERIESREAD proc)
{
m_pPortOwner = pWnd;
m_OnSeriesRead = proc;
};
//串口读线程函数
DWORD CCEComm::ReadThreadFunc(LPVOID lparam)
{
CCEComm *ceSeries = (CCEComm*)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);
}
delete[] readBuf;
}
}
//如果收到读线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hReadCloseEvent,0) == WAIT_OBJECT_0)
{
break;
}
}
return 0;
}
//串口写线程函数
DWORD CCEComm::WriteThreadFunc(LPVOID lparam)
{
CCEComm *ceSeries = (CCEComm*)lparam;
MSG msg;
DWORD dwWriteLen = 0;
BYTE * buf = NULL;
while (TRUE)
{
//如果捕捉到线程消息
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.hwnd != 0 )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
if (msg.message == CM_THREADCOMMWRITE)
{
//向串口写
buf = (BYTE*)msg.lParam;
dwWriteLen = msg.wParam;
//向串口写
WritePort(ceSeries->m_hComm,buf,dwWriteLen);
//删除动态分配的内存
delete[] buf;
}
}
//如果收到写线程退出信号,则退出线程
if (WaitForSingleObject(ceSeries->m_hWriteCloseEvent,0) == WAIT_OBJECT_0)
{
break;
}
}
return 0;
}
//私用方法,用于向串口写数据,被写线程调用
BOOL CCEComm::WritePort(HANDLE hComm,const BYTE *buf,DWORD bufLen)
{
DWORD dwNumBytesWritten;
DWORD dwHaveNumWritten =0 ; //已经写入多少
ASSERT(hComm != INVALID_HANDLE_VALUE);
do
{
if (WriteFile (hComm, //串口句柄
buf+dwHaveNumWritten, //被写数据缓冲区
bufLen - dwHaveNumWritten, //被写数据缓冲区大小
&dwNumBytesWritten, //函数执行成功后,返回实际向串口写的个数
NULL)) //此处必须设置NULL
{
dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;
//写入完成
if (dwHaveNumWritten == bufLen)
{
break;
}
Sleep(10);
}
else
{
return FALSE;
}
}while (TRUE);
return TRUE;
}
/*
*函数介绍:打开串口
*入口参数:portNo :串口号
baud :波特率
parity :奇偶校验
databits :数据位
stopbits :停止位
maxblock :最大数据块
*出口参数:(无)
*返回值:TRUE:成功打开串口;FALSE:打开串口失败
*/
BOOL CCEComm::OpenPort(BYTE portNo, DWORD baud, BYTE parity,
BYTE databits, BYTE stopbits, DWORD maxblock)
{
DCB commParam;
TCHAR szPort[15];
// 已经打开的话,直接返回
if (m_hComm != INVALID_HANDLE_VALUE)
{
return TRUE;
}
//ASSERT(portNo > 0 && portNo < 5);
//设置串口名
m_nPort = portNo;
wsprintf(szPort, _T("COM%d:"), m_nPort);
//打开串口
m_hComm = CreateFile(
szPort,
GENERIC_READ | GENERIC_WRITE, //允许读和写
0, //独占方式(共享模式)
NULL,
OPEN_EXISTING, //打开而不是创建(创建方式)
0,
NULL
);
if (m_hComm == INVALID_HANDLE_VALUE)
{
// 无效句柄,返回。
TRACE(_T("CreateFile 返回无效句柄"));
return FALSE;
}
// 得到打开串口的当前属性参数,修改后再重新设置串口。
// 设置串口的超时特性为立即返回。
if(!GetSeriesState(&commParam)) return FALSE;
commParam.BaudRate = baud; // 设置波特率
commParam.fBinary = TRUE; // 设置二进制模式,此处必须设置TRUE
commParam.fParity = TRUE; // 支持奇偶校验
commParam.ByteSize = databits; // 数据位,范围:4-8
commParam.StopBits = stopbits; // 停止位
commParam.Parity = parity; // 校验模式
commParam.fOutxCtsFlow = FALSE; // No CTS output flow control
commParam.fOutxDsrFlow = FALSE; // No DSR output flow control
//commParam.fDtrControl = DTR_CONTROL_ENABLE; // DTR flow control type
commParam.fDsrSensitivity = FALSE; // DSR sensitivity
commParam.fTXContinueOnXoff = TRUE; // XOFF continues Tx
commParam.fOutX = FALSE; // No XON/XOFF out flow control
commParam.fInX = FALSE; // No XON/XOFF in flow control
commParam.fErrorChar = FALSE; // Disable error replacement
commParam.fNull = FALSE; // Disable null stripping
//commParam.fRtsControl = RTS_CONTROL_ENABLE; // RTS flow control
commParam.fAbortOnError = FALSE; // 当串口发生错误,并不终止串口读写
if(!SetSeriesState(&commParam)) return FALSE;
//设置串口读写时间
COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts (m_hComm, &CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
if(!SetSeriesTimeouts(&CommTimeOuts)) return FALSE;
//指定端口监测的事件集
SetCommMask (m_hComm, EV_RXCHAR | EV_CTS | EV_DSR | EV_TXEMPTY);
//分配设备缓冲区
SetupComm(m_hComm,maxblock,maxblock);
//初始化缓冲区中的信息
PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
//创建读串口线程
m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);
m_hReadCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
//创建写串口线程
m_hWriteThread = CreateThread(NULL,0,WriteThreadFunc,this,0,&m_dwWriteThreadID);
m_hWriteCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
if( (m_hReadThread==NULL)
||(m_hReadCloseEvent==NULL)
||(m_hWriteThread==NULL)
||(m_hWriteCloseEvent==NULL) )
{
return FALSE;
}
TRACE(_T("串口打开成功"));
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -