📄 multithreadserial.cpp
字号:
/*****************************************************************
||文件 : MultiThreadSerial.cpp(多线程串口通信类)
||编者 : 许伟群
||EMail: xuweiqun@126.com
||QQ : 12626946
||日期 : 2004-05
||修改 : 2005-09
||使用 :
|| 1、设置DCB
|| 最好使用简单设置(4个主要参数)SetDCB(int nBaudRate,int nDataBit,int nCheckBit,int nStopBit );
|| 也可以自定义设置SetDCB(DCB dcb)(对各个变量不熟悉,自定义很容易出错)
|| 不设置默认为:波特率9600 数据位8 偶校验 停止位1
|| 2、初使化串口InitComm(传入串口号和窗口句柄m_hWnd)
|| 3、BeginComm启动串口接收数据的线程
|| 4、当串口收到数据,向m_hWnd发送WM_ACTIVE_TRANS消息,并且发送了串口号
|| 在消息处理函数中处理数据(通过串口号判断是哪个串口对象来接收数据)
|| 然后调用ReceiveData函数接收数据.
|| 5、写数据通过WriteComm函数
******************************************************************/
#include "stdafx.h"
#include "MultiThreadSerial.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
MultiThreadSerial::MultiThreadSerial()
{
m_bCommConnected = false;//端口连接标志
memset(m_sRtnData,0x00,sizeof(m_sRtnData));
m_bComIsOpen = false;
bCommRxSign = false;
//默认DCB设置
m_nBaudRate = CBR_9600 ;
m_nDataBit = 8;
m_nCheckBit = EVENPARITY;
m_nStopBit = ONESTOPBIT;
m_DCB.DCBlength = sizeof(DCB);
m_DCB.BaudRate = m_nBaudRate;
m_DCB.ByteSize = m_nDataBit;
m_DCB.Parity = m_nCheckBit;
m_DCB.StopBits = m_nStopBit;
m_DCB.fOutxDsrFlow = false;
m_DCB.fOutxCtsFlow = false;
m_DCB.fDtrControl = RTS_CONTROL_DISABLE;
m_DCB.fRtsControl = RTS_CONTROL_DISABLE;
m_DCB.fInX = false;
m_DCB.fOutX = false;
m_DCB.fBinary = TRUE;
m_DCB.fParity = TRUE;
//m_DCB.wReserved = 0;
}
MultiThreadSerial::~MultiThreadSerial()
{
}
UINT jThreadFunction(LPVOID lpParam)
{
//线程函数主体,监视串口
//AfxMessageBox("进入线程"); //测试
MultiThreadSerial *pComm = ( MultiThreadSerial*)lpParam;
OVERLAPPED os;
DWORD dwEventMask, dwTransfer;
DWORD dwErrorFlags;
COMSTAT ComStat;
memset(&os, 0, sizeof(OVERLAPPED));
os.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //FALSE: nonsignaled
if (os.hEvent == NULL)
{
return FALSE;
}
if (!SetCommMask(pComm->m_hCom, EV_RXCHAR))
return FALSE;
//Loop until user requests disconnect
while (pComm->ComIsConnected())
{
ClearCommError(pComm->m_hCom, &dwErrorFlags, &ComStat);
if(ComStat.cbInQue) //有数据
{
//AfxMessageBox("进入COMSTAT"); //测试
pComm->bCommRxSign = true;
ResetEvent(pComm->hPostMsgEvent);
pComm->OnCommRecvNotify(0,1);
WaitForSingleObject(pComm->hPostMsgEvent, 0xFFFFFFFF);
//AfxMessageBox("waitforsingleobject"); //测试
continue;
}
dwEventMask = 0;
if (!WaitCommEvent(pComm->m_hCom, &dwEventMask, &os))// dwEventMask: receive event
{
//WaitCommEvent()没有等到结果,如果ERROR_IO_PENDING == GetLastError()
//就用GetOverlappedResult()来等待。
if (ERROR_IO_PENDING == GetLastError())
{
//AfxMessageBox("进入等待"); //测试
GetOverlappedResult(pComm->m_hCom, &os, &dwTransfer, TRUE); //dwTransfer:actual bytes count
//TRUE:If TRUE, the function does not return until the operation has been completed.
}
}
if ((dwEventMask & EV_RXCHAR) == EV_RXCHAR)
{
//Sets the state of the event to nonsignaled until explicitly set to signaled by the SetEvent member function.
pComm->bCommRxSign = true;
ResetEvent(pComm->hPostMsgEvent);
pComm->OnCommRecvNotify(0, 1);
//AfxMessageBox("进入EventMask,等待事件"); //测试
WaitForSingleObject(pComm->hPostMsgEvent, 0xFFFFFFFF);
}
}
CloseHandle(os.hEvent);
return TRUE;
}
bool MultiThreadSerial::InitComm(int nCom , HWND hWnd)
{
m_hWnd = hWnd; //是主程序的窗口句柄,此参数必须传入,否则数据不能
//响应到主程序中去
m_nCom = nCom;
CString sCommPort;
sCommPort.Format( "COM%d", m_nCom );
HANDLE hCom;
hCom= CreateFile(sCommPort, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
NULL); //以重叠I/O的形式打开串口
m_hCom = hCom;
if(m_hCom == INVALID_HANDLE_VALUE)
{
m_bComIsOpen=false;
return false;
}
SetupComm(m_hCom, COMM232GETDATAMAX, COMM232SENDDATAMAX);
COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts(m_hCom, &CommTimeOuts);
if(!SetCommMask(m_hCom, EV_RXCHAR))
{
return false;
}
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;//20;
CommTimeOuts.ReadTotalTimeoutConstant = 0;//1000;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;//20;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;//1000
SetCommTimeouts(m_hCom, &CommTimeOuts);
DCB dcb;
dcb.DCBlength = sizeof(DCB);
GetCommState(m_hCom, &dcb);
dcb.BaudRate = m_DCB.BaudRate;
dcb.ByteSize = m_DCB.ByteSize;
dcb.Parity = m_DCB.Parity;
dcb.StopBits = m_DCB.StopBits;
dcb.fOutxDsrFlow = m_DCB.fOutxDsrFlow;
dcb.fOutxCtsFlow = m_DCB.fOutxCtsFlow;
dcb.fDtrControl = m_DCB.fDtrControl;
dcb.fRtsControl = m_DCB.fRtsControl;
dcb.fInX = m_DCB.fInX;
dcb.fOutX = m_DCB.fOutX;
dcb.fBinary = m_DCB.fBinary;
dcb.fParity = m_DCB.fParity;
//dcb.wReserved = 0;
if(!SetCommState(m_hCom,&dcb))
return false;
if((hPostMsgEvent = CreateEvent(NULL, TRUE, TRUE, NULL))==NULL) //有信号状态
return false;
PurgeComm( m_hCom, PURGE_RXCLEAR | PURGE_TXABORT |PURGE_TXCLEAR| PURGE_RXABORT);
m_bComIsOpen = true;
return true;
}
DWORD MultiThreadSerial::WriteComm(unsigned char *buf, DWORD dwLength)
{
BOOL fState;
DWORD l_dwRes;
DWORD length = dwLength;
COMSTAT ComStat;
DWORD dwErrorFlags = 0;
OVERLAPPED osWrite = {0} ;
if((osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))==NULL)
{
length = 0;
//AfxMessageBox("Event失败"); //测试 :结果;没经过
return length;
}
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
fState = WriteFile(m_hCom, buf, length, &length, &osWrite);
if(!fState)
{
if(GetLastError() == ERROR_IO_PENDING)
{
l_dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
switch(l_dwRes)
{
case WAIT_OBJECT_0:
if (!GetOverlappedResult(m_hCom, &osWrite, &length, FALSE))
{
length = 0;
}
else
{
return length;
}
break;
default:
length = 0;
break;
}
}
else
length = 0;
}
return length;
}
DWORD MultiThreadSerial::ReadComm(unsigned char *buf, DWORD dwLength )
{
DWORD length = 0;
COMSTAT ComStat;
DWORD dwErrorFlags;
Sleep(250);
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
length = min(dwLength, ComStat.cbInQue);
///////////////////////////////////////////////////////////// 测试
// 以下是自己添加代码: 为了解决ReadFile,如果不加ReadFile返回0,
// 加代码,直到读完,返回 length
//////////////////////////////////////////////////////////// 测试
OVERLAPPED osRead = {0};
BOOL l_bWaitingOnRead = FALSE; //用来检测是否在读
osRead.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
if(osRead.hEvent == NULL)
{
return FAIL;
}
if(!ReadFile(m_hCom, buf, length, &length, &osRead))
{
if(GetLastError() != ERROR_IO_PENDING)
{
length = FAIL;
//AfxMessageBox("读失败2,ReadFile"); //测试
}
else
{
l_bWaitingOnRead = TRUE;
}
}
else
{
return length;
}
DWORD l_dwRes;
if(l_bWaitingOnRead)
{
l_dwRes = WaitForSingleObject(osRead.hEvent, 10 * 1000);
switch(l_dwRes)
{
case WAIT_OBJECT_0:
if (!GetOverlappedResult(m_hCom, &osRead, &length, FALSE))
{
length = FAIL;
}
else
{
return length;
}
break;
default:
length = FAIL;
}
}
CloseHandle(osRead.hEvent);
return length;
}
/////////////////////////////////////////////////////////////
void MultiThreadSerial::CloseComm()
{
m_bCommConnected = false;
m_bComIsOpen=false;
SetCommMask(m_hCom, 0);
//Clears the DTR (data-terminal-ready) signal
EscapeCommFunction(m_hCom, CLRDTR);
//清除操作
PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
CloseHandle(m_hCom);
pThread = NULL;
}
bool MultiThreadSerial::BeginComm()
{
if (!m_bComIsOpen) return false;
m_bCommConnected = true;
if((pThread = AfxBeginThread(jThreadFunction, this)) == NULL)
{
m_bCommConnected = false;
CloseHandle(m_hCom);
return false;
}
else
{
//函数会建立一个辅助线程并暂时将其挂起。
//调用CWinThread:: ResumeThread使线程开始运行
pThread->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
pThread->ResumeThread();
//AfxMessageBox("线程运行完了"); //测试
EscapeCommFunction(m_hCom, SETDTR); //Sends the DTR (data-terminal-ready) signal.
}
return true;
}
//bool MultiThreadSerial::ChangeBaud()
//{
// //此函数现在没有用到。
// if(hCom==NULL)
// return false;
// COMMTIMEOUTS CommTimeOuts;
// GetCommTimeouts(hCom, &CommTimeOuts);
// if(!SetCommMask(hCom, EV_RXCHAR))
// {
// return false;
// }
// SetupComm(hCom, 4096, 4096);
// CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
// CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
// CommTimeOuts.ReadTotalTimeoutConstant = 0;
// CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
// CommTimeOuts.WriteTotalTimeoutConstant = 5000;
// SetCommTimeouts(hCom, &CommTimeOuts);
//
// DCB Dcb;
// Dcb.DCBlength = sizeof(DCB);
// GetCommState(hCom,&Dcb);
// Dcb.BaudRate=iBaud;
// Dcb.ByteSize=8;
// Dcb.Parity=EVENPARITY;
// Dcb.StopBits=ONESTOPBIT;
// Dcb.fOutxDsrFlow = false;
// Dcb.fOutxCtsFlow = false;
// Dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
// Dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
// Dcb.fInX = Dcb.fOutX = false;
// //Dcb.XonChar = ASCII_XON;
// //Dcb.XoffChar = ASCII_XOFF;
// Dcb.XonLim = 100;
// Dcb.XoffLim = 100;
// Dcb.fBinary = TRUE;
// Dcb.fParity = TRUE;
// if(!SetCommState(hCom,&Dcb))
// return false;
// return true;
//}
void MultiThreadSerial::OnCommRecvNotify(WPARAM wParam, LPARAM lParam)
{
//取得数据缓冲
m_nCommGetCounter = ReadComm((unsigned char *)m_sCommGetBuffer,COMM232GETDATAMAX);
if(m_nCommGetCounter == 0)
{
SetEvent(hPostMsgEvent); //根本就没有取到数据,所以返回
return;
}
memset(m_sRtnData, 0x00, sizeof(m_sRtnData)); //每一次都必须初始化
memcpy(m_sRtnData, m_sCommGetBuffer, m_nCommGetCounter*sizeof(BYTE));
memset(m_sCommGetBuffer, 0x00, COMM232GETDATAMAX * sizeof(BYTE)); //清空接收缓冲
//提示接收数据,将串口号传送出去,以便判断哪个串口接收了数据
::SendMessage(m_hWnd, WM_ACTIVE_TRANS, m_nCom, 0);
Sleep(20);
//允许发送下一个WM_COMMNOTIFY消息
SetEvent(hPostMsgEvent);
}
void MultiThreadSerial::SetDCB(DCB dcb)
{
ZeroMemory(&m_DCB,sizeof(DCB));
memcpy(&m_DCB,&dcb,sizeof(DCB));
}
void MultiThreadSerial::SetDCB(int nBaudRate,int nDataBit,int nCheckBit,int nStopBit)
{
///////////////设置波特率
m_nBaudRate = nBaudRate;
m_DCB.BaudRate = nBaudRate;
////////////////设置数据位
m_nDataBit = nDataBit;
m_DCB.ByteSize = nDataBit;
/////////////////设置校验位
m_nCheckBit = nCheckBit;
m_DCB.Parity = nCheckBit;
/////////////////设置停止位
m_nStopBit = nStopBit;
m_DCB.StopBits = nStopBit;
}
//////////取得串口号
int MultiThreadSerial::GetComNum()
{
return m_nCom;
}
//////////取得速率
int MultiThreadSerial::GetBaudRate()
{
return m_nBaudRate;
}
//////取得数据位
int MultiThreadSerial::GetDataBit()
{
return m_nDataBit;
}
///////////取得校验位
int MultiThreadSerial::GetCheckBit()
{
return m_nCheckBit;
}
///////取得停止位
int MultiThreadSerial::GetStopBit()
{
return m_nStopBit;
}
//串口是否打开
bool MultiThreadSerial::ComIsOpen()
{
return m_bComIsOpen;
}
//线程是否启动
bool MultiThreadSerial::ComIsConnected()
{
return m_bCommConnected;
}
void MultiThreadSerial::ReceiveData(BYTE* psz)
{
memcpy(psz, m_sRtnData, sizeof(m_sRtnData));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -