⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serialcom.cpp

📁 工作中写的一个含串口访问功能的小测试程序
💻 CPP
字号:
// SerialCom.cpp: implementation of the CSerialCom class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SerialCom.h"
#include "TESTUTDlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
HANDLE G_m_hCom;
CSerialCom *pGSerial;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSerialCom::CSerialCom()
{
	m_bConnected = FALSE;
	if((m_hPostMsgEvent=CreateEvent(NULL, TRUE, FALSE, NULL))==NULL)
	{
		AfxMessageBox("创建调用事件对象失败!");
	}
	if((m_hReadSerialEvent=CreateEvent(NULL, TRUE, FALSE, NULL))==NULL)
	{
		AfxMessageBox("创建调用事件对象失败!");
	}
	memset(&(m_osRead), 0, sizeof(OVERLAPPED));
	memset(&(m_osWrite), 0, sizeof(OVERLAPPED));

	// 为重叠读创建事件对象,手工重置,初始化为无信号的
	if((m_osRead.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL))==NULL)
	{
		AfxMessageBox("为重叠读创建事件对象失败!");
	}

	// 为重叠写创建事件对象,手工重置,初始化为无信号的
	if((m_osWrite.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL))==NULL)
	{
		AfxMessageBox("为重叠写创建事件对象失败!");
	}
}

CSerialCom::~CSerialCom()
{
	CloseConnection();
}

