PLC通訊--同步

1、 OPC服務介紹

  西門子提供的最新軟件:Simatic Net PC-Software CD 2005為各種組態軟件的開發提供了一個統一的平臺,它建立的PC站既為一些組態軟件,如">

欧美成人aaaaa免费视频_亚洲欧美激情小说另类_欧美激情一区二区三区视频_一级在线|欧洲

技術頻道

運用VC#編程通過OPC方式實現PC機與西門子PLC通訊—

運用VC#編程通過OPC方式實現PC機與西門子PLC通訊--同步

1、 OPC服務介紹

  西門子提供的最新軟件:Simatic Net PC-Software CD 2005為各種組態軟件的開發提供了一個統一的平臺,它建立的PC站既為一些組態軟件,如:WinCC、Protol等提供了與PLC的通訊平臺,也提供了一套編程接口,可使用高級語言編程通過Simatic Net訪問PLC數據。本文討論的主要就是這個編程接口,最新版的Simatic NET支持五種編程方式:

<1>、ActiveX控件

  提供了一系列數據訪問控件,以便于向VB6這種語言使用控件的方式與PLC通訊。

<2>、OPC自動化

為VB6、Dephi等語言運用OLE 自動化的方式進行編程。

<3>、OPC用戶接口

  這是專門為VC++提供的一種高效編程方式,其靈活程度與執行效率比前面的兩種方式均要高得多。

<4>、針對微軟的.NET平臺的OPC用戶接口

  這也是一種非常靈活的編程接口,不過它針對的是.NET平臺,其提供了大量的.NET類庫,以便于像VC#、VB.NET等高級語言編程。本文將詳細的介紹該接口。

<5>、OPL XML接口

  顧名思義,主要是針對XML編程的。

  對于<2>、<3>、<4>編程方式,他們各自又可以分為同步訪問方式和異步訪問方式。按西門子的文檔解釋:同步通訊指的是當一個客戶在訪問服務器時,其他客戶的訪問必須等待,直到服務器處理完該客戶的請求,才能繼續進行下一個服務,異步訪問與之正好相反,本文主要講的是同步編程篇,異步篇以后再提供。

2、 配置OPC服務器

  要進行編程,必須先配置服務器。本文以Prfibus DP網絡為例,介紹PC站的配置。其內容主要來自西門子文檔。

需要的軟件:

Step7 V5.3
Simatic Net PC-Software CD 2005

需要的硬件:

  至少為CP5611或以上級別,筆記本可以為CP5511,帶DP口的S7-300 PLC(若使用Simatic NET的仿真功能可以不需要這些硬件,后面會介紹到)

  <1>、組態一個S7站,配置Profibus DP網絡,其DP地址設為3,并下載到PLC,然后把網線由MPI口轉到DP口。S7站的配置這里就不介紹了。

  <2>、在 Step7 V5.3中建立一個新工程,插入一個PC站,并把該PC站的名字改成與你的計算機名字相同。打開該PC站的硬件組態界面。插入OPC服務器和連接卡CP5611(或者CP5511),他們在PC槽中處的位置可以任意,
  注:在插入CP5611時,應該選擇與組態S7站一樣的Profibus網絡,并將網絡地址設為2,一定不要與PLC的地址沖突。

  然后點擊下面工具條標為紅色的按鈕:
  選中”OPC Server”,然后插入一個新的連接,
  在彈出的對話框中選擇連接類型為S7 Connection,
  在OK后,然后在新對話框的紅色標志位置輸入3,表示PLC的地址,
  并選擇Address Details…,設置CPU的槽號為2,
  OK后,然后編譯并保存。

  <3>、然后建立OPC服務器,有兩種方式,本文介紹較簡單的一種。

  打開,Simatic Net中的Station Configurator,一般安裝后,他會自動啟動,并點擊Import Station…按鈕,找到你剛才在Step 7中建立PC站時創建的

  XDBs文件夾下的XDB文件,然后導入成功。

  <4>、可以使用Simatic Net中的OPC Scout,并選擇Simatic NET服務,然后在它下面創建組,然后在組下創建變量,這樣可以監控PLC數據,VC#編程不需要使用該程序,但熟悉使用OPC Scout有利于了解Simatic Net中的編程結構。

  說明:打開Simatic Net中的Configuration Console,選中S7進行如下的配置后,可以不需要PLC、CP5611等并可以模擬,
  上面的所有步驟,均可在Configuration Console下,PC Station的根樹下,選擇相應的幫助文檔得到。
