关于PC端与PLC端以太网通信
一、TCPIP通信
以太网通信基本上最先想到的是TCPIP
就是在PC端的VS上布置服务器端,我用的是VS2015,最长用的是WinSock2.h
大致的步骤就是:
a.初始化版本号
b.建立套接字
c.定义并绑定地址
d.进入监听状态
e.接收连接请求
f.交换数据
有一点值得注意的是,Inter的CPU和西门子的CPU的储存方式不同,大端和小端储存方式。就是你VS定义的一个int型数据,在传输的时候char[0]是高位,而西门子的储存方式是char[3]是高位。这个也是做了大量的实验发现的问题,后来在西门子提供的prodave库中的函数也得到了证明。
send_text[0] = temp_send[3];
send_text[1] = temp_send[2];
send_text[2] = temp_send[1];
send_text[3] = temp_send[0];
转换以后再发送,数就能对的上了,但是还有问题。
做实验的时候发现,可能PLC通信的时候还需要时序的信息,还有一些不为人知的数据结构,这就导致PC发送的时候,PLC收到的是不含时序或者混乱的信息。比如我发送三个数,一个浮点一个整型,一个bool型给PLC,PLC的DB块负责接收,发现第1次接收是正确的,第2次就错了,第3次错,第4次错,第5次错,第6次正确。。。就是这样的情况。
PLC PC
123 64
20 -34
-34 20
64 123
-20 65
81 4
4 81
65 -20
0 0
0 0
-34 0
64 0-89 64
-116 -34
123 20
20 123
82 65
-114 4
-20 81
21 -20
-89 0
-116 0
123 0
20 0-20 64
81 -34
4 20
65 123
123 65
20 4
-34 81
64 -20
0 0
0 0
4 0
65 082 64
-114 -34
-20 20
21 123
-89 65
-116 4
123 81
20 -20
82 0
-114 0
-20 0
21 082 64
-114 -34
-20 20
21 123
-89 65
-116 4
123 81
20 -20
82 0
-114 0
-20 0
21 0123 64
20 -34
-34 20
64 123
-20 65
81 4
4 81
65 -20
0 0
0 0
-34 0
64 0
就像这样的。还有一个问题就是,当第一个数只要是浮点就会发生这样的情况,但是换成第一个是整型,第二个数是浮点,问题就不会发生了。所以这样的通信是不能让人接受的。
二、OPC方式
OPC方式需要直接在PLC组态的时候就要和Windows的OPC进行OPC组态,连接成功就能通信。
需要通过vs读取windows opc中的数据,查资料知道MatrikonOPC可以简单的和VS搭配
这个需要提前安装MatrikonOPCSimulation工具,默认路径安装就行。这是代码:
#import "C://Windows//SysWOW64//OPCAuto.dll"
#pragma warning( disable : 4786 )
#include <comdef.h>
#include <vector>
#include <iostream>using namespace std;using namespace OPCAutomation;//声明全局变量
typedef struct OLEInit {OLEInit() { CoInitialize(NULL); }~OLEInit() { CoUninitialize(); }
} OLEInit;OLEInit oleInit;
OPCAutomation::IOPCAutoServerPtr opcSvr;
OPCAutomation::IOPCGroupsPtr opcGrps;
OPCAutomation::IOPCGroupPtr opcGrp;
vector<OPCAutomation::OPCItemPtr> opcItems;//连接到OPC Server
void agOPConn(const char * opcSvrName)
{HRESULT hr;hr = opcSvr.CreateInstance(_uuidof(OPCServer));if (FAILED(hr)){cerr << "OPCSever CreateInstance failed, hr = " << hr << endl;exit(1);}opcSvr->Connect(opcSvrName);
}//断开连接void agOPCDisc()
{opcGrps->RemoveAll();opcSvr->Disconnect();
}//创建一个组void agOPCCreateGroup()
{opcGrps = opcSvr->OPCGroups;opcGrp = opcGrps->Add(_variant_t("group1"));
}void agOPCAddItems()
{OPCItemPtr opcItm;opcItm = opcGrp->OPCItems->AddItem(_bstr_t("Bucket Bridge.Int4"),1);opcItems.push_back(opcItm);opcItm = opcGrp->OPCItems->AddItem(_bstr_t("Bucket Bridge.Int2"), 1);opcItems.push_back(opcItm);opcItm = opcGrp->OPCItems->AddItem(_bstr_t("Bucket Bridge.String"), 1);opcItems.push_back(opcItm);}//显示读取的值void agDumpVariant(VARIANT *v)
{switch (v->vt){case VT_I2:printf("value(VT_I2) = %d ", v->iVal);break;case VT_I4:printf("value(VT_I4) = %ld", v->lVal);break;case VT_BSTR:printf(" value(VT_BSTR) = %ls ", v->bstrVal);break;default:printf(" value(unknown type:%d) ", v->vt);break;}
}//同步读取三个Item的值,同步在很多情况下都是简单有效的选择方案,其实读取的异步方式在C++中可以建立一个工作线程来执行同步读的操作,等有新的Item值的时候再通过某种线程间通信的方式告诉主线程“数据改变”的事件
void agOPCReadItems() {_variant_t quality;_variant_t timestamp;SAFEARRAY *pServerHandles;SAFEARRAY *pValues;SAFEARRAY *pErrors;SAFEARRAYBOUND rgsabound[1];long dim[1];long svrHdl;vector<_variant_t> values;vector<long> errs;int i;_variant_t value;long err;// VC数组索引从0开始,而在OPCAuto.dll需要中从1开始,所以是rgsabound[ 0 ].cElements = 4,而给pServerHandles赋值的时候应该给索引是1,2,3相应的赋值Server Handlergsabound[0].cElements = 4;rgsabound[0].lLbound = 0;pServerHandles = SafeArrayCreate(VT_I4, 1, rgsabound); //构建一个1维数组,类型是VT_I4for (i = 0; i < opcItems.size(); i++) {svrHdl = opcItems[i]->ServerHandle;dim[0] = i + 1;// 给数组的每个元素赋值,对应的索引值是1, 2, 3SafeArrayPutElement(pServerHandles, dim, &svrHdl);}opcGrp->SyncRead(OPCDevice,3, // 读取的Item数目&pServerHandles, // 输入的服务器端句柄数组&pValues, // 输出的Item值数组&pErrors, // 输出的Item错误状态数组&quality, // 读取的值的状态×tamp); // 读取的事件戳for (i = 1; i <= opcItems.size(); i++) {dim[0] = i;SafeArrayGetElement(pValues, dim, &value); // 读取Item值在value中SafeArrayGetElement(pErrors, dim, &err); // 读取错误状态值在err中 values.push_back(value);errs.push_back(err);}for (i = 0; i < values.size(); i++) {agDumpVariant(&values[i]); // 显示读取的Item值cout << ", err = " << errs[i] << endl;}SafeArrayDestroy(pServerHandles);SafeArrayDestroy(pValues);SafeArrayDestroy(pErrors);
}// 写入3个Item的值,为了演示实例简单,参数传递3个对应的Item值
void agOPCWriteItems(vector<_variant_t> values) {_variant_t quality;_variant_t timestamp;SAFEARRAY *pServerHandles;SAFEARRAY *pValues;SAFEARRAY *pErrors;long dim[1];long svrHdl;int i;SAFEARRAYBOUND rgsabound[1];rgsabound[0].cElements = values.size() + 1;rgsabound[0].lLbound = 0;pServerHandles = SafeArrayCreate(VT_I4, 1, rgsabound);pValues = SafeArrayCreate(VT_VARIANT, 1, rgsabound);for (i = 0; i < values.size(); i++) {svrHdl = opcItems[i]->ServerHandle;dim[0] = i + 1;SafeArrayPutElement(pServerHandles, dim, &svrHdl);SafeArrayPutElement(pValues, dim, &values[i]);}opcGrp->SyncWrite(3, &pServerHandles, &pValues, &pErrors);SafeArrayDestroy(pServerHandles);SafeArrayDestroy(pValues);SafeArrayDestroy(pErrors);
}//main主程序
int main()
{try{agOPConn("Matrikon.OPC.Simulation.1");agOPCCreateGroup();agOPCAddItems();// 第一次写和读vector<_variant_t> values;values.push_back((long)156);values.push_back((short)11);values.push_back("opc");agOPCWriteItems(values);agOPCReadItems();cout << "---------------------------------------" << endl;// 第二次写和读vector<_variant_t> values1;values1.push_back((long)123456);values1.push_back((short)666);values1.push_back("hello");agOPCWriteItems(values1);agOPCReadItems();}catch (_com_error &e) {// 应该在上面的子函数里面捕捉异常,但为了演示简单,在主函数里面捕捉异常_bstr_t bstrSource(e.Source());_bstr_t bstrDescription(e.Description());cout << "Code = " << e.Error() << endl;cout << "Code meaning = " << e.ErrorMessage() << endl;cout << "Source = " << (LPCTSTR)bstrSource << endl;cout << "Description = " << (LPCTSTR)bstrDescription << endl;}system("pause");getchar();return 0;
}
因为网上的代码import的时候加了no_namespace 但是得到的.tlh找不到OPCAuto.dll的底层函数接口,所以我就加上了,namespace问题解决。这样的通信方法,一组数大约需要100ms,可能不是因为数据量的问题,可能就是这样的速度。
三、prodave
prodave是西门子提供的库,用来和vs进行通信。现在我能找到最新的是6.2版本,需要安装prodave安装包,并注册激活。
安装完成目录下会生成VB、VC的demo,但是VC的demo需要改一些东西才能在C++中编译成功。
Prodave6.2 密码:yak3
授权 密码:qr7b
我改的demo 密码:c8ce
关于PC端与PLC端以太网通信相关推荐
- SIMATIC WINCC与PLC进行以太网通信的具体组态方法和步骤
SIMATIC WINCC与PLC进行以太网通信的具体组态方法和步骤 采用普通网卡通过TCP/IP与PLC通讯,通过以太网实现WICC与PLC系统连接的前提条件是PLC系统配置有以太网模块或者使用带P ...
- 博途PLC开放式以太网通信TRCV_C指令应用编程(运动传感器UDP通信)
博途PLC开放式以太网通信TSENG_C指令应用,请参看下面的文章链接: 博途PLC 1200/1500PLC开放式以太网通信TSEND_C通信(UDP)_plc的udp通信_RXXW_Dor的博客- ...
- 查看PLC IP 端口_详解S7-1500的以太网通信数据类型:TCON_IP_v4
西门子S7系列PLC的开放式以太网通信过程包括如下几个步骤:建立连接(Establish connection).发送/接收数据(Send/receive data).断开连接(Disconnect) ...
- 三菱FX系列PLC转以太网连接CHNet-FX实现以太网通信配置方法
产品简介 兴达易控CHNet-FX是兴达易控研制的一款经济型的以太网通讯处理器,是为满足日益增多的工厂设备信息化需求(设备网络监控和生产管理)而设计,用于三菱FX1S/1N/2N/3S/3G/3GA/ ...
- 使用PC Access实现WinCC v7.4和S7-200 PLC之间的通信
-- 参考自: PC Access快速入门 <现代电气控制及PLC应用技术> 王永华 北京航空航天大学 0 WinCC和S7-200 PLC之间的通信 WinCC没有集成S7-200系列的 ...
- 欧姆龙CP系列PLC转以太网连接CHNet-CP实现以太网通信配置方法
产品简介 CHNet-CP是兴达易控研制的一款经济型的以太网通讯处理器,是为满足日益增多的工厂设备信息化需求(设备网络监控和生产管理)而设计,用于欧姆龙CP1L/CP1E/CP1H系列PLC的以太网数 ...
- 如何在 PC 机上测试移动端的网页?
如何在 PC 机上测试移动端的网页?如果用 HTML5 写的页面,想兼容 iOS.Android 平台的手机,在 PC 机上看有些效果可能不准确,但不可能在每个移动终端都放上去看下效果吧,一般用什么工 ...
- 超详细的用户认证、权限、安全原理详解(认证、权限、JWT、RFC 7235、HTTPS、HSTS、PC端、服务端、移动端、第三方认证等等)
用户认证.权限.安全 原 理 与 实 践 作者: jcLee95 邮箱 :291148484@163.com CSDN 主页:https://blog.csdn.net/qq_28550263?spm ...
- javascript 判断 前端 是 pc端 还是 移动端
javascript 判断 前端 是 pc端 还是 移动端 <!DOCTYPE html> <html lang="en"> <head>< ...
最新文章
- static 静态成员变量和静态函数 C++
- Spring 整合 CXF
- class h5 点击后样式变化_H5学习笔记
- 蓝桥杯--算法训练 表达式计算
- JSON表单提交(ajax异步刷新)
- jzoj1402-偷懒的小X【贪心】
- C#求数组中元素的全排列
- http状态码_一些常见的HTTP状态码
- WEB前端开发规范文档+CSS命名规范
- C++ 面向对象编程
- 昨天,JetBrains 推出“下一代 IDE”,对标VS Code?快看看有哪些值得期待的功能!...
- 走近源码:Redis的启动过程
- 关于idea,双击选中问题
- 2022年Java面试宝典【4万字带答案】
- 北理工慕课 嵩天 Python零基础入门 笔记整理
- C++ typedef 用法详解
- ROS服务通信《客户端》 C++向服务端发送信息(乌龟案例,生成第二个乌龟)
- Failed to start LSB: Enable AMQP service provided by RabbitMQ broker.
- arbexpress使用教程_信号发生器使用说明
- 记一次JAVA中字符串首字母大写转化为小写的Code
热门文章
- Speedoffice(Excel)如何计算指定日期后续N天的日期
- android 紧急呼叫号码,android学习之——紧急呼叫
- Java 基础夯实2:全面了解异常
- 提取OutLook邮件里面的邮件头信息(发件人、收件人)
- 基于C++实现(MFC界面)家谱管理系统【100010005】
- Vue3电商项目实战-结算支付 3【05-结算-收货地址-添加、06-结算-收货地址-修改、07-结算-提交订单】
- 渗透测试工具-burpsuite
- PHP中json_encode与json_decode用法
- 微博短链接的生成算法(Java版本)
- ESP8266连接阿里云(STM32)