回复:【MODBUS】跑在以太网上的MODBUS

SIEMENS-XP

  • 帖子

    254
  • 精华

    3
  • 被关注

    32

论坛等级:侠士

注册时间:2011-09-19

普通 普通 如何晋级?

发布于 2015-04-15 10:54:35

30楼

展开查看
以下是引用奔波工控人在2015-04-14 08:53:38的发言 >26楼:我是自己用VB写的采集驱动,然后在WINCC建立内部变量(内部变量不算点),采集驱动采集到数据后,通过HMIruntime库函数写wincc的内部变量(我的大致有1万多个点,其实只需要买最低点数的wincc即可)

那阵子我观察了下,一般这种和上位机的通讯都需要在电脑上建立虚拟串口,但是建立虚拟串口太多,我的需要建208个虚拟串口,力控软件根本就支持不了这么多的串口设备。通过观察,我发现电脑跟串口跟服务器的通讯使用的依然是TCP的报文,我截取了报文看了,只是把串口的查询字符串和返回数据的字符串给封装了。

我自己尝试着用vb 使用winsock控件写了一下,发现是可以的,这样我的程序放到任何一个电脑上就可以直接使用,不需要建立虚拟串口了。用vb写的话,要使用它默认的端口号 961~968。是TCP报文 不是modbus-TCP,我用VB写比较方便,获得报文自己分析就可以了。

其实这么多表通讯,用网关是最直接的,由于种种原因,没办法。
代码大部分跟modbusrtu的代码差不多,附点部分代码吧,真要做完善还是要花时间的,我花了好多天的时间了,现在基本上正常用了。

Dim outputLen As Integer ' 发送数据长度
Dim outData As String ' 发送数据暂存
Dim SendArr() As Byte ' 发送数组
Dim TemporarySave As String ' 数据暂存
Dim dataCount As Integer ' 数据个数计数
Dim i As Integer ' 局部变量


outData = UCase(Replace(TxtSend, Space(1), Space(0))) ' 先去掉空格,再转换为大写字母
outData = UCase(outData) ' 转换成大写
outputLen = Len(outData) ' 数据长度
For i = 0 To outputLen - 1
TemporarySave = Mid(outData, i + 1, 1) ' 取一位数据
If (Asc(TemporarySave) >= 48 And Asc(TemporarySave) <= 57) Or (Asc(TemporarySave) >= 65 And Asc(TemporarySave) <= 70) Then
dataCount = dataCount + 1
Else
Exit For
Exit Sub
End If
Next i

If dataCount Mod 2 <> 0 Then ' 判断十六进制数据是否为双数
dataCount = dataCount - 1 ' 不是双数,则减1
End If

outData = Left(outData, dataCount) ' 取出有效的十六进制数据

ReDim SendArr(dataCount / 2 - 1) ' 重新定义数组长度
For i = 0 To dataCount / 2 - 1
SendArr(i) = Val("&H" + Mid(outData, i * 2 + 1, 2)) ' 取出数据转换成十六进制并放入数组中
Next


Main.WinsockClient(Index).SendData SendArr() ' 发送数据


SlaveNow(Index) = SlaveNow(Index) + 1 '从站依次轮询
If SlaveNow(Index) > SlaveNum(Index) Then
SlaveNow(Index) = 1
End If


==============================================================================

Private Sub WinsockClient_DataArrival(Index As Integer, ByVal bytesTotal As Long)


On Error Resume Next
Dim strData() As Byte


WinsockClient(Index).GetData strData()




'若接收的数据总长度 和 数据长度加上地址吗功能码以及校验码之和 不相等 说明接收到的数据不正确 就可以丢弃了
If (bytesTotal < 10) Then
DataOK(Index) = True
DataSendCounter(Index) = 0
Exit Sub
End If

GoodData(Index) = ""
For i = 0 To bytesTotal - 1
If strData(i) < 16 Then
GoodData(Index) = GoodData(Index) & "0" & Hex(strData(i))
Else
GoodData(Index) = GoodData(Index) & Hex(strData(i))
End If
Next i



'************************************************************************
'************************CRC16校验***************************************
Dim CRC_A As String
Dim CRC_B As String
Dim Txt1 As String
Dim Txt2 As String
Dim H1, H2 As String

Txt1 = UCase(Replace(GoodData(Index), Space(1), Space(0)))
Txt2 = Mid(Txt1, 1, Len(Txt1) - 4)

H1 = Mid(Txt1, Len(Txt1) - 3, 2)
H2 = Mid(Txt1, Len(Txt1) - 1, 2)
Call CRC_16(Txt2, CRC_A, CRC_B)
If (H1 <> CRC_A) Or (H2 <> CRC_B) Then
DataOK(Index) = True
DataSendCounter(Index) = 0

End If
'************************CRC16校验***************************************
'************************************************************************


'现在开始判断仪表类型
'bytesTotal=105 ---SCK600B多功能电表(电流电压电能等)
'bytesTotal=13 or 14 ---安科瑞的电表 或者是电操的状态返回信号
'bytetotal= 21 ----斯菲尔电能表
'bytesTotal >= 40 And <= 56 ------SCK600B多功能电表 或者 SCK600A火灾报警
'bytesTotal >=109 ------PF3000电表处理
Dim CongZhanNumber As Integer
Dim DuanKou As Integer
Dim IP As Integer

