QT-C++ 西门子snap7通讯库接口
QT-C++ 西门子snap7通讯库接口
- 一、核心程序
- 1.头文件
- 2.源文件
- 二、下载连接
一、核心程序
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, ¤tData);
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, ¤tData);
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, ¤tData);
if (nRet != 0)
return false;
// 更新数据
if (bState)
currentData |= dataToWrite;
else
currentData &= ~dataToWrite;
// 写入
int nRet1 = m_ptr->pClient->ReadArea(S7AreaPA, nDb, uStartByte, 1, S7WLBit, ¤tData);
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