📄 serialcom.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 + -