3、 OPC編程

<1>、西門子的變量結構如下:

----------------------服務器------------------------------
/ OPC.SimaticNet OPCServer.Wincc .... (一系列類型的服務器)
/ Group1 Group2 Group3 ...(把更新時間一致的變量統一為一個組)
/ Item1 Item2 ... (變量:I、Q、M、DB等,指向網絡中某個PC站OPC Server服務的某個連接)
-----------------------------------------------------------------------------------------------------------------
  第一層是不同種類的服務器,如:OPC.SimaticNET類型,OPC.SimaticNET.DP類型,OPCServer.WinCC等一系列類型,這里選擇OPC.SimaticNET類型。

第二層是Group,一個服務器下可以有多個組,可以把組理解為掃描周期相同的一系列變量的集合。在開發組態界面時,可以把一個界面中的所有變量統一到一個組中。

第三層是Item,項是指向網絡中某個PC站OPC Server服務的某個連接的一系列變量,如:I、Q、M、DB等

<2>、項的命名

  項即Item,在S7連接中針對的直接是PLC中的變量,因此它的命名很重要:

  格式: :[]
其中的protocolID表示連接類型,在上面的組態PC站時可以選擇,這里應該與它一致,類型有9種,最常用的為S7,即S7連接,其他類型請參看文檔。

  Connectionname:顧名思義,即在上面的組態PC站時產生的連接名,如果使用仿真功能,連接名為DEMO Variablename:變量名有一系列規則,這里舉例說明,讀者也可以使用OPC Scout創建變量,學習程序是如何生成變量名的。

S7:[DEMO]MB1 :表示連接類型為S7,連接名為DEMO(這里為仿真),變量為MB1
S7:[DEMO]QB0,3: 表示為從QB0開始的三個連續變量。
S7:[DEMO]DB10,X4.6 :表示DB10的DBX4.6。

<3>、添加引用

  在VC#開發環境中添加對OpcRcw.Da庫的引用引用,該庫屬于.NET庫,不屬于COM庫,西門子雖然編寫了類庫,以提供對.NET平臺的支持,但這些類庫仍然難于編程,

  里面包含了大量的在托管和非托管區傳輸數據,因此我們需要在它的基礎上再開發一個類庫,以簡化以后的編程,首先在類的開頭使用命名空間:
using System.Runtime.InteropServices;
using OpcRcw.Da;
using System.Collections;

<4>、編程

1、 在類的開頭部分生名變量

private string serverType="";
private IOPCServer pIOPCServer; // OPC server接口
private Object pobjGroup1; // Pointer to group object
private int nSvrGroupID; // server group handle for the added group
private System.Collections.Hashtable groupsID=new Hashtable(11); //用于記錄組名和組ID號
private System.Collections.Hashtable hitemsID=new Hashtable(17); //用于記錄項名和項ID號
private Guid iidRequiredInterface;
private int hClientGroup = 0; //客戶組號
private int hClientItem=0; //Item號
2、 創建服務器,編寫Open()方法
/// 創建一個OPC Server接口
///
/// 返回錯誤信息
/// 若為true,創建成功,否則創建失敗
public bool Open(out string error)
{
error="";bool success=true;
Type svrComponenttyp ;
//獲取 OPC Server COM 接口
iidRequiredInterface = typeof(IOPCItemMgt).GUID;
svrComponenttyp = System.Type.GetTypeFromProgID(serverType);
try
{
//創建接口
pIOPCServer =(IOPCServer)System.Activator.CreateInstance(svrComponenttyp);
error="";
}
catch (System.Exception err) //捕捉失敗信息
{
error="錯誤信息:"+err.Message;success=false;
}
Return true;
}

