
西门子标准电缆6XV1830-0EH10
西门子标准电缆6XV1830-0EH10
{心中有空间,梦想就有可能}
SIMATIC NET, PROFIBUS 快速标准电缆 GP, 2 芯, 屏蔽, 为快速安装而特殊设计,最大长度: 1000m, 最小订购数量: 20m, 按米销售
1 引言
2 s7-200通讯指令及特殊字节
pp:两位用于选择通讯的校验方式 当这两位的组合是:
n=1时:表示禁止接收信息
en=0时:禁止接收信息
发送指令用于激活发送数据缓冲区tbl中的数据,数据格式如下所示,数据缓冲区中的第一个数据是指定要发送的数据的总字节数,最大为255个,从第二个数据开始是依次要发送的数据。port指定用于发送的端口,在发送完缓冲区中的最后一个数据时产生中断事件。
可能是剩余时间值减至0之后的下一扫描周期T1的常开触点才闭合,而下一扫描周期T1又被自己的常闭触点复位,所以图1不能将M2.0置位。交换两个程序段的上、下位置,M2.0就能被置位了。
我有一个变量名是DB2.DB160用在程序块中,数据块我知道在DB2内,那我如何在程序中快速并全部一一找到这个变量?我用交叉参考没有找到这个变量,不知有没有其它的办法,因为程序比较大,一一找比较麻烦,我想快速下一个、下一个这样显示出来。
答:要看你要找的地址是以什么形式在程序中应用的,如果是直接写成DB2.DBB160;DB2.DBW160;DB2.DBD160这种形式是可以用交叉参考找到的。也可以用Ctrl+Alt+Q组合键快速打开Go To LOCAIION 窗口,在Address中直接输入需要找的地址。
如果在程序中用OPN DB2,然后后面直接用DBB160或DBW160或DBD160,那么就只能找DB2的引用位置,慢慢找了。
还有一种就更费劲了,就是FC或者FB的引脚直接填写DB块的块号,在程序中打开,这个不是编程人员很难查的。或者直接在程序中写成
MD0由字节MB0~MB3组成,MB0为最高字节,MB3为最低字节。这个顺序可能和别的PLC或计算机的编程语言的规定刚好相反!
用变量表监控MD0,可以验证此结论,显示格式中HEX是十六进制,BIN为二进制。
在上一次发表的<运用VC#编程通过OPC方式实现PC机与西门子PLC通讯>主要讲的是同步通讯,本文将主要讲解如何编程实现异步通讯,通过讲解你也将会知道同步通讯与异步通讯的区别,以及在什么情况下使用异步通讯。
{西门子与客户携手,让关键所在,逐一实现}
联 系 人: 黄勇《黄工》 24小时联系手机: 13701633515
直线销售 电 话: 021-31660605 在 线 商 务 QQ: 77956468
德国制造 现货
全新原装 参数
质量保证 保修
价格优势 特价
我公司大量现货供应,价格优势,品质保证,德国原装进口
西门子S7-200PLC自由口通讯的实现及应用设计
为了达到和通讯协议已知的控制设备进行数据交换,以提高自动化控制系统的灵活性,很多plc制造商都相继的开发出了方便、灵活的自由口通讯方式,例如三菱公司的fx2系列plc, omron公司的cjm1系列的plc, 西门子公司的s7-200系列plc等都提供了自由口通讯模式。自由口通讯是指plc提供了串行的通讯硬件,和用于定制通讯协议的相关指令,在控制系统中,当要和plc连接的控制设备的通讯协议已知时,可以在plc中进行编程定制通讯协议,和控制设备进行数据通讯。本文主要介绍西门子s7-200的自由口和计算机的串口进行的通讯,计算机中采用visual basic进行编程,从而实现计算机与可编程控制器的直接控制。该通讯方式具有效率高、容易实现、通讯硬件简单、容易配置等特点在工业控制领域中被广泛应用。
采用自由口通讯方式时,s7-200上的rs485口完全由用户控制,可以与任何协议已知的设备进行通讯,在这种情况下通讯协议完全由用户制定,为此,s7-200提供了用于进行通讯协议定制的特殊标志位以及相关的通讯指令。
2.1 特殊标志字节
s7-200用于自由口通讯模式定义的特殊标志字节有smb30和smb130,smb30用于s7-200的端口0的通讯,smb130用于s7-200的端口1的通讯,两者的格式一样,下面我们以smb130为例,介绍其组成。smb130各位的含义如下:
00无校验 01 偶校验 10 无校验 11 奇校验
d:这一位用于选择通讯的数据位数 d=1时7个数据位,d=0时8个数据位
bbb:用于选择自由口通讯是的波特率,这三位的组合和通讯波特率的关系如下:
000 ——38400bps
001 ——19200bps
010 ——9600bps
011 ——4800bps
100 ——2400bps
101 ——1200bps
110 —— 600 bps
111 —— 300 bps
mm: 用于通讯协议的选择,当这两位的组合是:
00 ppi从站模式 01 自由口通讯模式 10 ppi主站模式
2.2 接收信息的状态字节
s7-200在自由口通讯时用于接受信息的状态有smb86和smb186,smb86用于s7-200的端口0的通讯,smb186用于s7-200的端口1的通讯,两者的格式一样,下面我们以smb186为例,介绍其组成。smb186各位的含义如下:
r=1时:表示接收信息结束
e=1时:表示收到结束字符
t=1时:表示接收信息超时错误
c=1时:表示接收信息字符超长错误
p=1时:表示接收信息奇、偶校验错误
2.3 接收信息的控制字节
s7-200在自由口通讯时用于接受信息的控制字节有smb87和smb187,smb87用于s7-200的端口0的通讯,smb187用于s7-200的端口1的通讯,两者的格式一样,下面我们以smb187为例,介绍其组成。smb187各位的含义如下:
en=1时:允许接收信息
sc=0时:不使用起始字符开始
sc=1时:使用起始字符做为接收信息的开始
ec=0时:不使用结束字符结束
ec=1时:使用结束字符做为接收信息的结束
il=0时:不使用空闲线检测
il=1时:使用空闲线检测
c/m=0时:定时器是字符定时器
c/m=1时:定时器是信息定时器
tmr=0时:不使用超时检测
tmr=1时:使用超时线检测
bk=0时:不使用中断检测
bk=1时:使用中断检测
2.4 其它和自由口通讯有关的特殊字节(见表1)
2.5 自由口通讯的指令
(1) 发送指令xmt 其指令格式如图所示:
(2) 发送指令rcv其指令格式如图所示:
S7-300定时器的问题
下图中I0.0的常开触点闭合时,T1开始定时,剩余时间值减至0时,在下一扫描周期,T1的常闭触点断开,T1因为线圈断电被复位。复位后下一扫描周期T1的常闭触点闭合,又开始定时。因此T1周期性地定时,定时的周期为预置值3s。
如何快速找出STEP7程序数据中DB2.DB160?
OPN DB2
L DW#16#84000500
LAR1
L DBB[AR1,P#0.0]
不仅不好查,还不太容易看。
这种也是要能把程序全部理解才能知道的,没有什么捷径可走。
S7-300的双字MD0中哪一位是最高位,哪一位是最低位?
在MB0中,M0.7最高位,接着为M0.6……M0.0最低位。MD0中各位的排列顺序如下,M0.7为最高位,M3.0为最低位。
M0.7、0.6、0.5、0.4、0.3、0.2、0.1、0.0,M1.7、1.6、1.5、1.4、1.3、1.2、1.1、1.0
M2.7、2.6、2.5、2.4、2.3、2.2、2.1、2.0,M3.7、3.6、3.5、3.4、3.3、3.2、3.1、3.0
运用VC#编程通过OPC方式实现PC机与西门子PLC通讯-异步篇
1、 配置OPC服务器
对于服务器的配置与同步通讯的配置一样,这里不需再讲解,若有不清楚的,可以参阅之前发布的<运用VC#编程通过OPC方式实现PC机与西门子PLC通讯>
2、 OPC编程
变量组、项的命名规则与同步通讯的一样,这里不再描叙,下面主要就开发一个异步通讯类 AsynServer来讲解如何编程。
<1>、引用
在VC#开发环境中添加对OpcRcw.Da库以及OpcRcw.Comn库的引用,该库属于.NET库,不属于COM库,西门子虽然编写了类库,以提供对.NET平台的支持,但这些类库仍然难于编程,里面包含了大量的在托管和非托管区传输数据,因此我们需要在它的基础上再开发一个类库,以简化以后的编程,首先在类的开头使用命名空间:
using OpcRcw.Comn;
using OpcRcw.Da;
using System.Runtime.InteropServices;
using System.Collections;
<2>、编程
异步编程的原理就是在OPC服务器那边检测当前活动的变量组,一但检测到某一个变量,譬如变量Q0.0从1变成0,就会执行一个回调函数,以实现针对变量发生变化时需要实现的动作,在这里可以采用委托来实现该功能。
1、 在命名空间的内部、类 AsynServer声明之前添加委托的申明:
// 定义用于返回发生变化的项的值和其对应的客户句柄
public delegate void DataChange(object[] values,int[] itemsID);
2、 该类继承于西门子提供的库接口IOPCDataCallback
public class AsynServer:IOPCDataCallback
在类的开头部分声明变量:
struct groupStru
{
public int groupID;
public object groupObj;
}
internal const int LOCALE_ID = 0x407; //本地语言
private Guid iidRequiredInterface;
private string serverType="";
private int hClientGroup = 0; //客户组号
private int nSvrGroupID; // server group handle for the added group
private Hashtable hashGroup; //用于把组收集到一起
private int hClientItem=0; //Item号
3、编写构造函数,接收委托参数已确定当数据发生变化时需要执行的方法入口点:
//创建服务器
//svrType 服务器类型的枚举
//dataChange 提供用于在数据发生变化时需要执行的函数入口
public AsynServer(ServerType svrType,DataChange dataChange)
{
switch(svrType)
{
case ServerType.OPC_SimaticHMI_PTPRO:
serverType="OPC.SimaticHMI.PTPro";break;
case ServerType.OPC_SimaticNET:
serverType="OPC.SimaticNET";break;
case ServerType.OPC_SimaticNET_DP:
serverType="OPC.SimaticNET.DP";break;
case ServerType.OPC_SimaticNET_PD:
serverType="OPC.SimaticNET.PD";break;
case ServerType.OPCServer_WinCC:
serverType="OPCServer.WinCC";break;
}
hashGroup=new Hashtable(11);
dtChange=dataChange;
}
4、创建服务器
// 创建一个OPC Server接口
//error 返回错误信息
//若为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 success;
}
5、 编写添加Group的函数
///
/// 添加组
///
/// 组名
/// /创建时,组是否被激活
/// //组的刷新频率,以ms为单位
/// 返回错误信息
/// 若为true,添加成功,否则添加失败
public bool AddGroup(string groupName,int bActive,int updateRate,out string error)
{
error="";bool success=true;
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;
groupStru grp=new groupStru();
grp.groupID=nSvrGroupID;grp.groupObj=pobjGroup1;
this.hashGroup.Add(groupName,grp);//储存组信息
// 对异步操作设置回调,初始化接口
pIConnectionPointContainer = (IConnectionPointContainer)pobjGroup1;
Guid iid = typeof(IOPCDataCallback).GUID;
pIConnectionPointContainer.FindConnectionPoint(ref iid,out pIConnectionPoint);
pIConnectionPoint.Advise(this,out dwCookie);
}
catch (System.Exception err) //捕捉失败信息
{
error="错误信息:"+err.Message;success=false;
}
finally
{
if (hDeadband.IsAllocated) hDeadband.Free();
}
return success;
}
编写激活、或者取消激活组的函数
在同步编程中对于组的激活或者取消激活没有实质的意义,但在异步通讯编程中却异常重要,这是因为OPC服务器只对当前处于活动状态的组中的变量进行监控,同时这也是很有必要的,因为我们可以把不同界面中的变量编程不同的组,即同一界面中的变量规成一个组,而在某一时刻提供给用户的只有一个界面,让该界面中用到的组处于活动状态,这样执行委托调用时只会执行于该界面中有关的变量检测,而如果让所有的组处于活动状态,则当前没有显示给用户的界面用到的变量若发生变化也会触发对委托函数的调用,这根本是没有必要的,同时会大大降低程序的性能,请严格控制组的激活。
///
/// 激活或者取消激活组
///
/// 指定组名
/// true为激活,false为取消激活
/// 若有错误,返回错误信息
/// 若为true,添加成功,否则添加失败
public bool AciveGroup(string groupName,bool toActive,out string error)
{
error="";bool success=true;
//通过名称获取组
object grp=((groupStru)hashGroup[groupName]).groupObj;
IOPCGroupStateMgt groupStateMgt=(IOPCGroupStateMgt)grp;
//初始化传递参数
IntPtr pRequestedUpdateRate = IntPtr.Zero; //由客户指定的Item更新间隔时间
int nRevUpdateRate = 0; //由服务器返回的能够更新的最短时间间隔
IntPtr hClientGroup = IntPtr.Zero; //客户组
IntPtr pTimeBias = IntPtr.Zero;
IntPtr pDeadband = IntPtr.Zero;
IntPtr pLCID = IntPtr.Zero;
// 激活或者取消激活组
int nActive = 0;
GCHandle hActive = GCHandle.Alloc(nActive,GCHandleType.Pinned);
if(toActive)
hActive.Target = 1;
else
hActive.Target = 0;
try
{
groupStateMgt.SetState(pRequestedUpdateRate,out nRevUpdateRate,hActive.AddrOfPinnedObject(),pTimeBias,pDeadband,pLCID,hClientGroup);
}
catch(System.Exception err)
{
error="错误信息:"+err.Message;success=false;
}
finally
{
hActive.Free();
}
return success;
}
7、 向指定的组中添加变量的函数
///
/// 向指定的组添加一系列项
///
/// 指定组名
/// 完整的item名数组
/// 由服务器返回读写数据时需要使用的item号
/// 无错误,返回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; //客户项自动加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 ,在OnDataChange中会用到
ItemDefArray[i].dwBlobSize = 0; // blob size
ItemDefArray[i].pBlob = IntPtr.Zero; // pointer to blob
ItemDefArray[i].vtRequestedDataType = 4; //DWord数据类型
}
//初始化输出参数
IntPtr pResults = IntPtr.Zero;
IntPtr pErrors = IntPtr.Zero;
try
{
// 添加项到组
object grp=((groupStru)hashGroup[groupName]).groupObj;
((IOPCItemMgt)grp).AddItems(itemsName.Length,ItemDefArray,out pResults,out pErrors);
int[] errors = new int[itemsName.Length];
IntPtr pos = pResults;
Marshal.Copy(pErrors, errors, 0,itemsName.Length);
for(int i=0;i
{
if (errors[i] == 0)
{
OPCITEMRESULT result = (OPCITEMRESULT)Marshal.PtrToStructure(pos, typeof(OPCITEMRESULT));
itemsID[i] = result.hServer;
pos = new IntPtr(pos.ToInt32() + Marshal.SizeOf(typeof(OPCITEMRESULT)));
}
else
{
String pstrError;
pIOPCServer.GetErrorString(errors[0],0x407,out pstrError);
success=false;
break;
}
}
SetItenClient(groupName,itemsID,itemsID); //要求始终只有一个组被激活,才不会引起冲突。
}
catch (System.Exception err) // catch for error in adding items.
{
success=false;
//error="错误信息:"+error+err.Message;
}
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号:
8、 下面编写的是一个最重要的重载函数,当检测到当前活动组中的某个变量发生变化时,就会调用委托。
//数据变化时处理的问题
public virtual void OnDataChange ( Int32 dwTransid ,
Int32 hGroup ,
Int32 hrMasterquality ,
Int32 hrMastererror ,
Int32 dwCount ,
int[] phClientItems ,
object[] pvValues ,
short[] pwQualities ,
OpcRcw.Da.FILETIME[] pftTimeStamps ,
int[] pErrors )
{
dtChange(pvValues,phClientItems);
}
该函数的代码只有一句,即调用委托函数。
以上编写的是需要实现监控的最重要的方法,当然不完善,还有许多方法和重载函数可以编写,这里就不详细介绍。
9、 编写基本的测试程序,用于检测上面编写的异步类AsynServer
<1>、 重新创建一个工程,添加对上面编写的异步类的引用,并在类的开头部分添加变量声明:
//声明委托
private S7Connection.DataChange dt;
//声明服务器
S7Connection.AsynServer server;
*您的姓名:
*联系手机:
固话电话:
E-mail:
所在单位:
需求数量:
*咨询内容: