|
马上注册,精彩即将继续...
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
本帖最后由 forever 于 2017-9-6 10:55 编辑
最近碰到个项目需要配合仪表厂家对S7 200 PLC做上位机通讯软件的开发,由不是搞代码专业的,在网上搜了一堆的资料,总算也是可以把东西做出来了,抽空做了一个小的Demo,在这里也跟大家分享一点点经验,作为自己的总结,也以期能给后来人带来稍许启发。
首先,既然是基于RS485 Modbus RTU通讯协议的软件,我们肯定需要对它有一定的了解,很多人可能会去搜Modbus协议的标准文件,当然我也是,说实话这个文件实在是太长了,看完之后说实话对我的帮助也有限,在这里我推荐大家去百度文库里看一篇文章:《MODBUS规约与报文解析详细说明》,因为我没有下载券了,所以没法放在附件里了,里面很简洁、明了的介绍Modbus的内容以及相应的报文格式,这个报文格式对编写上位机软件是对我帮助最大的,大家把这个看一下应该比我做大篇幅的介绍要好的多,这里我就不说了,只把上位机读取PLC里V区变量(即保持型寄存器)的流程简单说一下。
我们通常的做法是把仪表测量的信号通过4-20mA传入PLC,再把相应的AIW传给我们分配的VW,上位机发送读取对应VW区的报文,下位机(从站,也就是我们的PLC)接收指令之后会给出响应,反回一条信息给上位机,然后上位机对相应的报文做解析。其他读取I区,Q区,写入V区的原理大概相同。
好了,了解Modbus报文格式以及相应的流程之后,我们需要做的就是与S7 200 PLC通讯了,以CPU224xp为例,它有两个RS485通讯口,分别为port0和port1,其中做主站port0,port1都行,做从站只能用port0,这里因为是通过上位机控制PLC,所以我们选择plc为从站就可以了,开发的时候用RS232/RS485的s7 200编程电缆把电脑与PLC连上就行了,硬件的连接很简单,接下来就是s7 200的编程了。不过在开始之后我还是建议大家去看一下S7 200关于Modbus通讯的官方文档介绍,百度搜 s7 200 Modbus关键字,第一条就是,可能大家看完之后我下面关于s7 200的编程就可以略过了。但是这里我还是做个简单的介绍。
第一步我们需要去下载一个S7 200的Modbus通讯库,因为Step7默认安装是没有这个库的,直接百度搜索吧,有很多链接可以下载,装完之后重新打开step7,在库里会出现相应的图标,展开Modbus Slave Port0,将MBUS-INIT和MBUS-SLAVE分别添加到程序中去,如下面三个图所示:
这里面对应每一个属性的意思大家在Step7中点击相应的栏目,按F1调出帮助文档,里面有详细的介绍,我也不啰嗦了。其他PLC的编程就只是把你模拟量AIW的值传到你想要放置的VW区了,最后记得做库存储区分配,在step7软件的 文件/库存储区菜单里。到这里为止,PLC上需要做的工作就结束了。(其他你们需要控制程序就由自己发挥吧。。。)
-------------------------------------------------------------------------------------------------------------------------------------------
接下来就是我们的重点,关于上位机的部分了, 我还是以VB6.0读取V区为例来说明,关于C#的实现方法,如果与VB不一样的地方,我也会做相应的说明,其他的大家可以下载附件VB6.0的源代码之后去看一下,形式基本上都是一样的。
工作模式我在这里再说一下:上位机发送相应的请求,下位机接收请求之后做出相应的反馈
在VB6.0里,我们与串口的通讯需要用到MSComm控件,在工程/部件菜单里找到Microsoft Comm Control 6.0添加一下就行了。
为了尽可能简单的让大家明白,我直接上代码了,首先我们要进行通讯,肯定要进行相应的连接,如下
MSComm1.CommPort = 1 ‘自己电脑的com口
MSComm1.Settings = "9600,n,8,1" ‘这个不多说了,一般人都能看得懂
MSComm1.InputMode = comInputModeBinary '二进制收发
MSComm1.InBufferSize = 1024 ’设置相应的缓冲区
MSComm1.OutBufferSize = 1024
If (Not MSComm1.PortOpen) Then MSComm1.PortOpen = True ‘打开串口
到这里,我们就可以与S7 200进行信息的传递了。接下来我们就发送读取V区的报文,(报文的格式在前面我已经提到了,请看《MODBUS规约与报文解析详细说明》里的介绍)如下:
Dim btSend(7) As Byte '定义一个用于存储发送报文的数组
btSend(0) = &H1 '目标站号,也就是从站PLC的站地址
btSend(1) = &H3 '功能码
btSend(2) = &H0 '&VW1000地址(0000)高字节
btSend(3) = &H0 '&VW1000地址(0000)低字节
btSend(4) = &H0 '读取个数高字节
btSend(5) = &H2 '读取个数低字节,2表示读取2个字,即&VW1000(&VB1000,&VB1001),&VW1002(&VB1002,&VB1003),返回4个字节,我在S7 200中的库存储区是从VW1000开始的。
Dim crc ‘关于CRC校验部分可以直接看我的源码,或者百度搜索一下,有很多
Dim btCRCHi As Byte, btCRCLo As Byte
crc = CalCRC16Fast(btSend, 6, btCRCLo, btCRCHi) ‘调用CRC校验
btSend(6) = btCRCHi 'CRC高字节
btSend(7) = btCRCLo 'CRC低字节
MSComm1.InBufferCount = 0
MSComm1.Output = btSend ‘发送报文
MSComm1.RThreshold = 9 ‘当接收缓冲区的数据字节数达到9时,会触发MSComm的OnComm()事件
这里我解释一下RThreshold为什么是9,因为btSend[0]到btSend[4]各占一个字节,即5个字节,btSend[5]返回4个字节
另外,MSComm的OnComm()事件是用来处理接收返回的报文的,双击添加到窗口的MSComm控件,进行相应的编程即可:
Dim btReceive() As Byte
Dim Buf As String
Dim crc
Dim btCRCLo As Byte, btCRCHi As Byte
Dim Data As Long
If btReceive(1) = &H3 Then '判断是否为读取V区功能
crc = CalCRC16Fast(btReceive, 9, btCRCLo, btCRCHi)
If btReceive(UBound(btReceive) - 1) = btCRCLo & btReceive(UBound(btReceive)) = btCRCHi Then ’判断CRC校验是否正确
For i = 3 To UBound(btReceive) - 2 Step 2 ‘报文处理
Data = btReceive(i) * 256 + btReceive(i + 1)
Buf = Buf + Str(Data) + Chr(32) + Chr(10)
Next i
txtReceiveV.Text = Trim(Buf) ‘用text文本控件显示获取的值
End If
End If
MSComm1.InBufferCount = 0 ’清空接收缓冲区
这一段好像没有什么能解释的了。
到这里差不多就结束了,更多的功能就由你自己去添加吧。
--------------------------------------------------------------------------------------------------------------
现在估计VB用得很少了,我再简单的说下C#的实现方法吧,其实掌握了原理,用什么语言来写都差不多。
C#的串口通讯需要用到serialPort控件,其用法跟VB的MSComm类似,设置完相应的参数之后直接调用open()方法就可以了,对应onCom事件是serialPort_DataReceived,也是当serialPort.ReceivedBytesThreshold达到设置值时触发,在其中调用serialPort.Read(btReceive, 0, btReceive.Length)方法就可以了,如果需要在界面做数据显示,则需要做到委托或者多线程,这个一下子就说不明白了,自己可以百度一下C#的serialPort控件,都有很详细的说明。
贴点示例代码,
数据的发送:
定义一个发送数据的方法,用一个timer控件或者一个循环调用这个方法,然后write(btSend, 0, 8);就行了。
private static byte[] SendMsg(int node, byte stat, int addr, int len)
{
byte[] btSend = new byte[8];
byte[] CRC = new byte[2];
btSend[0] = Convert.ToByte(node); //功能码
btSend[1] = stat; //目标站号
btSend[2] = (byte)(addr >> 8); //I0.0地址(0000)高字节,即高8位
btSend[3] = (byte)(addr & 0xFF); //I0.0地址(0000)低字节,即低8位
btSend[4] = (byte)(len >> 8); //读取个数高字节
btSend[5] = (byte)(len & 0xFF); //读取个数低字节
CRC = BitConverter.GetBytes(CRC16.crc16(btSend, 6)); //计算CRC校验码
btSend[6] = CRC[0];
btSend[7] = CRC[1];
return btSend;
}
//CRC校验类
class CRC16
{
public static uint crc16(byte[] modbusdata, uint Length)//Length为modbusdata的长度
{
uint i, j;
uint crc16 = 0xFFFF;
for (i = 0; i < Length; i++)
{
crc16 ^= modbusdata; // CRC = BYTE xor CRC
for (j = 0; j < 8; j++)
{
if ((crc16 & 0x01) == 1) //如果CRC最后一位为1􀁋右移一位后carry=1􀁋则将CRC右移一位后􀁋再与POLY16=0xA001进行xor运算
crc16 = (crc16 >> 1) ^ 0xA001;
else //如果CRC最后一位为0􀁋则只将CRC右移一位
crc16 = crc16 >> 1;
}
}
return crc16;
}
怎么样,是不是跟VB的差不多,上面都有注释了,我也不多费话了。
另外,版主大大,看在我码了这么多字的情况下,请允许我打个小广告,哈。。我是M&C技术工程师,在这里已经有5年了,对CEMS或者工业过程采样跟预处理了解还算可以,各位如果有采样及预处理方面的咨询,可以跟我们联系,我们会为您提供最合适的解决方案。
我的个人邮箱是290094363@qq.com
到这里,本贴就结束了,手工码字,希望各位多多支持。
vb modbus test 2(CRC校验-计算法).rar
(4.38 KB, 下载次数: 4)
|
|