3、 在服務器上添加用于添加Group的函數
/// 添加組
/// 組名
/// /創建時,組是否被激活
/// //組的刷新頻率,以ms為單位
/// 返回錯誤信息
/// 若為true,添加成功,否則添加失敗
public bool AddGroup(string groupName,int bActive,int updateRate,out string error)
{
error="";
int dwLCID = 0x407; //本地語言為英語
int pRevUpdateRate;
float deadband = 0;
// 處理非托管COM內存
GCHandle hDeadband;
IntPtr pTimeBias = IntPtr.Zero;
hDeadband = GCHandle.Alloc(deadband,GCHandleType.Pinned);
try
{
pIOPCServer.AddGroup(groupName, //組名
bActive, //創建時,組是否被激活
updateRate, //組的刷新頻率,以ms為單位
hClientGroup, //客戶號
pTimeBias, //這里不使用
(IntPtr)hDeadband,
dwLCID, //本地語言
out nSvrGroupID, //移去組時,用到的組ID號
out pRevUpdateRate, //返回組中的變量改變時的最短通知時間間隔
ref iidRequiredInterface,
out pobjGroup1); //指向要求的接口
hClientGroup=hClientGroup+1;
int groupID=nSvrGroupID;
groupsID.Add(groupName,groupID);
}
catch (System.Exception err) //捕捉失敗信息
{
error="錯誤信息:"+err.Message;
}
finally
{
if (hDeadband.IsAllocated) hDeadband.Free();
}
if(error=="")
return true;
else
return false;
}

