C++实现上位机4:实现串口控制类之派生类CSerialPort实现1

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haimianjie2012/article/details/82971737

C++实现上位机3:实现串口控制类之抽象基类设计,前文已经讲解了抽象基类的设计,这里不在详述。

CSerialPort类继承了前文的CComminicationTool类,继承了打开连接,断开连接,发送数据,接收数据四个方法,本文先看CSerialPort的头文件定义,然后对其中的主要成员函数一个接一个挨着讲解。

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();
};

打开连接Connect

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 

打开连接OpenSerialPort()

在用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

猜你喜欢

转载自blog.csdn.net/haimianjie2012/article/details/82971737