Bootstrap

QT-C++ 西门子snap7通讯库接口

QT-C++ 西门子snap7通讯库接口

一、核心程序

1.头文件

#pragma once
#include <QObject>
#include <QMutex>
#include <QThread>
#include "ToolSnapGlobal.h"
#include "snap7.h"
/*
特别说明:
西门子PLC使用是大端的数据格式,PC端用是小端数据格式i,需要转换
*/
struct sSnapData;
class TOOL_SNAP_EXPORT cSnapConObject : public QThread
{
	Q_OBJECT

public:
	cSnapConObject(QObject *parent = 0);
	~cSnapConObject();

public:
	static cSnapConObject *getInstance();

public:
	bool connect(QString strIp, int nPort = 102,int nRack = 0, int nSlot = 1);               // 连接
	bool readInt16(uint16_t uAddr, int16_t &nValue,int nDb = 1);                             // 读取单个16位寄存器
	bool readMultInt16(uint16_t uStartAddr, int nCount,int16_t *buffer, int nDb = 1);        // 读取多个16位寄存器
	bool readInt32(uint16_t uAddr, int32_t &nValue, int nDb = 1);                            // 读取单个32位寄存器
	bool readMultiInt32(uint16_t uStartAddr, int nCount, int32_t *buffer, int nDb = 1);      // 读取多个32位寄存器
	bool readFloat(uint16_t uAddr, float &fValue, int nDb = 1);                              // 读取浮点数
	bool readMultiFloat(uint16_t uStartAddr, int nCount, float *buffer, int nDb = 1);        // 读取多个浮点数寄存器
	bool readM(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb = 1);         // 读取M寄存器
	bool readInput_X(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb = 1);   // 读取输入点
	bool readOutput_Y(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb = 1);  // 读取输出点

	bool writeInt16(uint16_t uAddr, int16_t nValue, int nDb = 1);                               // 写入单个16位寄存器
	bool writeMultiInt16(uint16_t uStartAddr, int nCount, int16_t *buffer, int nDb = 1);        // 写入多个16位寄存器
	bool writeInt32(uint16_t uAddr, int32_t nValue, int nDb = 1);                               // 写入单个32位寄存器
	bool writeMultiInt32(uint16_t uStartAddr, int nCount, int32_t *buffer, int nDb = 1);        // 写入多个32位寄存器
	bool writeFloat(uint16_t uAddr, float fValue, int nDb = 1);                              // 写入单浮点数
	bool writeMultiFloat(uint16_t uStartAddr, int nCount, float *buffer, int nDb = 1);       // 写入多个浮点数 
	bool writeM(uint16_t uStartByte, uint16_t uBitOffset, bool bState, int nDb = 1);         // 写入M寄存器
	bool writeOutput_Y(uint16_t uStartByte, uint16_t uBitOffset, bool bState, int nDb = 1);  // 设置输出

	bool isConnected();                                                                      // 是否连接
	void release();                                                                          // 软件关闭调用

private:
	void convertInt16ToBigEndian(int16_t value, byte* buffer);
	void convertInt32ToBigEndian(int32_t value, byte* buffer);
	int32_t bigEndianToLittleEndian(int32_t bigEndianValue);
	int16_t bigEndianToLittleEndian(int16_t bigEndianValue);

protected:
	void run() override;


private:
	sSnapData *m_ptr;
	QString m_strIp = "192.168.200.1";				// IP地址
	int m_nPort = 1000;								// 端口号
	int m_nConnectionType = 2;						// 连接类型
	int m_nDbNumber = 1;							// 数据块号
	int m_nRackNumber = 0;                          // 机架号
	int m_nSlotNumber = 1;                          // 卡槽号

};


2.源文件

#include "Snap7ConObject.h"
#include "snap7.h"
#include <QDebug>
#include <QTime>
#include <QDataStream>

   
struct sSnapData
{
	int nErrorCount = 0;
	bool bExit = false;
	bool bConneted = false;
	TS7Client *pClient = nullptr;
	QMutex funMutex;                                   // 为了保证通讯的稳定性,函数接口锁为必须
};

// 不阻塞定时器
struct sSnap7Timer
{
	QTime time;
	uint32_t interval;

	void start(uint32_t t)
	{
		interval = t;
		time.restart();
	};

	bool isTimeOut()
	{
		return time.elapsed() > interval;
	};
};

cSnapConObject::cSnapConObject(QObject *parent)
	: QThread(parent)
	, m_ptr(new sSnapData())
{
	m_ptr->pClient = new TS7Client();
	
	this->start();
}

cSnapConObject::~cSnapConObject()
{
}