4、 向指定的組中添加變量的函數
/// 添加多個項到組
///
/// 指定組名
/// 指定項名
/// 由函數返回的服務器確定的項ID號
/// 無錯誤,返回true,否則返回false
public bool AddItems(string groupName,string[] itemsName,int[] itemsID)
{
bool success=true;
OPCITEMDEF[] ItemDefArray=new OPCITEMDEF[itemsName.Length];
for(int i=0;i<ITEMSNAME.LENGTH;I++)
{
hClientItem=hClientItem+1;
ItemDefArray[i].szAccessPath = ""; // 可選的通道路徑,對于Simatiic Net不需要。
ItemDefArray[i].szItemID = itemsName[i]; // ItemID, see above
ItemDefArray[i].bActive = 1; // item is active
ItemDefArray[i].hClient = hClientItem; // client handle
ItemDefArray[i].dwBlobSize = 0; // blob size
ItemDefArray[i].pBlob = IntPtr.Zero; // pointer to blob
ItemDefArray[i].vtRequestedDataType = 2; //Word數據類型
}
//初始化輸出參數
IntPtr pResults = IntPtr.Zero;
IntPtr pErrors = IntPtr.Zero;
try
{
// 添加項到組
((IOPCItemMgt)GetGroupByName(groupName)).AddItems(itemsName.Length,ItemDefArray,out pResults,out pErrors);
// Unmarshal to get the server handles out fom the m_pItemResult
// after checking the errors
int[] errors = new int[itemsName.Length];
Marshal.Copy(pErrors, errors, 0,itemsName.Length);
IntPtr pos = pResults;
for(int i=0;i
{
if (errors[i] == 0)
{
OPCITEMRESULT result = (OPCITEMRESULT)Marshal.PtrToStructure(pos, typeof(OPCITEMRESULT));
itemsID[i] = result.hServer;
this.hitemsID.Add(itemsName[i],result.hServer);
pos = new IntPtr(pos.ToInt32() + Marshal.SizeOf(typeof(OPCITEMRESULT)));

}
else
{
success=false;
break;
}
}
}
catch (System.Exception err) // catch for error in adding items.
{
success=false;
}
finally
{
// 釋放非托管內存
if(pResults != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(pResults);
pResults = IntPtr.Zero;
}
if(pErrors != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(pErrors);
pErrors = IntPtr.Zero;
}
}
return success;
}

  說明:使用該函數時,在類的開頭,應該先聲明整數數據,以用于保存由本函數返回的服務器對每一項分配的Item ID號:

5、 向指定組中指定的一系列項變量寫入數據的公開方法
///
/// 一次性寫入多個值
///
/// 指定組名
/// 由服務器給每個項分配的標志號
/// 一系列值
/// 無錯誤,返回true,否則返回false
public bool Write(string groupName,int[] itemID,object[] values)
{
bool success=true;
IntPtr pErrors = IntPtr.Zero;

if(GetGroupByName(groupName) != null)
{
try
{ //同步寫入
((IOPCSyncIO)GetGroupByName(groupName)).Write(itemID.Length,itemID,values,out pErrors);
int[] errors = new int[itemID.Length];
Marshal.Copy(pErrors, errors, 0,itemID.Length);
for(int i=0;i
{
if (errors[i] != 0)
{
pErrors = IntPtr.Zero;
success=false;
}
}
}
catch(System.Exception error)
{
success=false;
}
}
return success;
}
注:參數int[] itemID應該是與AddItems函數中的int[] itemsID參數相對應。

6、 編寫獲取變量值的函數
/// 一次性讀取多個數據
/// 指定組名
/// >由服務器給每個項分配的標志號
/// 返回的值
/// 無錯誤,返回true,否則返回false
public bool Read(string groupName,int[] itemID,object[] result)
{
bool success=true;
//指向非托管內存
//指向非托管內存
IntPtr pItemValues = IntPtr.Zero;
IntPtr pErrors = IntPtr.Zero;
if(GetGroupByName(groupName)!=null)
{
try
{ //同步讀取
((IOPCSyncIO)GetGroupByName(groupName)).Read(OPCDATASOURCE.OPC_DS_DEVICE,itemID.Length,itemID,out pItemValues,out pErrors);
int[] errors = new int[itemID.Length];
Marshal.Copy(pErrors, errors, 0,itemID.Length);
OPCITEMSTATE[] pItemState=new OPCITEMSTATE[itemID.Length];
IntPtr pos = pItemValues;
for(int i=0;i
{
if (errors[i] == 0)
{
//從非托管區封送數據到托管區
pItemState[i] = (OPCITEMSTATE)Marshal.PtrToStructure(pos,typeof(OPCITEMSTATE));
pos = new IntPtr(pos.ToInt32() + Marshal.SizeOf(typeof(OPCITEMSTATE)));
result[i]=pItemState[i].vDataValue;
}
}
}
catch(System.Exception error)
{
return false;
}
}
return success;
}
  注:同Write()函數一樣,參數int[] itemID應該是與AddItems函數中的int[] itemsID參數相對應。

  通過給類編寫上面的幾個最重要的函數,我們已經可以讀寫PLC數據了,下面給出例子。

  創建一個C#工程,添加對上面開發的類庫的引用,并在窗體類的開頭,聲名:

int[] nt=new int[2];int[] nt1=new int[2];
S7Connection.SynServer server;
其中的SynServer即為上面開發的類。

<1>、創建服務器接口

在程序初始化處,添加:
server =new S7Connection.SynServer(S7Connection.ServerType.OPC_SimaticNET);

<2>、打開連接
string err;
server.Open(out err);

<3>、添加組

server.AddGroup("maiker",1,350,out err);
server.AddGroup("maiker1",1,350,out err);

<4>、添加項(即變量),同樣在程序的初始化中,將一系列項添加到他們各自得組。

string[] m1={"S7:[DEMO]MB1","S7:[DEMO]MW3"};
string[] m2={"S7:[DEMO]MB6","S7:[DEMO]MW8"};
server.AddItems("maiker",m1,nt);
server.AddItems("maiker1",m2,nt1);

<5>、讀寫數據,這里以寫數據為例:

obj[0]=this.textBox2.Text;
obj[1]=this.textBox3.Text;
if(radioButton1.Checked)
{
server.Write("maiker",nt,obj);
}
else if(radioButton2.Checked)
{
server.Write("maiker1",nt1,obj);
}

  至此并完成了數據的通訊,如何,只要你把類庫開發完善,在它的基礎上再開發,會異常簡單,本人已開發了完善的類庫,上面的類庫只是把最重要的部分講解出來,我曾經在網上求助過很多次這方面的知識,無人應答。唉!太不容易了,等待Simatic NET軟件花費了我一個月的時間,然后讀幾百頁的英文文檔,到開發程序,并測試花費了我一個星期的空閑時間,寫這篇文章,又花費了我一個晚上的時間,不過我還是愿意把這些摸索出來的東西發給大家。



文章版權歸西部工控xbgk所有,未經許可不得轉載。

欧美成人aaaaa免费视频_亚洲欧美激情小说另类_欧美激情一区二区三区视频_一级在线|欧洲

      9000px;">

          欧美丝袜自拍制服另类| 欧美国产日韩亚洲一区| 国产精品毛片高清在线完整版 | 欧美日韩亚洲国产综合| 2020国产成人综合网| 精品sm在线观看| 日韩av电影免费观看高清完整版在线观看| 久久 天天综合| 亚洲国产乱码最新视频| 国产91精品精华液一区二区三区| 91麻豆免费观看| 成人av在线观| bt欧美亚洲午夜电影天堂| 欧美在线一区二区三区| 国产欧美精品一区aⅴ影院| 奇米色一区二区| 欧美日韩国产影片| 一区二区三区精品视频| 不卡一区二区在线| 成人免费观看av| 韩国精品免费视频| 日韩欧美中文字幕一区| 欧美精品丝袜中出| 国产日产欧美一区二区视频| 日本不卡123| 精品嫩草影院久久| 7777精品伊人久久久大香线蕉最新版| 亚洲猫色日本管| 欧美日本一道本在线视频| 日韩一区在线播放| 欧美亚洲精品一区| 蜜臂av日日欢夜夜爽一区| 亚洲国产va精品久久久不卡综合 | 色悠久久久久综合欧美99| 最新久久zyz资源站| 亚洲综合色婷婷| 欧美影片第一页| 日韩一区二区在线看片| 亚洲视频图片小说| 91精品国产综合久久久久久久 | 视频在线观看国产精品| 日韩视频一区二区在线观看| 成人午夜在线视频| 日韩电影在线免费看| 美国欧美日韩国产在线播放| 狠狠色综合播放一区二区| 亚洲国产精品成人综合| 欧美日韩国产高清一区二区| 国产精品一区二区视频| 国产精品色呦呦| 日韩一区二区三区视频在线| 91视频精品在这里| 91精品国产综合久久香蕉麻豆| 国产91精品欧美| 免费不卡在线观看| 日韩一本二本av| 国产一二精品视频| 免费高清视频精品| 亚洲成人福利片| 一区二区三区欧美视频| 成人免费在线播放视频| 国产午夜精品理论片a级大结局 | 91麻豆福利精品推荐| 久久精品理论片| 久久国产精品第一页| 青草国产精品久久久久久| 亚洲精品视频一区二区| 国产精品国产三级国产有无不卡 | 久久99精品久久只有精品| 日一区二区三区| 激情av综合网| 国产suv精品一区二区6| 久久精品一区蜜桃臀影院| 久久伊人蜜桃av一区二区| 欧美成人精精品一区二区频| 亚洲影视资源网| 蜜臀av亚洲一区中文字幕| 欧美日本一区二区三区| 亚洲综合激情另类小说区| 中文字幕免费一区| 亚洲精品国产a| 欧美二区乱c少妇| 国产欧美精品国产国产专区| 亚洲欧美激情一区二区| 国产一区二区三区四区五区入口| 9i在线看片成人免费| 5858s免费视频成人| 盗摄精品av一区二区三区| 欧美在线短视频| 国产三级欧美三级日产三级99| 亚洲女人的天堂| 成人夜色视频网站在线观看| 欧美日韩不卡在线| 亚洲精选一二三| 99国产精品久久久久| 欧美大片免费久久精品三p| 一区二区成人在线| 成人综合婷婷国产精品久久| 正在播放一区二区| 亚洲国产成人高清精品| 久草精品在线观看| 成人精品小蝌蚪| 91看片淫黄大片一级在线观看| 久久婷婷色综合| 国产精品一区二区91| 久久色在线视频| 亚洲人成网站在线| 国产成人精品免费网站| 日韩欧美在线网站| 亚洲精品国久久99热| 91成人网在线| 婷婷成人综合网| 欧美成人三级在线| 成人污污视频在线观看| 国产精品传媒在线| 欧美日韩视频在线第一区 | 久久成人免费网站| 懂色av一区二区三区免费看| 精品卡一卡二卡三卡四在线| 国产成人a级片| 欧美色综合影院| 国产综合成人久久大片91| 亚洲欧洲中文日韩久久av乱码| 色哟哟国产精品| 蜜臀av国产精品久久久久| 精品福利一二区| 色婷婷激情一区二区三区| 婷婷成人综合网| 8v天堂国产在线一区二区| 国产麻豆精品久久一二三| 亚洲乱码国产乱码精品精的特点 | 色天使久久综合网天天| 久久久亚洲欧洲日产国码αv| 日韩成人一级大片| 一区在线中文字幕| 日韩欧美久久久| 成人福利电影精品一区二区在线观看| 亚洲aⅴ怡春院| 亚洲一卡二卡三卡四卡| 日本一区二区三区久久久久久久久不| 欧美亚洲动漫制服丝袜| 成人激情小说网站| 国产九色sp调教91| 久久99精品久久久久久| 亚洲成人av福利| 亚洲免费毛片网站| 日韩影视精彩在线| 日本精品视频一区二区三区| 成人中文字幕电影| 成人v精品蜜桃久久一区| 韩国成人福利片在线播放| 亚洲影视在线播放| 午夜精品福利一区二区三区蜜桃| 亚洲黄一区二区三区| 亚洲激情第一区| 午夜久久久久久电影| 欧美日韩中文字幕一区二区| 91精品国产福利| 国产精品传媒视频| 国产老妇另类xxxxx| 色一区在线观看| 久久久91精品国产一区二区三区| 欧美午夜一区二区| 国产欧美日韩视频一区二区| 亚洲精品中文在线| av在线免费不卡| 国产欧美一区二区精品久导航| 日韩国产精品大片| 精品视频123区在线观看| 亚洲人成精品久久久久| 成人黄色777网| 亚洲人成小说网站色在线| 成人午夜又粗又硬又大| 欧美国产一区二区在线观看| 另类小说一区二区三区| 欧美日韩国产一级二级| 天堂av在线一区| 91精品国模一区二区三区| 日本午夜精品一区二区三区电影 | 精品一区二区久久| 欧美精品一区二区三区一线天视频| 欧美日韩国产色站一区二区三区| 亚洲日本在线天堂| 在线中文字幕一区二区| 亚洲精品欧美在线| 亚洲午夜一区二区| 3d成人动漫网站| 国内久久婷婷综合| 国产喷白浆一区二区三区| 国产精品18久久久| 亚洲精品乱码久久久久久| 欧美精选一区二区| 蜜桃久久久久久久| 久久久噜噜噜久噜久久综合| 丁香另类激情小说| 亚洲制服丝袜在线| 在线观看视频欧美| 国精产品一区一区三区mba视频| 成人精品免费看| 日韩一区精品字幕|