http://blog.csdn.net/ohiolee/article/details/17878567在柔性制造FMS系統(tǒng)中,本次項目以西門子PLC300,PLC200和倍加福RFID構(gòu)建自動化輸送和立體倉庫物流方案。
硬件:
1、一個西門子PLC300為主站,四個PLC200為從站
2、倍加福RFID IC-KP-B17-AIDA1 IDENTControl interface with Ethernet interface的識別系統(tǒng)
系統(tǒng):
因為西門子PLC,選用WinCC做組態(tài)畫面,VBS實現(xiàn)MES/WMS的功能。
課題:
因為首次選用帶TCP/IP的倍加福RFID,需要解決其與WinCC的通訊問題。
倍加福RFID有兩種方式可以進行通訊,一、DLL,通過加載和調(diào)用所提供的DLL進行通訊;二、TCP的Socket進行通訊。
首先嘗試了DLL,在WinCC中是可以調(diào)用DLL的,嘗試了一個簡單的DLL進行測試。
在WinCC圖形編輯器中添加一個按鈕,2個輸入輸出框。在按鈕點擊事件中創(chuàng)建以下代碼:
- #include "apdefap.h"
- void OnLButtonDown(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName, UINT nFlags, int x, int y)
- {
-
- #pragma code ("c:/DLL/T1_C.dll") //指定絕對路徑,網(wǎng)上有說放在WinCC/bin目錄的,好像不靠譜還是這樣好。
- int aufruf1(int a); //聲明函數(shù)
- #pragma code ()
-
- int value;
- value = GetTagDouble("var1"); //Return-Type: double
- SetTagDouble("result",aufruf1(value)); //Return-Type: BOOL
-
- }
其中T1_C.dll里有一個返回參數(shù)+100的aufruf1函數(shù)。詳見
http://www.cnblogs.com/ohiolee/articles/3498381.html
但是倍加福提供的RFID_TCP_DLL及示例代碼是C++的,沒怎么弄明白要怎么聲明里面的函數(shù),還有類的問題。代碼如下:
- /* 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;
-
- }
最終沒能實現(xiàn)。要求廠家提供VB示例代碼也沒能給過來。
轉(zhuǎn)而研究了其Socket的通訊方式。其報文格式如下:
- 報文格式請參看手冊26頁,27頁。報文格式是這樣的
-
- *****************************************************
- CT格式
-
- 00:06:04:02:30:33 (6個字節(jié)的字符)
- 00:06 報文總長度
- 就是CT的命令格式,0x 10是讀 就是 SR命令, 000610220000
- 通道1,0000 0010 紅色標記的就是通道的編號
- 30:33 Tag type (IPC03)
- 發(fā)生命令以后,控制器會回復一個6個字節(jié)的確認短報文,一個6個或者6個字節(jié)以上的回復報文。
-
- 確認短報文:
- 00:06:04:02:FF:01
- 00:06報文總長度
- 重復一下命令(CT)
- 重復受到的命令
- FF Status FFh (說明正在執(zhí)行)
- 回復的計數(shù)器 到0xff以后會重新開始計數(shù)
-
- 回復報文
-
- 00:06:04:02:00:02
- 00:06報文總長度
- 04重復一下命令(CT)
- 02重復受到的命令
- Status 0 (0表示命令成功完成,如果不是0,可以參考10 Troubleshooting 的10.1 Fault/Status messages P114. 有返回錯誤碼的解釋)
- 02回復的計數(shù)器
-
- *****************************************************
- 單次寫SW 命令:
- 0A 40 12 00 01 39 38 37 36
- 0A報文總長度
- 40命令(SW)
- (0001 0010)紅色表示寫一個雙字,也就是4個字節(jié)
- 01 表示起始地址是1.也就從地址0 偏移一個雙字(4個字節(jié))
- 38 37 36 表示寫入的數(shù)值,這里就是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回復的計數(shù)器
-
- 回復報文
-
- 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 (成功運行)
- 回復的計數(shù)
- 31:32:33:34:35:36:37:38 讀出數(shù)據(jù)
-
- 注意,:冒號表示一個字節(jié)間的分割,但是TCP傳輸報文中,沒有冒號的。
拿到這些資料,首先面對的問題是WinCC中沒有WinSock控件,網(wǎng)上找到了一篇《關(guān)于在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%\system32\MSWINSCK.OCX
保存文件退出。雙擊執(zhí)行即可。(下載地址中提供了安裝.bat文件,雙擊即可)
2、在WinCC中添加WinSock控件
在WinCC圖形編輯器中打開需要顯示服務(wù)器數(shù)據(jù)的畫面,選擇“對象選項板”的“控件”選項卡,在選項卡中選擇“添加/刪除”,在“選擇OCX控件”對話框中選擇“Microsoft WinSock Control, version 6.0”進行注冊。
在對象選項板中的WinSock控件拖入畫面中。

在實施到服務(wù)器上時,碰到了以下問題。
“未找到許可證信息(winsock)”
網(wǎng)上找到了一個神解決方案:
打開注冊表,找?到HKEY_CLASSES_?ROOT下的Licenses,在他下面添加一個項,并且命名為2c49f800-c2dd-11cf-9ad6-0080c7e7b78d,然后修改這個項的默認值為:mlrljgrlhltlngjlthrligklpkrhllglqlrk,關(guān)閉注冊表編輯器,再次啟動WINCC即可。
這不是WinCC的許可問題,而是WinSock的注冊問題。


二、因為需要做數(shù)據(jù)轉(zhuǎn)換,需導入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,然后單擊 解壓縮。
單擊 確定,然后單擊 關(guān)閉。
單擊 開始,單擊 運行,鍵入 regsvr32 C:\ArrayConvert\ads.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")
-
- '這是一個轉(zhuǎn)換DLL,后面還要講到
- Set cnvt = CreateObject("ADS.ArrayConvert")
-
- '以下是建立連接前的參數(shù)初始化工作,遠程地址和端口號根據(jù)實際情況修改,此處設(shè)置是為了方便測試工作,可使用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
-
- '連接沒有建立、連接錯誤、同級人員正在關(guān)閉連接,這三種情況下,先關(guān)閉連接,再嘗試建立連接。
- 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
- '從接收緩沖區(qū)取得數(shù)據(jù),并清空緩沖區(qū)
- 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
|