/**
* @brief	    获取示例对象
* @param[IN]	
* @param[OUT]
* @return       对象指针
*
* @note
*/
cSnapConObject *cSnapConObject::getInstance()
{
	static cSnapConObject instance;
	return &instance;
}

void cSnapConObject::run()
{
	static int nStep = 0;
	static sSnap7Timer timeout;
	while (true)
	{
		QThread::msleep(100);
		if (m_ptr->bExit)
			return;

		switch (nStep)
		{
		case 0:
		{
			// 掉线重新连接
			if (m_ptr->nErrorCount > 50)
			{
				nStep = 1;
			}
		}break;

		case 1:
		{
			if (!m_ptr->pClient->Connected())
			{
				int nRet = m_ptr->pClient->ConnectTo(m_strIp.toStdString().c_str(), m_nRackNumber, m_nSlotNumber);
				if (nRet == 0)
				{
					m_ptr->nErrorCount = 0;
					m_ptr->bConneted = true;
				}
				else
					m_ptr->bConneted = false;
			}
			else
			{
				m_ptr->nErrorCount = 0;
			}

			timeout.start(5 * 1000);
			nStep = 2;
		}break;

		case 2:
		{
			if (timeout.isTimeOut())
			{
				nStep = 0;
			}
		}break;

		default:
			break;
		}
	}
}

// 连接
bool cSnapConObject::connect(QString strIp, int nPort, int nRack, int nSlot)
{
	m_strIp = strIp;
	m_nPort = nPort;
	m_nRackNumber = nRack;
	m_nSlotNumber = nSlot;
	int nRet = m_ptr->pClient->ConnectTo(strIp.toStdString().c_str(), nRack, nSlot);
	if (nRet == 0)
		m_ptr->bConneted = true;
	else
		m_ptr->bConneted = false;

	return m_ptr->bConneted;
}

// 读取VW寄存器值(16)位
bool cSnapConObject::readInt16(uint16_t uAddr, int16_t &nValue,int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	int16_t buffer[1] = { 0 };
	bool bRet = readMultInt16(uAddr, 1, buffer, nDb);
	nValue = buffer[0];

	return bRet;
}

// 批量读取16位
bool cSnapConObject::readMultInt16(uint16_t uStartAddr, int nCount, int16_t *buffer, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	// 创建用于读取的数据缓冲区
	QByteArray data(nCount * sizeof(int16_t), 0);
	int nRet = m_ptr->pClient->ReadArea(S7AreaDB, nDb, uStartAddr, nCount * sizeof(int16_t), S7WLByte, data.data());

	if (nRet == 0)
	{
		// 如果没有错误
		QDataStream dataStream(data);
		dataStream.setByteOrder(QDataStream::BigEndian); // 设置字节序为大端

		// 逐个读取 qint16 数据并转换
		for (int i = 0; i < nCount; ++i)
		{
			int16_t value;
			dataStream >> value; // 读取 qint16 值
			//buffer[i] = bigEndianToLittleEndian(value);
			buffer[i] = (value);
		}

		return true;
	}
	else
		m_ptr->nErrorCount++;

	return false;
}

// 读取VD寄存器值(32)位
bool cSnapConObject::readInt32(uint16_t uAddr, int32_t &nValue, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	int32_t buffer[1] = { 0 };
	bool bRet = readMultiInt32(uAddr, 1, buffer, nDb);
	nValue = buffer[0];

	return bRet;
}

// 批量读取32位
bool cSnapConObject::readMultiInt32(uint16_t uStartAddr, int nCount, int32_t *buffer, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	// 创建用于读取的数据缓冲区
	QByteArray data(nCount * sizeof(int32_t), 0);
	int nRet = m_ptr->pClient->ReadArea(S7AreaDB, nDb, uStartAddr, nCount * sizeof(int32_t), S7WLByte, data.data());

	if (nRet == 0)
	{
		// 如果没有错误
		QDataStream dataStream(data);
		dataStream.setByteOrder(QDataStream::BigEndian); // 设置字节序为大端

		// 逐个读取 int32_t 数据并转换
		for (int i = 0; i < nCount; ++i)
		{
			int32_t value;
			dataStream >> value; // 读取 int32_t 值
			//buffer[i] = bigEndianToLittleEndian(value);
			buffer[i] = (value);
		}

		return true;
	}

	return false;
}

// 读取浮点
bool cSnapConObject::readFloat(uint16_t uAddr, float &fValue, int nDb)
{
	float fArray[1] = {0.0};
	bool bRet = readMultiFloat(uAddr,1,fArray);
	fValue = fArray[0];
	return bRet;
}

