C++实现上位机3:实现串口控制类之抽象基类设计,前文已经讲解了抽象基类的设计,这里不在详述。
CSerialPort类继承了前文的CComminicationTool类,继承了打开连接,断开连接,发送数据,接收数据四个方法,本文先看CSerialPort的头文件定义,然后对其中的主要成员函数一个接一个挨着讲解。
#pragma once
#include "CComminicationTool.h"
#include "../stdafx.h"
class CSerialPort :public CComminicationTool{
// Construction
public:
CSerialPort();//初始化
~CSerialPort();
// Operations:
public:
#ifdef __AFX_H__
void SetPort(CString COM = L"COM3");//设置端口号
#else
void SetMyPort(std::wstring COM = L"COM3");//设置端口号
#endif
int SetDCB(DWORD BaudRate = 57600, BYTE ByteSize = 8, BYTE Parity = NOPARITY, BYTE StopBits = ONESTOPBIT);//设置波特率 字节 校验
int SetCache(DWORD InBuff = 1024, DWORD OutBuff = 1024);//设置缓存区大小
int SetTimeout(COMMTIMEOUTS timeOuts);//设置超时
std::wstring Ansi2WChar(LPCSTR pszSrc, int nLen);
char m_resver_str[1024];//接受到的数据缓存
private:
void CloseHcom();
bool OpenSerialPort();//打开串口
// Attributes:
private:
#ifdef __AFX_H__
CString m_strCOM;//打开的COM口
#else
std::wstring m_strCOM;//打开的COM口
#endif
COMMTIMEOUTS m_TimeOuts;//设定读超时
DCB m_wdcb;//设置波特率 字节 校验
HANDLE m_hCom;//串口句柄
// Implementation
public:
bool Connect();//连接
bool Connect(std::string com);//连接
bool Disconnect();//不连接
DWORD SendData(void* data, DWORD size);//发送数据 (指向数据的地址,数据大小(单位为字节))
char* ReadData(DWORD& wCount);//读取数据 (数据长度的引用 (单位为字节))
bool IsConnect();
};
bool CSerialPort::Connect(){
if (m_hCom == NULL){
return OpenSerialPort();
}
else{
PrintMessage("已经建立连接");
}
return false;
}
bool CSerialPort::Connect(std::string com){
if (m_hCom == NULL){
SetMyPort(Ansi2WChar(com.c_str(), com.size()));
return OpenSerialPort();
}
else{
PrintMessage("已经建立连接");
}
return false;
}
PrintMessage已经在C++实现上位机3:实现串口控制类之抽象基类设计中定义,不再详述。
函数功能:该函数映射一个字符串到一个宽字符(unicode)的字符串。由该函数映射的字符串没必要是多字节字符组。
函数原型:
int MultiByteToWideChar(
UINT CodePage,
DWORD dwFlags,
LPCSTR lpMultiByteStr,
int cchMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar
);
如果函数运行成功,并且cchWideChar不为零,返回值是由lpWideCharStr指向的缓冲区中写入的宽字符数;如果函数运行成功,并且cchWideChar为零,返回值是接收到待转换字符串的缓冲区所需求的宽字符数大小。
Ansi2WChar()将ANSI编码的字符串转换为宽字符(unicode)的字符串:
std::wstring CSerialPort::Ansi2WChar(LPCSTR pszSrc, int nLen)
{
int nSize = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, nLen, 0, 0);
if (nSize <= 0) return NULL;
WCHAR *pwszDst = new WCHAR[nSize + 1];
if (NULL == pwszDst) return NULL;
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, nLen, pwszDst, nSize);
pwszDst[nSize] = 0;
if (pwszDst[0] == 0xFEFF) // skip Oxfeff
for (int i = 0; i < nSize; i++)
pwszDst[i] = pwszDst[i + 1];
std::wstring wcharString(pwszDst);
delete pwszDst;
return wcharString;
}
SetMyPort()
#ifdef __AFX_H__
void CSerialPort::SetPort(CString COM){
m_strCOM = COM;
}
#else
void CSerialPort::SetMyPort(std::wstring COM){
m_strCOM = COM;
}
#endif
在用ReadFile和WriteFile读写串行口时,需要考虑超时问题。如果在指定的时间内没有读出或写入指定数量的字符,那么ReadFile或WriteFile的操作就会结束。要查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUTS结构。调用SetCommTimeouts可以用某一个COMMTIMEOUTS结构的内容来设置超时。 有两种超时:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延,总超时是指读写操作总共花费的最大时间。写操作只支持总超时,而读操作两种超时均支持。
bool CSerialPort::OpenSerialPort(){
m_hCom = CreateFile(m_strCOM.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (m_hCom == INVALID_HANDLE_VALUE)
{
PrintMessage("打开COM失败");
return false;
}
else
{
memset(&m_TimeOuts, 0, sizeof(m_TimeOuts));
m_TimeOuts.ReadIntervalTimeout = 1;
//如果ReadIntervalTimeout为0,则该值不起作用。
m_TimeOuts.ReadTotalTimeoutMultiplier = 1;
m_TimeOuts.ReadTotalTimeoutConstant = 10;
/*如果值为MAXDWORD,
并且ReadTotalTimeoutConstant和ReadTotalTimeoutMultiplier两个值都为0,
则指定读操作携带已经收到的字符立即返回,即使没有收到任何字符。*/
//设定写超时
m_TimeOuts.WriteTotalTimeoutMultiplier = 50;
m_TimeOuts.WriteTotalTimeoutConstant = 2000;
/*如果 WriteTotalTimeoutMultiplier 和 WriteTotalTimeoutConstant都为0,则在写操作时忽略总超时数。
提示:用户设置通讯超时后,如没有出错,串口已经被打开。*/
if (!SetCommTimeouts(m_hCom, &m_TimeOuts)){//设置超时
PrintMessage("设置超时失败!(set timeout failed)");
CloseHandle(m_hCom);
return false;
}
if (!SetupComm(m_hCom, 1024, 1024)){ //输入缓冲区和输出缓冲区的大小都是1024
PrintMessage("设置缓存区失败!(set cache failed)");
CloseHandle(m_hCom);
return false;
}
if (!GetCommState(m_hCom, &m_wdcb)){
PrintMessage("获取通讯状态字失败!(get ComState failed)");
CloseHandle(m_hCom);
return false;
}
m_wdcb.BaudRate = 57600;//波特率:57600,其他:不变
m_wdcb.ByteSize = 8; //每个字节8位
m_wdcb.Parity = NOPARITY; //无校验
m_wdcb.StopBits = ONESTOPBIT;//1位停止位
if (!SetCommState(m_hCom, &m_wdcb)){
PrintMessage("设置通讯状态字失败!(set ComState failed)");
CloseHandle(m_hCom);
return false;
}
PurgeComm(m_hCom, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR);
}
return true;
}
aa