每家PLC厂商都有自己的通讯协议,三菱有MC、倍福有ADS,然而没有统一性的接口协议。
为适应每一家通讯,每一家设备商、MES和工厂等都需要针对每款产品开发相应的通讯接口。
OneConnectAPI为实现统一的接口,去适配每一家厂商的协议。为中国工控行业快速发展而贡献,每一家公司都需要重新制造轮子,这是非常浪费时间和金钱,同时也不能保证稳定性以及持续的维护。
我们采取高效的多线程处理方案,保证极其高效的读写性能,对电脑性能要求极其低,一直进行读写操作,CPU使用率不超过1%(Atom E3940下测试)。
用户可以在一台工控机上进行对上百台的PLC主动读写操作,我们在光伏行业大量应用和测试过。
我们在半导体行业深耕多年,积累大量的经验,实现功能的同时,也需要保证极其严格的稳定性,晶圆生成设备7*24小时不能出任何故障。
以下是我们的接口库下载以及源代码。
下载地址 软件及资料书 www.secsgem.cn 欧姆龙Fins通讯源代码,简洁易懂、模块高效稳定-电信文档类资源-CSDN文库https://download.csdn.net/download/jacp_haik/55020678
沟通qun:30806722
demo界面
接口示例
#pragma once #include <string> #include "InterfaceExport.h" #include "ModuleDevelopH.h" // 欧姆龙Fins协议 class CFins { public: CFins(); virtual ~CFins(); // 参数 CResult SetIP(std::string pIP); // 设置地址 CResult SetPort(int nPort); // 设置端口号 CResult SetTimeout(int nTimeMs); // 设置超时 // 读出 CResult Read(std::string pAddr, char& pData); CResult Read(std::string pAddr, __int16& pData); CResult Read(std::string pAddr, __int32& pData); CResult Read(std::string pAddr, __int64& pData); CResult Read(std::string pAddr, char* pData, int nSize); CResult Read(std::string pAddr, __int16* pData, int nSize); CResult Read(std::string pAddr, __int32* pData, int nSize); CResult Read(std::string pAddr, __int64* pData, int nSize); // 写入 CResult Write(std::string pAddr, char& pData); CResult Write(std::string pAddr, __int16& pData); CResult Write(std::string pAddr, __int32& pData); CResult Write(std::string pAddr, __int64& pData); CResult Write(std::string pAddr, char* pData, __int32 nSize); CResult Write(std::string pAddr, __int16* pData, __int32 nSize); CResult Write(std::string pAddr, __int32* pData, __int32 nSize); CResult Write(std::string pAddr, __int64* pData, __int32 nSize); private: CResult SetParament(std::string pName, std::string pValue); CResult SetParament(std::string pName, int nValue); private: CInterfaceExport* m_pFins; CMgrDllDelegate m_pLoadInterface; };
使用方法
CFins m_pFins; // 欧姆龙通讯对象 // 设置参数 m_pFins.SetIP("192.168.1.50"); m_pFins.SetPort(9600); m_pFins.SetTimeout(3000); // 读取一个数据 __int32 nData; CResult rc = m_pFins.Read("DM102", nData); if (rc.nCode != 0) { // 出错处理 } // 读取多个数据 __int16 nDataMulit[100]; CResult rc = m_pFins.Read("DM102", nDataMulit, 100); if (rc.nCode != 0) { // 出错处理 }
Fins内部通讯协议
#pragma once #include "Communication.h" class CFinsHandle : public CCommunication { public: CFinsHandle(); long ReadMemoryData(int nAddr, int nSize, FINS_DATA_TYPE::ENUM nType, __int16* pData); long WriteMemoryData(int nAddr, int nSize, FINS_DATA_TYPE::ENUM nType, __int16* pData); private: virtual void OnBeginRecv(); // 重写数据接收,开始接收数据 virtual void OnDataRecv(char* pData, int nSize); // 重写数据接收,用于协议识别 virtual void OnCloseConnect(); // 通讯关闭 // 检查答复数据是否错误 long CheckReplyDataIsError(char* pData, int nSize); // 检查答复数据是否错误 long GetFinsNodeAddress(); // 获取fins节点地址 long EstablishCommunicationByFins(); // 建立Fins通讯 private: CMyString m_pRecvData; bool m_bEstablishCommunicationByFins; // 与Fins建立通讯 int m_nIpNode; // IP节点 };
通讯实现代码
#include "stdafx.h" #include "FinsHandle.h" CFinsHandle::CFinsHandle() { m_bEstablishCommunicationByFins = false; m_nIpNode = 0; } // 重写数据接收,用于协议识别 void CFinsHandle::OnDataRecv(char* pData, int nSize) { if (nSize > 0) { m_pRecvData.Append(pData, nSize); if (m_pRecvData.Size() >= FINS_TCP_HEAD_SIZE) { FINS_TCP_HEAD pHead; pHead.SetData(m_pRecvData.GetString()); int nAllSize = pHead.GetLength(); if (m_pRecvData.Size() >= nAllSize) { SetRecvComplete(nAllSize); } } } } // 重写数据接收,开始接收数据,用于协议识别 void CFinsHandle::OnBeginRecv() { m_pRecvData.SetSize(0); } // 通讯关闭 void CFinsHandle::OnCloseConnect() { m_bEstablishCommunicationByFins = false; } long CFinsHandle::ReadMemoryData(int nAddr, int nSize, FINS_DATA_TYPE::ENUM nType, __int16* pData) { long nCode = 0; if(nCode = EstablishCommunicationByFins()) { return nCode; } CMyString pSendData; // 获取发送内存 int nAllSize; nAllSize = FINS_TCP_HEAD_SIZE; nAllSize += FINS_CONTROL_HEAD_SIZE; nAllSize += FINS_MEMORY_AREA_READ_SIZE; pSendData.SetSize(nAllSize); char* pBuff = pSendData.GetString(); // 头部信息 FINS_TCP_HEAD pHead; pHead.nCommand = FINS_TCP_CMD_DATA; pHead.SetLength(nAllSize); //长度 pHead.GetData(pBuff); // control部分 FINS_CONTROL_HEAD pControlHead; pControlHead.nDA1 = 0; pControlHead.nSA1 = m_nIpNode; pControlHead.nCmd1 = 0x01; pControlHead.nCmd2 = 0x01; pControlHead.GetData(pBuff + FINS_TCP_HEAD_SIZE); // 数据部分 FINS_MEMORY_AREA_READ pMemory; pMemory.nAreaCode = nType; pMemory.nAddr = nAddr; pMemory.nBitNo = 0; pMemory.nLength = nSize; pMemory.GetData(pBuff + FINS_TCP_HEAD_SIZE + FINS_CONTROL_HEAD_SIZE); // // 发送数据 CMyString pRecvData; nCode = SendSyncData(pSendData, pRecvData); if (nCode == 0) { // 先判断答复数据的头数据是否正确 if(nCode = CheckReplyDataIsError(pRecvData.GetString(), pRecvData.Size())) { return nCode; } // 数据头 FINS_TCP_HEAD pHeadReply; pHeadReply.SetData(pRecvData.GetString()); // 答复长度要求 int nMinSize = FINS_TCP_HEAD_SIZE + FINS_CONTROL_HEAD_SIZE + FINS_MEMORY_AREA_READ_FIX_R_SIZE + nSize * 2; if(pHeadReply.GetLength() < nMinSize) { return FINS_REPLY_READ_DATA_TOO_SHORT; } else { // FINS协议部分 FINS_CONTROL_HEAD pControlHeadReply; pControlHeadReply.SetData(pRecvData.GetString()); if (pControlHeadReply.nCmd1 != pControlHead.nCmd1 || pControlHeadReply.nCmd2 != pControlHead.nCmd2) { // 命令不一致 return FINS_REPLY_CMD_NO_IS_REQUST_CMD; } // 答复数据 FINS_MEMORY_AREA_READ_REPLY pReplyData; pReplyData.SetData(pRecvData.GetString(), pRecvData.Size()); if(pReplyData.nEndCode != 0) { return FINS_REPLY_READ_DATA_FAIL; } // 拷贝数据 int nReadByte = nSize * 2; if (pReplyData.GetDataBytsSize() == nReadByte) { memcpy(pData, pReplyData.GetData(), nReadByte); } else { return FINS_REPLY_READ_DATA_TOO_SHORT; } } } return nCode; } long CFinsHandle::WriteMemoryData(int nAddr, int nSize, FINS_DATA_TYPE::ENUM nType, __int16* pData) { long nCode = 0; if(nCode = EstablishCommunicationByFins()) { return nCode; } CMyString pSendData; int nBytsSize = nSize * 2; // 获取发送内存 int nAllSize; nAllSize = FINS_TCP_HEAD_SIZE; nAllSize += FINS_CONTROL_HEAD_SIZE; nAllSize += FINS_MEMORY_AREA_READ_SIZE; nAllSize += nBytsSize; pSendData.SetSize(nAllSize); char* pBuff = pSendData.GetString(); // 头部信息 FINS_TCP_HEAD pHead; pHead.nCommand = FINS_TCP_CMD_DATA; pHead.SetLength(nAllSize); //长度 pHead.GetData(pBuff); // control部分 FINS_CONTROL_HEAD pControlHead; pControlHead.nDA1 = 0; pControlHead.nSA1 = m_nIpNode; pControlHead.nCmd1 = 0x01; pControlHead.nCmd2 = 0x02; pControlHead.GetData(pBuff + FINS_TCP_HEAD_SIZE); // 数据部分 FINS_MEMORY_AREA_WRITE pMemory; pMemory.nAreaCode = nType; pMemory.nAddr = nAddr; pMemory.nBitNo = 0; pMemory.nLength = nSize; pMemory.pData.Append((char*)pData, nBytsSize); pMemory.GetData(pBuff + FINS_TCP_HEAD_SIZE + FINS_CONTROL_HEAD_SIZE); // // 发送数据 CMyString pRecvData; nCode = SendSyncData(pSendData, pRecvData); if (nCode == 0) { // 先判断答复数据的头数据是否正确 if(nCode = CheckReplyDataIsError(pRecvData.GetString(), pRecvData.Size())) { return nCode; } // 数据头 FINS_TCP_HEAD pHeadReply; pHeadReply.SetData(pRecvData.GetString()); // 答复长度要求 int nMinSize = FINS_TCP_HEAD_SIZE + FINS_CONTROL_HEAD_SIZE + FINS_MEMORY_AREA_WRITE_R_SIZE; if(pHeadReply.GetLength() < nMinSize) { return FINS_REPLY_READ_DATA_TOO_SHORT; } else { // FINS协议部分 FINS_CONTROL_HEAD pControlHeadReply; pControlHeadReply.SetData(pRecvData.GetString()); if (pControlHeadReply.nCmd1 != pControlHead.nCmd1 || pControlHeadReply.nCmd2 != pControlHead.nCmd2) { // 命令不一致 return FINS_REPLY_CMD_NO_IS_REQUST_CMD; } // 答复数据 FINS_MEMORY_AREA_WRITE_REPLY pReplyData; pReplyData.SetData(pRecvData.GetString()); if(pReplyData.nEndCode != 0) { return FINS_REPLY_WRITE_DATA_FAIL; } } } return nCode; } // 获取fins节点地址 long CFinsHandle::GetFinsNodeAddress() { return 0; } // 检查答复数据是否错误 long CFinsHandle::CheckReplyDataIsError(char* pData, int nSize) { if (nSize < FINS_TCP_HEAD_SIZE) { // 小于最小要求数据 return FINS_REPLY_DATA_TOO_SHORT; } // 消息错误 FINS_TCP_HEAD pHeadReply; pHeadReply.SetData(pData); if (pHeadReply.nErrorCode) { return FINS_REPLY_ERROR_BY_MESSAGE; } return 0; } // 建立通讯 long CFinsHandle::EstablishCommunicationByFins() { if (m_bEstablishCommunicationByFins) { // 已经建立通讯连接了 return 0; } long nCode = 0; CMyString pSendData; // 获取发送内存 int nAllSize; nAllSize = FINS_TCP_HEAD_SIZE; nAllSize += FINS_CONNECT_REQUST_SIZE; pSendData.SetSize(nAllSize); char* pBuff = pSendData.GetString(); // 头部信息 FINS_TCP_HEAD pHead; pHead.nCommand = FINS_TCP_CMD_CONNECT_REQUST; pHead.SetLength(nAllSize); //长度 pHead.GetData(pBuff); // IP地址 FINS_CONNECT_REQUST pConnectRequst; pConnectRequst.GetData(pBuff + FINS_TCP_HEAD_SIZE); // 发送数据 CMyString pRecvData; if(nCode = SendSyncData(pSendData, pRecvData)) { return nCode; } // 处理返回值 FINS_TCP_HEAD pHeadReply; pHeadReply.SetData(pRecvData.GetString()); // 检查头信息 if (pHeadReply.nErrorCode == 0 && pHeadReply.nCommand == FINS_TCP_CMD_CONNECT_RESPONSE) { // 提取 IP Node信息 if (pHeadReply.GetLength() == FINS_TCP_HEAD_SIZE + FINS_CONNECT_RESPONS_SIZE) { // 提取 FINS_CONNECT_RESPONSE pConnectResponse; pConnectResponse.SetData(pRecvData.GetString()); m_nIpNode = pConnectResponse.pClientAddrss[3]; // 建立通讯成功 m_bEstablishCommunicationByFins = true; return 0; } } return FINS_REQUST_CONNECT_FAIL; }