// 读取多个浮点数寄存器
bool cSnapConObject::readMultiFloat(uint16_t uStartAddr, int nCount, float *buffer, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	// 创建用于读取的数据缓冲区
	int nSize = sizeof(float);
	QByteArray data(nCount * sizeof(float), 0);
	int nRet = m_ptr->pClient->ReadArea(S7AreaDB, nDb, uStartAddr, nCount * sizeof(float), S7WLByte, data.data());

	if (nRet == 0)
	{

		// 如果没有错误
		QDataStream dataStream(data);
		//dataStream.setByteOrder(QDataStream::BigEndian); // 设置字节序为大端
		dataStream.setFloatingPointPrecision(QDataStream::SinglePrecision);

		// 逐个读取 float 数据并转换
		for (int i = 0; i < nCount; ++i)
		{
			float value;
			dataStream >> value; // 读取 float 值

			buffer[i] = (value);
		}

		return true;
	}

	return false;
}

// 读取M x.x
bool cSnapConObject::readM(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	uint8_t boolValue = 0;  // 存储读取到的布尔值
	int nRet = m_ptr->pClient->ReadArea(S7AreaMK, nDb, uStartByte, 1, S7WLBit, &boolValue);
	if (nRet == 0)
	{
		bState = (boolValue & (1 << uBitOffset)) != 0;
		return true;
	}
	else
		m_ptr->nErrorCount++;

	return false;
}

// 读取输入点
bool cSnapConObject::readInput_X(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	uint8_t boolValue = 0; 
	int nRet = m_ptr->pClient->ReadArea(S7AreaPE, nDb, uStartByte, 1, S7WLBit, &boolValue);
	if (nRet == 0)
	{
		bState = (boolValue & (1 << uBitOffset)) != 0;
		return true;
	}
	else
		m_ptr->nErrorCount++;

	return false;
}

// 读取输出点
bool cSnapConObject::readOutput_Y(uint16_t uStartByte, uint16_t uBitOffset, bool &bState, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	uint8_t boolValue = 0;
	int nRet = m_ptr->pClient->ReadArea(S7AreaPA, nDb, uStartByte, 1, S7WLBit, &boolValue);
	if (nRet == 0)
	{
		bState = (boolValue & (1 << uBitOffset)) != 0;
		return true;
	}
	else
		m_ptr->nErrorCount++;

	return false;
}

// 写入16位整数
bool cSnapConObject::writeInt16(uint16_t uAddr, int16_t nValue, int nDb)
{
	int16_t buffer[1] = { nValue };

	return writeMultiInt16(uAddr, 1, buffer, nDb);
}

// 批量写入
bool  cSnapConObject::writeMultiInt16(uint16_t uStartAddr, int nCount, int16_t *buffer, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	std::vector<byte> bufferTemp(nCount * sizeof(int16_t)); 

	// 将 INT16 数据转换为大端格式并填入缓冲区
	for (size_t i = 0; i < nCount; ++i) 
	{
		convertInt16ToBigEndian(buffer[i], &bufferTemp[i * sizeof(int16_t)]);
	}

	int nRet = m_ptr->pClient->WriteArea(S7AreaDB, nDb, uStartAddr,nCount*sizeof(int16_t), S7WLByte, bufferTemp.data());
	if (nRet == 0)
		return true;
	else
		m_ptr->nErrorCount++;

	return false;
}

// 写入32位整数
bool cSnapConObject::writeInt32(uint16_t uAddr, int32_t nValue, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	int32_t buffer[1] = { nValue };

	return writeMultiInt32(uAddr,1,buffer,nDb);
}

// 批量写入
bool cSnapConObject::writeMultiInt32(uint16_t uStartAddr, int nCount, int32_t *buffer, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	std::vector<byte> bufferTemp(nCount * sizeof(int32_t));

	// 将 INT32 数据转换为大端格式并填入缓冲区
	for (size_t i = 0; i < nCount; ++i)
	{
		convertInt32ToBigEndian(buffer[i], &bufferTemp[i * sizeof(int32_t)]);
	}

	int nRet = m_ptr->pClient->WriteArea(S7AreaDB, nDb, uStartAddr,nCount*sizeof(int32_t), S7WLByte, bufferTemp.data());
	if (nRet == 0)
		return true;
	else
		m_ptr->nErrorCount++;

	return false;
}

// 写入浮点数
bool cSnapConObject::writeFloat(uint16_t uAddr, float fValue, int nDb)
{
	float buffer[1] = { fValue };

	return writeMultiFloat(uAddr,1,buffer,nDb);
}

