概述
在柔性制造FMS系统中,本次项目以西门子PLC300,PLC200和倍加福RFID构建自动化输送和立体仓库物流方案。
硬件:
1、一个西门子PLC300为主站,四个PLC200为从站
2、倍加福RFID IC-KP-B17-AIDA1 IDENTControl interface with Ethernet interface的识别系统
系统:
因为西门子PLC,选用WinCC做组态画面,VBS实现MES/WMS的功能。
课题:
因为首次选用带TCP/IP的倍加福RFID,需要解决其与WinCC的通讯问题。
倍加福RFID有两种方式可以进行通讯,一、DLL,通过加载和调用所提供的DLL进行通讯;二、TCP的Socket进行通讯。
首先尝试了DLL,在WinCC中是可以调用DLL的,尝试了一个简单的DLL进行测试。
在WinCC图形编辑器中添加一个按钮,2个输入输出框。在按钮点击事件中创建以下代码:
#include "apdefap.h"
void OnLButtonDown(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName, UINT nFlags, int x, int y)
{
#pragma code ("c:/DLL/T1_C.dll") //指定绝对路径,网上有说放在WinCC/bin目录的,好像不靠谱还是这样好。
int aufruf1(int a); //声明函数
#pragma code ()
int value;
value = GetTagDouble("var1"); //Return-Type: double
SetTagDouble("result",aufruf1(value)); //Return-Type: BOOL
}
其中T1_C.dll里有一个返回参数+100的aufruf1函数。详见 http://www.cnblogs.com/ohiolee/articles/3498381.html
但是倍加福提供的RFID_TCP_DLL及示例代码是C++的,没怎么弄明白要怎么声明里面的函数,还有类的问题。代码如下:
/* in your c++ header file */
#include "RFIDTCP.h"
#pragma comment(lib, "..\impDLL\PF_RFID_LIB.lib")
/* in your c++ CPP file */
void RFID_test()
{
int ret;
RFIDTCP *pRFIDTCP;
pRFIDTCP=new RFIDTCP;
rfidMSG *pRfidMSG;
pRfidMSG= new rfidMSG;
pRFIDTCP->setupDevice("192.168.40.119",2);
int startAddr=0;
int wordNum=0;
int channel;
int ms_BlocTimeout=1000;
int retStatus;
channel=1;
pRFIDTCP->connectDevice(ms_BlocTimeout);
/* CT Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidCT(channel,pRfidMSG->pMsgBuff,"21",&retStatus);
TRACE("CT [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
startAddr=0;
wordNum=26/4+1;
Sleep(500);
/* SW Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidSW(channel,startAddr,wordNum,pRfidMSG->pMsgBuff,"zyxvwutsrqponmlkjihgfedcba",&retStatus);
TRACE("SW [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
/* SR Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidSR(channel,startAddr,wordNum,pRfidMSG->pMsgBuff,&retStatus);
TRACE("SR [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
/* QU Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidQU(channel,pRfidMSG->pMsgBuff,&retStatus);
TRACE("QU [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
/* SF Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidSF(channel,pRfidMSG->pMsgBuff,&retStatus);
TRACE("SF [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
/* EW Test */
/*wordNum MUST <= 15 () */
pRfidMSG->reset();
char wContent[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ@ABCDEFGHIJKLMNOPQRSTUVWXYZ@@ABCDEFGHIJKLMNOPQRSTUVWXYZ@";
//wordNum=(strlen(wContent)/4+1);
wordNum=15;
ret=pRFIDTCP->rfidEW(channel,startAddr,wordNum,pRfidMSG->pMsgBuff,wContent,&retStatus);
pRfidMSG->reset();
TRACE("EW [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
for(int i=0;i<5;i++)
{
pRfidMSG->reset();
ret=pRFIDTCP->enhancedMSGRec(pRfidMSG);
TRACE("EW [ret=%d][i=%d][status=%d][%s]n",ret,i,pRfidMSG->status,pRfidMSG->pString);
}
/* QU Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidQU(channel,pRfidMSG->pMsgBuff,&retStatus);
TRACE("QU [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
/* ER Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidER(channel,startAddr,wordNum,pRfidMSG->pMsgBuff,&retStatus);
TRACE("ER [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
pRfidMSG->reset();
for(int i=0;i<5;i++)
{
pRfidMSG->reset();
ret=pRFIDTCP->enhancedMSGRec(pRfidMSG);
TRACE("ER [ret=%d][i=%d][status=%d][%s]n",ret,i,pRfidMSG->status,pRfidMSG->pString);
}
/* QU Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidQU(channel,pRfidMSG->pMsgBuff,&retStatus);
TRACE("QU [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
/* EF Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidEF(channel,startAddr,wordNum,pRfidMSG->pMsgBuff,&retStatus);
TRACE("EF [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
pRfidMSG->reset();
for(int i=0;i<5;i++)
{
pRfidMSG->reset();
ret=pRFIDTCP->enhancedMSGRec(pRfidMSG);
TRACE("EF [ret=%d][i=%d][status=%d][%s]n",ret,i,pRfidMSG->status,pRfidMSG->pString);
if(ret>6)
{
TRACE("[");
for(int j=0;j<(ret-6); j++)
TRACE("0x%02x ",(unsigned char )*(pRfidMSG->pString+j));
TRACE("]n");
}
}
/* QU Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidQU(channel,pRfidMSG->pMsgBuff,&retStatus);
TRACE("QU [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
/* RS Test */
pRfidMSG->reset();
ret=pRFIDTCP->rfidRS(channel,pRfidMSG->pMsgBuff,&retStatus);
TRACE("RS [ret=%d][%s][status=%d]n",ret,pRfidMSG->pString,retStatus);
pRFIDTCP->disconnectDevice();
delete pRFIDTCP;
delete pRfidMSG;
}
最终没能实现。要求厂家提供VB示例代码也没能给过来。
转而研究了其Socket的通讯方式。其报文格式如下:
报文格式请参看手册26页,27页。报文格式是这样的
*****************************************************
CT格式
00:06:04:02:30:33 (6个字节的字符)
00:06 报文总长度
就是CT的命令格式,0x 10是读 就是 SR命令, 000610220000
通道1,0000 0010 红色标记的就是通道的编号
30:33 Tag type (IPC03)
发生命令以后,控制器会回复一个6个字节的确认短报文,一个6个或者6个字节以上的回复报文。
确认短报文:
00:06:04:02:FF:01
00:06报文总长度
重复一下命令(CT)
重复受到的命令
FF Status FFh (说明正在执行)
回复的计数器 到0xff以后会重新开始计数
回复报文
00:06:04:02:00:02
00:06报文总长度
04重复一下命令(CT)
02重复受到的命令
Status 0 (0表示命令成功完成,如果不是0,可以参考10 Troubleshooting 的10.1 Fault/Status messages P114. 有返回错误码的解释)
02回复的计数器
*****************************************************
单次写SW 命令:
0A 40 12 00 01 39 38 37 36
0A报文总长度
40命令(SW)
(0001 0010)红色表示写一个双字,也就是4个字节
01 表示起始地址是1.也就从地址0 偏移一个双字(4个字节)
38 37 36 表示写入的数值,这里就是ASCII :9876
SW的确认短报文
06 40 12 ff 67
SW的回复报文
06 40 02 00 68
**************************************************
单次读SR 命令:
00:06:10:22:00:00
00:06 报文总长度
10命令(SR)
(0010 0010)Word number (2) / Channel (1), toggle bit (0)
00:00 读起始地址(0000)
确认短报文
00:06:10:22:FF:01
00:06报文总长度
10重复一下命令(SR)
(0010 0010)Word number (2) / Channel (1), toggle bit (0)
FF Status FFh (processing command)
01回复的计数器
回复报文
00:0E:10:22:00:02:31:32:33:34:35:36:37:38
00:0E报文总长度(14 bytes)
10重复一下命令(SR)
(0010 0010)Word number (2) / Channel (1), toggle bit (0)
Status 0 (成功运行)
回复的计数
31:32:33:34:35:36:37:38 读出数据
注意,:冒号表示一个字节间的分割,但是TCP传输报文中,没有冒号的。
拿到这些资料,首先面对的问题是WinCC中没有WinSock控件,网上找到了一篇《关于在WINCC中使用WinSock控件进行TCP_IP通讯的例程》的文档,介绍的比较详细。
一、在WINCC中使用WinSock控件进行TCP_IP通讯的例程
1、WinSock控件注册
在WinCC中使用WinSock控件前,需要先进行注册。下载地址:http://down5.cr173.com//soft1/MSWINSCK.rar
注册方法如下:
使用记事本新建一个后缀名为bat的文件,编辑文件,加入以下文本:
Copy /y MSWINSCK.OCX %windir%system32
regsvr32/s %windir%system32MSWINSCK.OCX
保存文件退出。双击执行即可。(下载地址中提供了安装.bat文件,双击即可)
2、在WinCC中添加WinSock控件
在WinCC图形编辑器中打开需要显示服务器数据的画面,选择“对象选项板”的“控件”选项卡,在选项卡中选择“添加/删除”,在“选择OCX控件”对话框中选择“Microsoft WinSock Control, version 6.0”进行注册。
在对象选项板中的WinSock控件拖入画面中。
在实施到服务器上时,碰到了以下问题。
“未找到许可证信息(winsock)”
网上找到了一个神解决方案:
打开注册表,找到HKEY_CLASSES_ROOT下的Licenses,在他下面添加一个项,并且命名为2c49f800-c2dd-11cf-9ad6-0080c7e7b78d,然后修改这个项的默认值为:mlrljgrlhltlngjlthrligklpkrhllglqlrk,关闭注册表编辑器,再次启动WINCC即可。这不是WinCC的许可问题,而是WinSock的注册问题。
二、因为需要做数据转换,需导入ads.dll,下载 ArrayConvert.exe 文件。
以下文件是可从 Microsoft 下载中心下载:
收起这个图片展开这个图片Download the arrayconvert.exe package now. (http://download.microsoft.com/download/exch55/sample/55/win98/en-us/arrayconvert.exe)
打开您下载 ArrayConvert.exe 文件文件夹,然后双击 ArrayConvert.exe 文件。
在 解压缩到文件夹 框中键入 C:ArrayConvert,然后单击 解压缩。
单击 确定,然后单击 关闭。
单击 开始,单击 运行,键入 regsvr32 C:ArrayConvertads.dll,然后按 ENTER 键。
单击 确定。
'-------------------------------------------------------------------------------
' 连接倍加福RFID
'-------------------------------------------------------------------------------
Function RFID_Connect
Dim Obj_SockClient
Dim cnvt
Dim Tag_intTXStatus
Dim i,j
Dim Tag_f,Tag_b
ScreenItems("msg").Text = "Obj_SockClient init" & Chr(13) & Chr(10) & ScreenItems("msg").Text
'获得当前窗口中的WinSock对象
Set Obj_SockClient = ScreenItems("objSock")
'这是一个转换DLL,后面还要讲到
Set cnvt = CreateObject("ADS.ArrayConvert")
'以下是建立连接前的参数初始化工作,远程地址和端口号根据实际情况修改,此处设置是为了方便测试工作,可使用TCP&UDP测试工具进行测试。
'Obj_SockClient.Protocol = "sckTCPProtocol"
'Obj_SockClient.RemoteHost = "192.168.1.222"
'Obj_SockClient.RemotePort = 10000
ScreenItems("msg").Text = "Obj_SockClient.Protocol=" & Obj_SockClient.Protocol & Chr(13) & Chr(10) & ScreenItems("msg").Text
ScreenItems("msg").Text = "Obj_SockClient.RemoteHost=" & Obj_SockClient.RemoteHost & Chr(13) & Chr(10) & ScreenItems("msg").Text
ScreenItems("msg").Text = "Obj_SockClient.RemotePort=" & Obj_SockClient.RemotePort & Chr(13) & Chr(10) & ScreenItems("msg").Text
ScreenItems("msg").Text = "Obj_SockClient.State=" & Obj_SockClient.State & Chr(13) & Chr(10) & ScreenItems("msg").Text
'连接没有建立、连接错误、同级人员正在关闭连接,这三种情况下,先关闭连接,再尝试建立连接。
If (Obj_SockClient.State = 0) Or (Obj_SockClient.State = 9) Or (Obj_SockClient.State = 8) Then
Obj_SockClient.Close
Obj_SockClient.Connect
End If
ScreenItems("msg").Text = "Obj_SockClient.Connect=" & Obj_SockClient.State & Chr(13) & Chr(10) & ScreenItems("msg").Text
End Function
Sub DataArrival(ByVal Item, ByVal bytesTotal)
On Error Resume Next
Dim cnvt
Dim obj_OutText
Dim strReceive
Dim strFromRec
Dim strTest
Set cnvt = CreateObject("ADS.ArrayConvert")
Set obj_OutText = ScreenItems("objOutText")
' MsgBox "DataArrival:bytesTotal=" & bytesTotal
strFromRec = ""
Set strReceive = Null
'从接收缓冲区取得数据,并清空缓冲区
Item.GetData strReceive
strFromRec = cnvt.CvOctetStr2vHexStr(strReceive)
'obj_OutText.Text = "strFromRec=" & strTest & Chr(13) & Chr(10) & obj_OutText.Text
If Len(strFromRec) > 0 Then
getDataArrival(strFromRec)
End If
End Sub
最后
以上就是会撒娇宝马为你收集整理的在WINCC中使用WinSock控件与倍加福RFID进行TCP_IP通讯的全部内容,希望文章能够帮你解决在WINCC中使用WinSock控件与倍加福RFID进行TCP_IP通讯所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复