头文件
// SerialPort.h: interface for the CSerialPort class.
// 类名: CSerialPort
// 创建人: 郑新华
// 创建日期:2005-7-13
// 概述:该类封装了对串口的基本操作,目前为同步操作,日后逐渐完善为同步
// 异步可配置状态
//
#if !defined(AFX_SERIALPORT_H__5F418CEB_1BFD_4A54_9ABD_4984A825E4CF__INCLUDED_)
#define AFX_SERIALPORT_H__5F418CEB_1BFD_4A54_9ABD_4984A825E4CF__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
typedef struct {
//串口号
DWORD m_dwPort;
//波特率
DWORD m_dwBaudRate;
//停止位
DWORD m_dwStopBit;
//奇偶校验
//DWORD m_dwParity;
char m_chrParity;
//字节大小
BYTE m_bytByteSize;
//串口输入缓冲大小
DWORD m_dwInputSize;
//串口输出缓冲大小
DWORD m_dwOutputSize;
//串口句柄
HANDLE m_hCommHandle;
//是否同步
BOOL m_bSync;
}UDT_PortParam;
class CSerialPort
{
public:
BOOL IsOpen();
//获取串口配置参数
UDT_PortParam GetParam();
//设置串口配置
void SetParam(UDT_PortParam udtParam);
//向串口写数据
DWORD Write(char* pszBuffer, DWORD dwBufferLen);
//从串口读数据
DWORD Read(char* pszBuffer, DWORD dwBufferLen, DWORD dwWaitTime = 20);
//关闭串口
void Close();
//打开串口
BOOL Open();
CSerialPort(UDT_PortParam udtPortParam);
CSerialPort();
virtual ~CSerialPort();
protected:
char szPort[20];
private:
BOOL Setup();
UDT_PortParam m_udtPortParam;
};
#endif // !defined(AFX_SERIALPORT_H__5F418CEB_1BFD_4A54_9ABD_4984A825E4CF__INCLUDED_)
cpp文件
// SerialPort.cpp: implementation of the CSerialPort class.
//
//
#include "stdafx.h"
#include "Comm.h"
#include "SerialPort.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CSerialPort::CSerialPort()
{
m_udtPortParam.m_dwBaudRate = 9600;
m_udtPortParam.m_dwPort = 1;
m_udtPortParam.m_bytByteSize = 8;
m_udtPortParam.m_dwStopBit = ONESTOPBIT;
//m_udtPortParam.m_dwParity = NOPARITY;
m_udtPortParam.m_chrParity = 'N';
m_udtPortParam.m_dwInputSize = 4096;
m_udtPortParam.m_dwOutputSize = 4096;
m_udtPortParam.m_hCommHandle = INVALID_HANDLE_VALUE;
m_udtPortParam.m_bSync = TRUE;
}
CSerialPort::~CSerialPort()
{
Close();
}
CSerialPort::CSerialPort(UDT_PortParam udtPortParam)
{
m_udtPortParam = udtPortParam;
}
/***************************************************************************
*功能: 打开串口
*参数: 无
*返回值:执行成功返回TRUE,否则返回FALSE
***************************************************************************/
BOOL CSerialPort::Open()
{
ASSERT(m_udtPortParam.m_dwPort >= 1 && m_udtPortParam.m_dwPort <= 1024);
//组合成欲打开的串口名
memset(szPort, '/0', 20);
strcpy(szPort, ".//COM");
char p[5];
ltoa(m_udtPortParam.m_dwPort, p, 10);
strcat(szPort, p);
TRACE1("/n串口为:%s", szPort);
if(IsOpen())
Close();
m_udtPortParam.m_hCommHandle = CreateFile(
szPort,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if(m_udtPortParam.m_hCommHandle == INVALID_HANDLE_VALUE)
return FALSE;
//设置缓冲区
if(!::SetupComm(m_udtPortParam.m_hCommHandle, m_udtPortParam.m_dwInputSize, m_udtPortParam.m_dwOutputSize))
{
Close();
return FALSE;
}
//设置超时时间
COMMTIMEOUTS _CO;
if(!::GetCommTimeouts(m_udtPortParam.m_hCommHandle, &_CO))
return FALSE;
_CO.ReadIntervalTimeout = 0xFFFFFFFF;
_CO.ReadTotalTimeoutMultiplier = 0;
_CO.ReadTotalTimeoutConstant = 0;
_CO.WriteTotalTimeoutMultiplier = 0;
_CO.WriteTotalTimeoutConstant = 2000;
if(!::SetCommTimeouts(m_udtPortParam.m_hCommHandle, &_CO))
{
Close();
return FALSE;
}
//清空串口缓冲区
if(!::PurgeComm(m_udtPortParam.m_hCommHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ))
{
Close();
return FALSE;
}
return Setup();
}
/*********************************************************************************
*功能: 关闭串口
*参数: 无
*返回值:无
*********************************************************************************/
void CSerialPort::Close()
{
if(IsOpen())
{
::CloseHandle(m_udtPortParam.m_hCommHandle);
m_udtPortParam.m_hCommHandle = INVALID_HANDLE_VALUE;
}
}
/***************************************************************************
*功能: 读取串口
*参数: pszBuffer 数据存放缓冲区首地址
* dwBufferLen 缓冲长度
* dwWaitTime 等待时间,默认20毫秒
*返回值:执行失败返回0,否则为读出数据长度
****************************************************************************/
DWORD CSerialPort::Read(char *pszBuffer, DWORD dwBufferLen, DWORD dwWaitTime)
{
ASSERT(pszBuffer != NULL);
if(!IsOpen())
{
TRACE0("/n串口没有打开!");
return 0;
}
COMSTAT Stat;
DWORD dwError;
//清除错误
if(::ClearCommError(m_udtPortParam.m_hCommHandle, &dwError, &Stat) && dwError > 0)
{
//清空输入缓冲区
::PurgeComm(m_udtPortParam.m_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR);
TRACE0("/n清除错误失败!");
return 0;
}
//Sleep(500);
pszBuffer[0] = '/0';
unsigned long uReadLength = 0;
//dwBufferLen = dwBufferLen - 1 > Stat.cbInQue ? Stat.cbInQue : dwBufferLen - 1;
//同步读取
if(m_udtPortParam.m_bSync)
{
if(!::ReadFile(m_udtPortParam.m_hCommHandle, pszBuffer, dwBufferLen, &uReadLength, NULL))
{
TRACE0("/n读取串口失败!");
if(::GetLastError() != ERROR_IO_PENDING)
uReadLength = 0;
}
TRACE1("/nReadFile读出%d个字符!", uReadLength);
//清空缓冲区
::PurgeComm(m_udtPortParam.m_hCommHandle, PURGE_RXABORT | PURGE_RXCLEAR);
}
else //异步
{
OVERLAPPED _ReadOverlapped;
memset(&_ReadOverlapped, 0 ,sizeof(_ReadOverlapped));
_ReadOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
ASSERT(_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE);
if(!::ReadFile(m_udtPortParam.m_hCommHandle, pszBuffer, dwBufferLen, &uReadLength, &_ReadOverlapped))
{
//结束异步IO
if(::GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(_ReadOverlapped.hEvent, dwWaitTime);
if(!::GetOverlappedResult(m_udtPortParam.m_hCommHandle, &_ReadOverlapped, &uReadLength, false))
{
//其他错误
if(::GetLastError() == ERROR_IO_INCOMPLETE)
uReadLength = 0;
}
else
uReadLength = 0;
}
}
if(_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE)
CloseHandle(_ReadOverlapped.hEvent);
}
pszBuffer[uReadLength] = '/0';
return uReadLength;
}
/*********************************************************************************
*功能: 向串口写入数据
*参数: pszBuffer 欲写入数据首地址
* dwBufferLen 欲写入数据长度
*返回值:执行失败返回0,否则为写入数据长度
**********************************************************************************/
DWORD CSerialPort::Write(char *pszBuffer, DWORD dwBufferLen)
{
ASSERT(pszBuffer != NULL);
if(!IsOpen())
return FALSE;
DWORD dwError;
//清除错误
if(::ClearCommError(m_udtPortParam.m_hCommHandle, &dwError, NULL) && dwError > 0)
//清空输入缓冲区
::PurgeComm(m_udtPortParam.m_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR);
unsigned long uWriteLength = 0;
//同步写入
if(m_udtPortParam.m_bSync)
{
if(!::WriteFile(m_udtPortParam.m_hCommHandle, pszBuffer, dwBufferLen, &uWriteLength, NULL))
if(::GetLastError() != ERROR_IO_PENDING)
uWriteLength = 0;
}
else //异步
{
OVERLAPPED _WriteOverlapped;
memset(&_WriteOverlapped, 0 ,sizeof(_WriteOverlapped));
_WriteOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
ASSERT(_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE);
if(!::WriteFile(m_udtPortParam.m_hCommHandle, pszBuffer, dwBufferLen, &uWriteLength, &_WriteOverlapped))
if(::GetLastError() != ERROR_IO_PENDING)
uWriteLength = 0;
if(_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE)
CloseHandle(_WriteOverlapped.hEvent);
}
return uWriteLength;
}
void CSerialPort::SetParam(UDT_PortParam udtParam)
{
m_udtPortParam = udtParam;
}
UDT_PortParam CSerialPort::GetParam()
{
return m_udtPortParam;
}
BOOL CSerialPort::IsOpen()
{
return m_udtPortParam.m_hCommHandle != INVALID_HANDLE_VALUE;
}
/****************************************************************************
*功能: 设置波特率、停止位等
*参数: 无
*返回值:执行成功返回TRUE,否则返回FALSE
*****************************************************************************/
BOOL CSerialPort::Setup()
{
BOOL bResult = FALSE;
if(IsOpen())
{
DCB dcb;
if(!::GetCommState(m_udtPortParam.m_hCommHandle, &dcb))
return FALSE;
/*
dcb.BaudRate = m_udtPortParam.m_dwBaudRate;
dcb.ByteSize = m_udtPortParam.m_bytByteSize;
dcb.StopBits = m_udtPortParam.m_dwStopBit;
dcb.Parity = m_udtPortParam.m_dwParity;*/
char chrSet[50];
sprintf(chrSet, "%d,%c,%d,%d", m_udtPortParam.m_dwBaudRate, m_udtPortParam.m_chrParity, m_udtPortParam.m_bytByteSize, m_udtPortParam.m_dwStopBit);
if(BuildCommDCB(chrSet, &dcb))
{
if(::SetCommState(m_udtPortParam.m_hCommHandle, &dcb))
bResult = TRUE;
}
}
if(!bResult)
Close();
return bResult;
}