这是基于Window SDK封装的串口通信类
// Serial.h
#ifndef __SERIAL_H__
#define __SERIAL_H__
//
#define DEBUG_VERSION
// 用户消息
#define MSG_SERIAL_OUTPUT_DEBUG WM_USER+123 // 输出调试信息消息 (说明:消息第一个参数为调试信息串指针,响应这个消息可以知道处理进度)
#define FC_DTRDSR 0x01
#define FC_RTSCTS 0x02
#define FC_XONXOFF 0x04
#define ASCII_BEL 0x07
#define ASCII_BS 0x08
#define ASCII_LF 0x0A
#define ASCII_CR 0x0D
#define ASCII_XON 0x11
#define ASCII_XOFF 0x13
#define CLEAR_IN_BUFFER 0x01
#define CLEAR_OUT_BUFFER 0x02
//#define PACK_SIZE 2048
#define PACK_SIZE 1024 //modify zp
class CSerial
{
public:
CSerial();
~CSerial();
BOOL IsOpened(void){ return m_bOpened; }
BOOL Open( int nPort, int nBaud, HWND hWndUser=NULL );
BOOL Close( void );
int WriteData( void *, int );
int ReadData ( void *, int );
void ClearBuffer(int iFlag);
void Flush();
int MySendData(BYTE* btSendData,int iLen,int iTimeOut,BYTE* byRecvBuf);
int MySendReadData(BYTE* btSendData,int iLen,int iTimeOut,BYTE* byRecvBuf);//add zp
protected:
void OutputDebug( TCHAR * pText );
HANDLE m_hComDev;
BOOL m_bOpened;
HWND m_hWndUser;
};
#endif
实现文件 .cpp
// Serial.cpp
#include "stdafx.h"
#include "Serial.h"
CSerial::CSerial()
{
m_hComDev = NULL;
m_bOpened = FALSE;
m_hWndUser = NULL;
}
CSerial::~CSerial()
{
Close();
}
/*-----------------------------------------------------------------------------
功 能:输出调试信息
参数说明:char * pText 信息串
返 回 值:无
说 明:
------------------------------------------------------------------------------*/
void CSerial::OutputDebug( TCHAR * pText )
{
if( m_hWndUser==NULL || pText==NULL )
return;
// 发送调试信息
SendMessage( m_hWndUser, MSG_SERIAL_OUTPUT_DEBUG, (WPARAM)pText, 0 );
}
BOOL CSerial::Open( int nPort, int nBaud, HWND hWndUser )
{
DWORD dwError = 0;
TCHAR szError[128] = {0};
m_hWndUser = hWndUser;
if(m_bOpened)
return TRUE;
TCHAR szPort[32];
TCHAR sszPort[32];
_stprintf_s(sszPort, _T("\\\\.\\COM%d"), nPort);
_stprintf_s( szPort,_T("\\\\.\\COM%d:"), nPort );
// 创建一个串口设备
m_hComDev = CreateFile( sszPort,
GENERIC_READ | GENERIC_WRITE, //访问模式(写/读)
0, //共享模式
NULL, //指向安全属性的指针
OPEN_EXISTING,
NULL,
NULL );
// 判断创建是否成功
//if((DWORD)m_hComDev==0xffffffff || (DWORD)m_hComDev==NULL)
if(m_hComDev == INVALID_HANDLE_VALUE)
{
// dwError = GetLastError();
// _stprintf( szError, _T("Open COM%d with baud rate %d failed, error = %d"), nPort, nBaud, dwError );
// MessageBox( NULL, szError, _T("error"), MB_OK);
return FALSE;
}
//_stprintf( szError, _T("Open COM%d with baud rate %d success."), nPort, nBaud );
//OutputDebug( szError );
// 填写通讯设备控制结构
DCB dcb;
dcb.DCBlength = sizeof( DCB );
GetCommState( m_hComDev, &dcb );
dcb.BaudRate = nBaud;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT; // 原来的
//dcb.StopBits = TWOSTOPBITS;// 潘相熙更改2008-1-15
// 控制设置
if( !SetCommState( m_hComDev, &dcb ) || !SetupComm( m_hComDev,1024*3,1024*3))
{
dwError = GetLastError();
_stprintf_s( szError, _T("SetCommState failed, error = %d"), dwError );
OutputDebug( szError );
CloseHandle(m_hComDev);
return FALSE;
}
// 填写通讯超时参数
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = 11*1000/dcb.BaudRate+1;
CommTimeOuts.ReadTotalTimeoutConstant = 40;
CommTimeOuts.WriteTotalTimeoutMultiplier = 11*1000/dcb.BaudRate+1;
//CommTimeOuts.WriteTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;//modify zp
// 超时设置
if(!SetCommTimeouts( m_hComDev, &CommTimeOuts ))
{
dwError = GetLastError();
_stprintf_s( szError, _T("SetCommTimeouts failed, error = %d"), dwError );
OutputDebug( szError );
CloseHandle(m_hComDev);
return FALSE;
}
m_bOpened = TRUE;
return m_bOpened;
}
BOOL CSerial::Close( void )
{
if( !m_bOpened || m_hComDev == NULL)
return TRUE;
ClearBuffer(CLEAR_IN_BUFFER);
ClearBuffer(CLEAR_OUT_BUFFER);
CloseHandle( m_hComDev );
m_bOpened = FALSE;
m_hComDev = NULL;
return TRUE;
}
// 函数功能:往串口写一串字符
int CSerial::WriteData( void *buffer, int size )
{
if( !m_bOpened || m_hComDev == NULL )
return -1;
DWORD dwError = 0;
TCHAR szError[128] = {0};
BYTE * pBuf = (BYTE*)buffer;
BOOL bWriteSuccess;
DWORD dwBytesWritten;
bWriteSuccess = WriteFile( m_hComDev,
(LPSTR) pBuf,
size,
&dwBytesWritten,
NULL );
if( !bWriteSuccess )
{
dwError = GetLastError();
_stprintf_s( szError, _T("WriteFile failed, error = %d"), dwError );
OutputDebug( szError );
return -1;
}
return( (int)dwBytesWritten );
}
// 函数功能:从串口读一串字符
int CSerial::ReadData( void *receBuf, int limit )
{
if( !m_bOpened || m_hComDev == NULL )
return -1;
DWORD dwError = 0;
TCHAR szError[128] = {0};
BOOL bReadSuccess;
DWORD dwBytesToRead, dwBytesRead, dwErrorFlags;
COMSTAT ComStat;
if( !ClearCommError( m_hComDev, &dwErrorFlags, &ComStat ) )
{
dwError = GetLastError();
_stprintf_s( szError, _T("ClearCommError failed, error = %d"), dwError );
OutputDebug( szError );
return -1;
}
if( !ComStat.cbInQue ) // 串口中有多少数据可以读
return 0;
dwBytesToRead = min( ComStat.cbInQue, (DWORD)limit );
bReadSuccess = ReadFile( m_hComDev,
receBuf,
dwBytesToRead,
&dwBytesRead,
NULL );
if(!bReadSuccess)
{
dwError = GetLastError();
_stprintf_s( szError, _T("ReadFile failed, error = %d"), dwError );
OutputDebug( szError );
return -1;
}
return((int)dwBytesRead);
}
void CSerial::ClearBuffer(int iFlag)
{
if(iFlag & CLEAR_IN_BUFFER)
PurgeComm(m_hComDev, PURGE_RXCLEAR);
if(iFlag & CLEAR_OUT_BUFFER)
PurgeComm(m_hComDev, PURGE_TXCLEAR);
}
void CSerial::Flush()
{
if (m_hComDev)
{
FlushFileBuffers(m_hComDev);
}
}
int CSerial::MySendData(BYTE* btSendData,int iLen,int iTimeOut,BYTE* byRecvBuf)
{
int iRet = 0;
for (int i = 0 ; i < 3 ; i ++)
{
memset(byRecvBuf, 0, PACK_SIZE);
ClearBuffer(CLEAR_IN_BUFFER);
int iSend = WriteData(btSendData, iLen);
if(iSend <= 0)
{
Sleep(100);
continue;;
}
DWORD dwStart = ::GetTickCount();
while(1)
{
iRet = ReadData(byRecvBuf, PACK_SIZE);
if(iRet > 0)
{
if((iRet > 2)&&((byRecvBuf[2]&0xF0)==0xE0))
return -1;//否定回答
Sleep(1);
return iRet;
}
DWORD dwEnd = ::GetTickCount();
if((dwEnd - dwStart) > iTimeOut)
break;
}
}
return iRet;
}
int CSerial::MySendReadData(BYTE* btSendData,int iLen,int iTimeOut,BYTE* byRecvBuf)
{
int iRet = 0;
while(1)
{
memset(byRecvBuf, 0, PACK_SIZE);
ClearBuffer(CLEAR_IN_BUFFER);
int iSend = WriteData(btSendData, iLen);
if(iSend <= 0)
{
Sleep(100);
continue;
}
DWORD dwStart = ::GetTickCount();
while(1)
{
iRet = ReadData(byRecvBuf, PACK_SIZE);
if(iRet > 0)
{
if((iRet > 2)&&((byRecvBuf[2]&0xF0)==0xE0))
return -1;//否定回答
Sleep(1);
return iRet;
}
DWORD dwEnd = ::GetTickCount();
if((dwEnd - dwStart) > iTimeOut)
break;
}
}
return iRet;
}