// 批量写入浮点数
bool cSnapConObject::writeMultiFloat(uint16_t uStartAddr, int nCount, float *buffer, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	// 准备要写入的数据的字节数组
	QByteArray byteArray;

	for (size_t i = 0; i < nCount; ++i)
	{
		float value = buffer[i];
		QByteArray tempData(reinterpret_cast<const char*>(&value), sizeof(float));

		// 大端转换:将字节顺序反转
		for (int j = sizeof(float) - 1; j >= 0; --j) 
		{
			byteArray.append(tempData[j]);
		}
	}

	int nRet = m_ptr->pClient->WriteArea(S7AreaDB, nDb, uStartAddr, byteArray.size(), S7WLByte, byteArray.data());
	if (nRet == 0)
		return true;
	else
		m_ptr->nErrorCount++;

	return false;
}

// 写入M x.x
bool cSnapConObject::writeM(uint16_t uStartByte, uint16_t uBitOffset, bool bState, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	// 准备写入的数据
	uint8_t dataToWrite = 0;
	if (bState) 
		dataToWrite = (1 << uBitOffset);  // 构造要写入的数据

	// 读取当前的值
	uint8_t currentData = 0;
	int nRet = m_ptr->pClient->ReadArea(S7AreaMK, nDb, uStartByte, 1, S7WLBit, &currentData);
	if (nRet != 0)
	{
		m_ptr->nErrorCount++;
		return false;
	}

	// 更新数据
	if (bState)
		currentData |= dataToWrite;		// eg.设置 M2.2 对应的位
	else 
		currentData &= ~dataToWrite;  //  eg.清除 M2.2 对应的位

	// 写入
	int nRet1 = m_ptr->pClient->ReadArea(S7AreaMK, nDb, uStartByte, 1, S7WLBit, &currentData);
	if (nRet1 == 0)
		return true;
	else
		m_ptr->nErrorCount++;


	return false;
}

// 设置输入点
bool cSnapConObject::writeOutput_Y(uint16_t uStartByte, uint16_t uBitOffset, bool bState, int nDb)
{
	if (!m_ptr->bConneted)
		return false;

	// 准备写入的数据
	uint8_t dataToWrite = 0;
	if (bState)
		dataToWrite = (1 << uBitOffset);  // 构造要写入的数据

	// 读取当前的值
	uint8_t currentData = 0;
	int nRet = m_ptr->pClient->ReadArea(S7AreaPA, nDb, uStartByte, 1, S7WLBit, &currentData);
	if (nRet != 0)
		return false;

	// 更新数据
	if (bState)
		currentData |= dataToWrite;		
	else
		currentData &= ~dataToWrite;  

	// 写入
	int nRet1 = m_ptr->pClient->ReadArea(S7AreaPA, nDb, uStartByte, 1, S7WLBit, &currentData);
	if (nRet1 == 0)
		return true;
	else
		m_ptr->nErrorCount++;


	return false;
}

// 16位转大端模式
void cSnapConObject::convertInt16ToBigEndian(int16_t value, byte* buffer)
{
	buffer[0] = (value >> 8) & 0xFF; // 高字节
	buffer[1] = value & 0xFF;        // 低字节
}

// 32位转大端模式
void cSnapConObject::convertInt32ToBigEndian(int32_t value, byte* buffer)
{
	buffer[0] = (value >> 24) & 0xFF; // 第一个字节
	buffer[1] = (value >> 16) & 0xFF; // 第二个字节
	buffer[2] = (value >> 8) & 0xFF;  // 第三个字节
	buffer[3] = value & 0xFF;         // 第四个字节
}

// 32位大端转小端
int32_t cSnapConObject::bigEndianToLittleEndian(int32_t bigEndianValue)
{
	// 将大端字节转换为小端字节
	return ((bigEndianValue << 24) & 0xFF000000) |  // 高字节移到低字节
		((bigEndianValue << 8) & 0x00FF0000) |  // 次高字节移到次低字节
		((bigEndianValue >> 8) & 0x0000FF00) |  // 次低字节移到次高字节
		((bigEndianValue >> 24) & 0x000000FF);    // 低字节移到高字节
}

// 16位大端转小端
int16_t cSnapConObject::bigEndianToLittleEndian(int16_t bigEndianValue)
{
	// 将大端字节转换为小端字节
	return (bigEndianValue << 8) | ((bigEndianValue >> 8) & 0xFF);
}

/**
* @brief        是否连接成功
* @param[IN]
* @param[OUT]
* @return       true - 成功
*               false - 失败
* @note
*/
bool cSnapConObject::isConnected()
{
	return m_ptr->bConneted;
}

/**
* @brief         资源释放,确保线程退出,软件关闭的时候调用
* @param[IN]
* @param[OUT]
* @return
*
* @note
*/
void cSnapConObject::release()
{
	m_ptr->bExit = true;
	if (m_ptr->pClient->Connected())
	{
		m_ptr->pClient->Disconnect();
	}
}



二、下载连接

https://download.csdn.net/download/u013083044/89939160

;