Dim ShuJuA As Integer
Dim ShuJuB As Integer
Dim ShuJuC As Integer
Dim ShuJuD As Integer
Dim F(30) As Single
Dim B(4) As Byte



'///////获取表数据的公共部分//////////////////////////////////////////
CongZhanNumber = CLng("&H" & Mid(GoodData(Index), 1, 2))
DuanKou = WinSockPort(Index) - 960
IP = CInt(Right(WinSockHostName(Index), 3))
'///////获取表数据的公共部分//////////////////////////////////////////



'///////SCK600B 多功能电表处理//////////////////////////////////////////
If (bytesTotal = 105) Then

'基本的过程是:先找出从站编号,数据处理需要根据电表的数据格式来组合,然后分别找出12个电表数据,
For i = 1 To 21
ShuJuA = CLng("&H" & Mid(GoodData(Index), i * 7 + (i - 1), 2))
ShuJuB = CLng("&H" & Mid(GoodData(Index), i * 7 + (i - 1) + 2, 2))
ShuJuC = CLng("&H" & Mid(GoodData(Index), i * 7 + (i - 1) + 4, 2))
ShuJuD = CLng("&H" & Mid(GoodData(Index), i * 7 + (i - 1) + 6, 2))
B(0) = ShuJuA
B(1) = ShuJuB
B(2) = ShuJuC
B(3) = ShuJuD
' 根据实际情况 进行选择, 1234 4321 2143 3412
CopyMemory ByVal (VarPtr(F(i)) + 0), B(3), 1
CopyMemory ByVal (VarPtr(F(i)) + 1), B(2), 1
CopyMemory ByVal (VarPtr(F(i)) + 2), B(1), 1
CopyMemory ByVal (VarPtr(F(i)) + 3), B(0), 1
Next i

Ua(Index, DuanKou, CongZhanNumber) = F(1)
Ub(Index, DuanKou, CongZhanNumber) = F(2)
Uc(Index, DuanKou, CongZhanNumber) = F(3)
Ia(Index, DuanKou, CongZhanNumber) = F(7)
Ib(Index, DuanKou, CongZhanNumber) = F(8)
Ic(Index, DuanKou, CongZhanNumber) = F(9)
P(Index, DuanKou, CongZhanNumber) = F(13)
Q(Index, DuanKou, CongZhanNumber) = F(17)
PF(Index, DuanKou, CongZhanNumber) = F(19)
EP(Index, DuanKou, CongZhanNumber) = F(21)


End If
'//////////////////////SCK600B 多功能电表处理//////////////
..........................................



还有就是,我这光安科瑞的电能表就有800多块了,分布在50多层大楼里面,电表的地址都是缺省的,需要一个个的去改地址,但是电表本身没有任何按键,只能通过modscan等软件一个个的改,而且拿着笔记本一个个的楼层跑,麻烦死了,我跑了几层,实在受不了了(要接线,还要笔记本的电池有电),就让人把每个楼层的表的地址按照顺序记下来,自己写了一个软件,在电脑上搜索单条总线的从站,搜到后按照他们记得地址顺序改成自己需要的地址,很方便很快捷,以下是软件界面:(直接点击搜索到的从站,输入你想要的地址就可以直接成功修改)




以下是引用SIEMENS-XP在2015-04-12 23:16:50的发言 >24楼:你这样就是自己要写...

引用24楼详细内容:

你这样就是自己要写脚本,我那天测试了用MOXA5610连接一块MODBUS电测表,该表直接用PLC和MODSCAN都可以采集数据。WINCC只支持MODBUS-RTU,无论我把串口设置为服务器,客户端,或者UDP模式。。WINCC都不能和该表通讯。 好像这个串口服务器是透明转换,只把数据透明转发,并没有转换成MODBUS-TCP协议,请斑竹赐教。

以下是引用奔波工控人在2015-04-11 17:55:43的发言 >23楼:我这现场2000多块电...

引用23楼详细内容:

我这现场2000多块电力仪表,全部是modbusrtu通信,当时选用的是力控软件和串口服务器,供配置了20多台8口的串口服务器,前面没太仔细考虑,问了下力控的技术,说没问题的。结果真正干活的时候发现根本没法用!再咨询,需要换成网关,还啥啥啥的,怎么可能啊,前期的投入要白费吗?

后来改成:用vb自己写驱动(kep的报价挺贵),采用tcp宝文的方式,省去了配置虚礼串口的麻烦,驱动读到数据后,直接发给wincc的内部变量,反正最小点数的wincc跟力控的无限点差不多价格,画面用wincc做,报警,曲线等很方便

谢谢朋友指点,我研究下,其实用网关比较省事啊 哈
相互学习 共同进步
评论
编辑推荐: 关闭

请填写推广理由:

本版热门话题

谈天说地

共有13243条技术帖

相关推荐

热门标签

相关帖子推荐

guzhang

恭喜,你发布的帖子

评为精华帖!

快扫描右侧二维码晒一晒吧!

再发帖或跟帖交流2条,就能晋升VIP啦!开启更多专属权限!

  • 分享

  • 只看
    楼主

top
您收到0封站内信:
×
×
信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。