DWORD CSerialCom::ReadComm(HANDLE m_hCom,unsigned char *buf,DWORD dwLength)
{
	DWORD length=0;
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	ClearCommError(m_hCom,&dwErrorFlags,&ComStat);
	length=min(dwLength, ComStat.cbInQue);
	ReadFile(m_hCom,buf,length,&length,&m_osRead);
	PurgeComm(m_hCom, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

	return length;
}

DWORD CSerialCom::WriteComm(HANDLE m_hCom,unsigned char *buf,DWORD dwLength)
{
	BOOL fState;
	DWORD length=dwLength;
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	
	int ii = ClearCommError(m_hCom,&dwErrorFlags,&ComStat);
	fState=WriteFile(m_hCom,buf,length,&length,&m_osWrite);
	ii = ClearCommError(m_hCom,&dwErrorFlags,&ComStat);
	if(!fState)
	{
		if(GetLastError()==ERROR_IO_PENDING)
			GetOverlappedResult(m_hCom,&m_osWrite,&length,TRUE);// 等待
		else
			length=0;
	}
	return length;
}
BOOL CSerialCom::ConfigConnection(HANDLE m_hCom)
{
	DCB dcb;

	if(!GetCommState(m_hCom, &dcb))
		return FALSE;

	dcb.fBinary=TRUE;
	switch(m_nBaud)
	{
		case 0: dcb.BaudRate = 1200; break;// 波特率 
			
		case 1: dcb.BaudRate = 2400; break;
			
		case 2: dcb.BaudRate = 4800; break;// 波特率 
			
		case 3:	dcb.BaudRate = 9600; break;
		
		case 4:	dcb.BaudRate = 14400; break;// 波特率 
		
		case 5:	dcb.BaudRate = 19200; break;
		
		case 6:	dcb.BaudRate = 38400; break;// 波特率 

		case 7:	dcb.BaudRate = 57600; break;

		case 8:	dcb.BaudRate = 115200; break;// 波特率 
		
		default: dcb.BaudRate = 9600;   break;
	}
	switch(m_nDataBits)
	{
		case 0: dcb.ByteSize = 7; break;
		case 1:	dcb.ByteSize = 8; break;
		default: dcb.ByteSize = 8; break;
	}


	dcb.fParity=TRUE;
	switch(m_nParity) // 校验设置
	{
		case 0: dcb.Parity=NOPARITY; break;
		case 1: dcb.Parity=ODDPARITY; break;
		case 2: dcb.Parity=EVENPARITY; break;
		default:dcb.Parity=NOPARITY; break;
	}

	switch(m_nStopBits) // 停止位
	{
		case 0:  dcb.StopBits=ONESTOPBIT;   break;
		case 1:  dcb.StopBits=ONE5STOPBITS;	break;
		case 2:  dcb.StopBits=TWOSTOPBITS;	break;
		default: dcb.StopBits=ONESTOPBIT;   break;
	}

	// 硬件流控制设置
	dcb.fOutxCtsFlow=m_nFlowCtrl==1;
	dcb.fRtsControl=m_nFlowCtrl==1?
	RTS_CONTROL_HANDSHAKE:RTS_CONTROL_ENABLE;
	// XON/XOFF流控制设置
	dcb.fInX=dcb.fOutX=m_nFlowCtrl==2;
	dcb.XonChar=XON;
	dcb.XoffChar=XOFF;
	dcb.XonLim=50;
	dcb.XoffLim=50;
	return SetCommState(m_hCom, &dcb);
}
BOOL CSerialCom::OpenConnection()
{
	COMMTIMEOUTS TimeOuts;

	if(m_bConnected)
		return FALSE;

	m_hCom=CreateFile(m_sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
			OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL); // 重叠方式

	if(m_hCom==INVALID_HANDLE_VALUE)
	{
		m_bConnected = FALSE;
		return FALSE;
	}
	SetupComm(m_hCom,MAXBLOCK,MAXBLOCK);
	SetCommMask(m_hCom, EV_RXCHAR);

	// 把间隔超时设为最大,把总超时设为0将导致ReadFile立即返回并完成操作
	TimeOuts.ReadIntervalTimeout=MAXDWORD; 
	TimeOuts.ReadTotalTimeoutMultiplier=0; 
	TimeOuts.ReadTotalTimeoutConstant=0; 
	/* 设置写超时以指定WriteComm成员函数中的
	GetOverlappedResult函数的等待时间*/
	TimeOuts.WriteTotalTimeoutMultiplier=50; 
	TimeOuts.WriteTotalTimeoutConstant=2000;
	SetCommTimeouts(m_hCom, &TimeOuts);
    

	if(ConfigConnection(m_hCom))
	{
		this->m_bConnected = TRUE;
		m_pReadSerialThread = AfxBeginThread(ReadSerialThread,this,THREAD_PRIORITY_NORMAL,
			                                 0,CREATE_SUSPENDED,NULL);
		if(m_pReadSerialThread == NULL)
		{   
			CloseHandle(m_hCom);
			return FALSE;
		}
		else
		{
			m_pReadSerialThread->ResumeThread();
		}
		m_pThread=AfxBeginThread(CommProc, this, THREAD_PRIORITY_NORMAL, 
				                0, CREATE_SUSPENDED, NULL); // 创建并挂起线程
		if(m_pThread==NULL)
		{
			CloseHandle(m_hCom);
			return FALSE;
		}
		else
		{
			m_pThread->ResumeThread(); // 恢复线程运行
		}
	}
	else
	{
		m_bConnected = FALSE;
		CloseHandle(m_hCom);
		return FALSE;
	}
	pGSerial = this;
	G_m_hCom = m_hCom;
	return TRUE;
}

BOOL CSerialCom::CloseConnection()
{
	if(!m_bConnected) return TRUE;
	m_bConnected=FALSE;
	//结束CommProc线程中WaitSingleObject函数的等待
	SetEvent(m_hPostMsgEvent); 
	SetEvent(this->m_hReadSerialEvent);
	//结束CommProc线程中WaitCommEvent的等待
	SetCommMask(m_hCom, 0); 
   
	//等待辅助线程终止
	WaitForSingleObject(m_pThread->m_hThread, INFINITE);
	WaitForSingleObject(m_pReadSerialThread->m_hThread,INFINITE);
	if(CloseHandle(m_hCom))
	{
		return TRUE;
	}
	else
		return FALSE;
}
UINT CommProc(LPVOID pParam) //监视串口字符事件线程
{
	OVERLAPPED os;
	DWORD dwMask, dwTrans;
	COMSTAT ComStat;
	DWORD dwErrorFlags;

	CSerialCom *pSerial = (CSerialCom*)pParam;

	memset(&os, 0, sizeof(OVERLAPPED));
	os.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
	if(os.hEvent==NULL)
	{
		AfxMessageBox("Can't create event object!");
		return (UINT)-1;
	}
	while(pSerial->m_bConnected)
	{
		ClearCommError(pSerial->m_hCom,&dwErrorFlags,&ComStat);
		if(ComStat.cbInQue)
		{
			//通知读串口的线程有串口接收到数据
			SetEvent(pSerial->m_hReadSerialEvent);
			// 无限等待读串口数据的线程完成读串口的任务
			WaitForSingleObject(pSerial->m_hPostMsgEvent, INFINITE);
			ResetEvent(pSerial->m_hPostMsgEvent);
			continue;
		}
		dwMask=0;
		if(!WaitCommEvent(pSerial->m_hCom, &dwMask, &os)) // 重叠操作
		{
			if(GetLastError()==ERROR_IO_PENDING)
				// 无限等待重叠操作结果
				GetOverlappedResult(pSerial->m_hCom, &os, &dwTrans, TRUE);
			else
			{
				CloseHandle(os.hEvent);
				return (UINT)-1;
			}
		}
	}
	CloseHandle(os.hEvent);
	return 0;

}
UINT ReadSerialThread(LPVOID pParam) //读串口数据的线程
{
	DWORD dwDataLen;
	CString str ="",strinfo = "",strAll; 
	CSerialCom *pSerial = (CSerialCom*)pParam;
	UINT length;
	
	static int counter;
	int nCmpResult1,nCmpResult2;
	DWORD dwOffsetAddr;
	char tempbuf[8] = "",temp_cmp_buf1[48] = "",temp_cmp_buf2[48] = "";
    char lpStr[3000] = ""; 
	int ii,RetVal;
	unsigned short pChkSum;
	CTESTUTDlg TestUTDlg; 
	
//	CWnd *pWnd = TestUTDlg.GetDlgItem(IDC_RECVDATA);
	HWND hWnd = ::GetDlgItem(AfxGetMainWnd()->m_hWnd,IDC_RECVDATA);
	
	while(1)
	{
		WaitForSingleObject(pSerial->m_hReadSerialEvent, INFINITE);
		if(!pSerial->m_bConnected) 
		{
			SetEvent(pSerial->m_hPostMsgEvent); 
			return 0L;
		}
		str.Empty();
		strinfo.Empty();
		Sleep(100);
        ZeroMemory(pSerial->RecvBuf,sizeof(pSerial->RecvBuf));
		dwDataLen = pSerial->ReadComm(pSerial->m_hCom,pSerial->RecvBuf,BYTENUMBER);
		str = "\nUT->RTU的数据: ";
		strinfo.Format("%s",pSerial->RecvBuf);
		str = str + strinfo;
        
        int nMaxCount = 2000;   
		::GetWindowText(hWnd,lpStr,nMaxCount);
		strAll.Format("%s\n",lpStr);
		strAll = strAll + str;
		::SetWindowText(hWnd,strAll);
		ResetEvent(pSerial->m_hReadSerialEvent);
		SetEvent(pSerial->m_hPostMsgEvent);
	}
	return 1L;
}
void CSerialCom::CalculateLRC(unsigned char *pByte, int nNumberOfBytes, unsigned short *pChecksum)
{
	//ASCII模式LRC校验
	unsigned char c,temph,templ;
	unsigned int i;
	c=0;
	for(i=0;i<nNumberOfBytes-1;i+=2)
	{
		temph=(pByte[i]<'A') ? pByte[i]-48 : ((pByte[i]<'a') ? pByte[i]-55 : pByte[i]-87);
		templ=(pByte[i+1]<'A') ? pByte[i+1]-48 : ((pByte[i+1]<'a') ? pByte[i+1]-55 : pByte[i+1]-87);
		c=temph*16+templ+c;
	}
	if(nNumberOfBytes%2!=0)
	{
		temph=(pByte[i]<'A') ? pByte[i]-48 : ((pByte[i]<'a') ? pByte[i]-55 : pByte[i]-87);
		c=temph*16+c;
	}
	*pChecksum=~c+1;
}
BOOL CSerialCom::CalculateChecksum(unsigned char * pByte, int nNumberOfBytes,
 							   				   unsigned short *pChecksum, int nChecksumMode /* = BCC_CHECKSUM */)
{
	BOOL bReturn = TRUE;

	if (BCC_CHECKSUM == nChecksumMode)
		CalculateBCC(pByte, nNumberOfBytes, pChecksum);
	else if (LRC_CHECKSUM == nChecksumMode)
		CalculateLRC(pByte, nNumberOfBytes, pChecksum);
	else if (CRC_CHECKSUM == nChecksumMode)
		CalculateCRC(pByte, nNumberOfBytes, pChecksum);
	else
	{
		// this should never happen
		TRACE("Invalid Checksum Mode(%ld), File %s, Line %d\n", nChecksumMode, __FILE__, __LINE__);
		bReturn = FALSE;
	}

	return bReturn;
}
void CSerialCom::CalculateBCC(unsigned char * pByte, int nNumberOfBytes, unsigned short *pChecksum)
{
	for (int nByte = 0; nByte < nNumberOfBytes; nByte++)
	{
		*pChecksum = (unsigned char)((unsigned char)*pChecksum + *pByte);
		pByte++;
	}

}
void CSerialCom::CalculateCRC(unsigned char *pByte, int nNumberOfBytes, unsigned short *pChecksum)
{
	//RTU模式CRC校验
	int nBit;
	unsigned short nShiftedBit;
	*pChecksum=0xffff;
	
	for (int nByte = 0; nByte < nNumberOfBytes; nByte++)
	{
       	*pChecksum ^= *(pByte+nByte);
       	for (nBit=0; nBit<8; nBit++)
		{
       		nShiftedBit=*pChecksum;
       		*pChecksum>>=1;
    		if (nShiftedBit & 0x0001)  *pChecksum^=0xA001;
		}
			
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -