上位机软件开发培训
基于RS485 Modbus RTU的上位机通讯软件实现
最近碰到个项目需要配合仪表厂家对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-SLA VE分别添加到程序中去,如下面三个图所示:
上海鉴昔仪器仪表有限公司
J&X Instrument (Shanghai) Co., Ltd
这里面对应每一个属性的意思大家在Step7中点击相应的栏目,按F1调出帮助文档,里面有详细的介绍,我也不啰嗦了。其他PLC的编程就只是把你模拟量AIW 的值传到你想要放置的VW区了,最后记得做库存储区分配,在step7软件的文件/库存储区菜单里。到这里为止,PLC上需要做的工作就结束了。(其他你们需要控制程序就由自己发挥吧。。。)-------------------------------------------------------------------------------------------------------------------------------------------
接下来就是我们的重点,关于上位机的部分了,我还是以VB6.0读取V区为例来说明,关于C#的实现方法,如果与VB不一样的地方,我也会做相应的说明,其他的大家可以下载附件VB6.0的源代码之后去看一下,形式基本上都是一样的。
工作模式我在这里再说一下:上位机发送相应的请求,下位机接收请求之后做出相应的反馈
在VB6.0里,我们与串口的通讯需要用到MSComm控件,在工程/部件菜单里到上海鉴昔仪器仪表有限公司
J&X Instrument (Shanghai) Co., Ltd
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校验
上海鉴昔仪器仪表有限公司
J&X Instrument (Shanghai) Co., Ltd
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文本控件显示获取的值
上海鉴昔仪器仪表有限公司
J&X Instrument (Shanghai) Co., Ltd
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位
上海鉴昔仪器仪表有限公司
J&X Instrument (Shanghai) Co., Ltd

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。