| 作者 | 主题 |
|---|---|
|
ILBB 游民 经验值:104 发帖数:37 精华帖:1 |
楼主
主题:VB做的MODBUS与仪表通讯,OPC与WINCC通讯
VB刚做的MODBUS与仪表通讯,OPC与WINCC通讯,已经成功,发上来与大家分享,希望斑竹不要删帖,(*^__^*) 嘻嘻…… QQ:413599191
Option Explicit '=================== OPC========================== Option Base 1 Dim WithEvents MyOPCServer As OPCServer Dim WithEvents MyOPCGroup As OPCGroup Private ClientHandles() As Long Private ServerHandles() As Long Private Errors() As Long Private SName As String '服务器名称 Private ItemIDs() As String Private SNode As String '计算机名或者网址 Private Item_num As Long Dim valuess() As Variant Dim sc As Integer Dim date1 As Variant Dim Tcommand(0 To 7) As Byte Dim address As Integer '地址 Dim CRC16Lo As Byte 'CRC16Lo为CRC寄存器低8位 Dim CRC16Hi As Byte 'CRC16Hi为CRC寄存器高8位 Dim value(0 To 500) As Byte Dim dd(0 To 500) As Single Dim num As Integer Dim start_add_H As Byte '起始地址 高 Dim start_add_L As Byte '起始地址 低 Dim data_num_H As Byte '数据长度 高 Dim data_num_l As Byte '数据长度 低 Dim pd_data(0 To 500) As Single Private Sub Form_Load() '窗体启动 Timer1.Enabled = False Timer2.Enabled = True sc = 1 If MSComm1.PortOpen = True Then MSComm1.PortOpen = False With MSComm1 .CommPort = 1 .InBufferSize = 1024 '开辟数据缓冲区 .Settings = "9600,n,8,1" .InputMode = comInputModeBinary '设定为二进制的数据流方式 End With If MSComm1.PortOpen = False Then MSComm1.PortOpen = True End Sub Private Sub Timer2_Timer() Dim I As Integer Dim j As Integer '===============变量个数================== Item_num = 72 '========================================= '==============定义WINCC变量名称=================== ReDim ItemIDs(Item_num) '建立WINCC内部变量名称 (d1_1,d1_2......d1_35),(d2_1,d2_2......d2_35) For I = 1 To 2 For j = 0 To 35 ItemIDs((I - 1) * 36 + j + 1) = "d" & I & "_" & j ' Next Next SNode = "" Call Connect("OPCServer.WinCC", SNode) Call Add_Group("Internal tags") Call Add_Items(ItemIDs(), Item_num) Timer2.Enabled = False Timer1.Enabled = True End Sub ' ====================采用MODBUS-RTU协议==================== ' ================仪表起始地址0100H,数据长度36个============ Private Sub Timer1_Timer() '向EX8仪表写报文 Dim I, K, j As Integer Dim SSS ReDim valuess(Item_num) As Variant Timer1.Enabled = False On Error GoTo ErrorHandler1 Select Case sc Case 1 address = Val("&h" + "01") '读一号地址参数 Case 2 address = Val("&h" + "02") '读二号地址参数 End Select start_add_H = Val("&h" + "01") '起始地址 高 start_add_L = Val("&h" + "00") '起始地址 低 data_num_H = Val("&h" + "00") '数据长度 高 data_num_l = Val("&h" + "24") '数据长度 低 Tcommand(0) = address '地址 Tcommand(1) = Val("&h" + "03") 'MODBUS 功能码 Tcommand(2) = start_add_H Tcommand(3) = start_add_L Tcommand(4) = data_num_H Tcommand(5) = data_num_l For I = 0 To 5 value(I) = Tcommand(I) Next I num = 6 Call CRC16 '调用CRC16校验子程序 Tcommand(6) = CRC16Lo 'CRC16低字节 Tcommand(7) = CRC16Hi 'CRC16高字节 MSComm1.Output = Tcommand '发送数据到EX8仪表 num = 2 * (data_num_H * 256 + data_num_l) + 5 '接收的数据个数 K = 0 Do SSS = DoEvents() '等待接收 K = K + 1 If K > 30000 Then For I = 0 To 76 value(I) = 0 Next GoTo 888 End If Loop Until (MSComm1.InBufferCount > num - 1) date1 = MSComm1.Input For I = 0 To num - 1 value(I) = date1(I) Next If value(0) <> address Then GoTo 999 '地址等否 If value(1) <> 3 Then GoTo 999 '功能码等否 num = num - 2 Call CRC16 If value(num + 1) <> CRC16Hi Then GoTo 999 'CRC 等否 If value(num) <> CRC16Lo Then GoTo 999 'CRC 等否 888 '====================数据处理==================== dd((address - 1) * 36 + 1) = F_FLOAT(value(3), value(4)) dd((address - 1) * 36 + 2) = U_FLOAT(value(5), value(6)) dd((address - 1) * 36 + 3) = U_FLOAT(value(7), value(8)) dd((address - 1) * 36 + 4) = U_FLOAT(value(9), value(10)) dd((address - 1) * 36 + 5) = U_FLOAT(value(11), value(12)) dd((address - 1) * 36 + 6) = U_FLOAT(value(13), value(14)) dd((address - 1) * 36 + 7) = U_FLOAT(value(15), value(16)) dd((address - 1) * 36 + 8) = U_FLOAT(value(17), value(18)) dd((address - 1) * 36 + 9) = U_FLOAT(value(19), value(20)) dd((address - 1) * 36 + 10) = I_FLOAT(value(21), value(22)) dd((address - 1) * 36 + 11) = I_FLOAT(value(23), value(24)) dd((address - 1) * 36 + 12) = I_FLOAT(value(25), value(26)) dd((address - 1) * 36 + 13) = I_FLOAT(value(27), value(28)) dd((address - 1) * 36 + 14) = I_FLOAT(value(29), value(30)) dd((address - 1) * 36 + 15) = PQS_FLOAT(value(31), value(32)) dd((address - 1) * 36 + 16) = PQS_FLOAT(value(33), value(34)) dd((address - 1) * 36 + 17) = PQS_FLOAT(value(35), value(36)) dd((address - 1) * 36 + 18) = DMD_FLOAT(value(37), value(38)) dd((address - 1) * 36 + 19) = PQS_FLOAT(value(39), value(40)) dd((address - 1) * 36 + 20) = PQS_FLOAT(value(41), value(42)) dd((address - 1) * 36 + 21) = PQS_FLOAT(value(43), value(44)) dd((address - 1) * 36 + 22) = DMD_FLOAT(value(45), value(46)) dd((address - 1) * 36 + 23) = PQS_FLOAT(value(47), value(48)) dd((address - 1) * 36 + 24) = PQS_FLOAT(value(49), value(50)) dd((address - 1) * 36 + 25) = PQS_FLOAT(value(51), value(52)) dd((address - 1) * 36 + 26) = DMD_FLOAT(value(53), value(54)) dd((address - 1) * 36 + 27) = PF_FLOAT(value(55), value(56)) dd((address - 1) * 36 + 28) = PF_FLOAT(value(57), value(58)) dd((address - 1) * 36 + 29) = PF_FLOAT(value(59), value(60)) dd((address - 1) * 36 + 30) = PF_FLOAT(value(61), value(62)) dd((address - 1) * 36 + 31) = UNBL_FLOAT(value(63), value(64)) dd((address - 1) * 36 + 32) = UNBL_FLOAT(value(65), value(66)) dd((address - 1) * 36 + 33) = (value(67) * 256 + value(68)) dd((address - 1) * 36 + 34) = DMD_FLOAT(value(69), value(70)) dd((address - 1) * 36 + 35) = DMD_FLOAT(value(71), value(72)) dd((address - 1) * 36 + 36) = DMD_FLOAT(value(73), value(74)) '显示数值到窗体 Text1.Text = Str(dd((address - 1) * 36 + 1)) Text2.Text = Str(dd((address - 1) * 36 + 2)) Text3.Text = Str(dd((address - 1) * 36 + 3)) Text4.Text = Str(dd((address - 1) * 36 + 4)) Text5.Text = Str(dd((address - 1) * 36 + 5)) Text6.Text = Str(dd((address - 1) * 36 + 6)) Text7.Text = Str(dd((address - 1) * 36 + 7)) Text8.Text = Str(dd((address - 1) * 36 + 8)) Text9.Text = Str(dd((address - 1) * 36 + 9)) Text10.Text = Str(dd((address - 1) * 36 + 10)) Text11.Text = Str(dd((address - 1) * 36 + 11)) Text12.Text = Str(dd((address - 1) * 36 + 12)) Text13.Text = Str(dd((address - 1) * 36 + 13)) Text14.Text = Str(dd((address - 1) * 36 + 14)) Text15.Text = Str(dd((address - 1) * 36 + 15)) Text16.Text = Str(dd((address - 1) * 36 + 16)) Text17.Text = Str(dd((address - 1) * 36 + 17)) Text18.Text = Str(dd((address - 1) * 36 + 18)) Text19.Text = Str(dd((address - 1) * 36 + 19)) Text20.Text = Str(dd((address - 1) * 36 + 20)) Text21.Text = Str(dd((address - 1) * 36 + 21)) Text22.Text = Str(dd((address - 1) * 36 + 22)) Text23.Text = Str(dd((address - 1) * 36 + 23)) Text24.Text = Str(dd((address - 1) * 36 + 24)) Text25.Text = Str(dd((address - 1) * 36 + 25)) Text26.Text = Str(dd((address - 1) * 36 + 26)) Text27.Text = Str(dd((address - 1) * 36 + 27)) Text28.Text = Str(dd((address - 1) * 36 + 28)) Text29.Text = Str(dd((address - 1) * 36 + 29)) Text30.Text = Str(dd((address - 1) * 36 + 30)) Text31.Text = Str(dd((address - 1) * 36 + 31)) Text32.Text = Str(dd((address - 1) * 36 + 32)) Text33.Text = Str(dd((address - 1) * 36 + 33)) Text34.Text = Str(dd((address - 1) * 36 + 34)) Text35.Text = Str(dd((address - 1) * 36 + 35)) Text36.Text = Str(dd((address - 1) * 36 + 36)) Text37.Text = sc 999 If sc = 2 Then For I = 1 To Item_num valuess(I) = Str(dd(I)) Next MyOPCGroup.SyncWrite Item_num, ServerHandles, valuess, Errors '同步写 End If ErrorHandler1: sc = sc + 1 If sc > 2 Then sc = 1 Timer1.Enabled = True End Sub Private Sub Form_Unload(Cancel As Integer) '断开OPC连接 On Error GoTo ErrorHandler3 Call Rem_Items(Item_num) Call Rem_Group("Internal tags") Call Disconnect ErrorHandler3: End Sub Sub Connect(ServerName, NodeName) '连接子函数 On Error GoTo ErrorHandler Set MyOPCServer = New OPCServer MyOPCServer.Connect ServerName, NodeName Exit Sub ErrorHandler: End Sub Sub Add_Group(Groupname) '添加组函数 On Error GoTo ErrorHandler MyOPCServer.OPCGroups.DefaultGroupUpdateRate = 0 Set MyOPCGroup = MyOPCServer.OPCGroups.Add(Groupname) MyOPCGroup.IsSubscribed = True MyOPCGroup.IsActive = True Exit Sub ErrorHandler: End Sub Sub Add_Items(ItemIDs() As String, Item_num As Long) '添加标签集合 Dim I As Long ReDim ClientHandles(Item_num) On Error GoTo ErrorHandler For I = 1 To Item_num ClientHandles(I) = I Next MyOPCGroup.IsSubscribed = False MyOPCGroup.OPCItems.AddItems Item_num, ItemIDs, ClientHandles, ServerHandles, Errors MyOPCGroup.IsSubscribed = True '允许订阅或者异步读取方式 Erase Errors() ' MsgBox "Add Item successful!" 'vbCritical Exit Sub ErrorHandler: 'MsgBox "Add Item Error!", vbCritical End Sub Sub Disconnect() 'MyOPCServer.Disconnect Set MyOPCServer = Nothing End Sub Sub Rem_Group(Groupname As String) '删除组对象 'MyOPCServer.OPCGroups.Remove Groupname Set MyOPCGroup = Nothing End Sub Sub Rem_Items(Item_num As Long) '删除标签集合对象 On Error GoTo ErrorHandler2 'MyOPCGroup.OPCItems.Remove Item_num, ServerHandles, Errors Erase ClientHandles() Erase ServerHandles() Erase Errors() ErrorHandler2: End Sub Public Sub CRC16() 'CRC16效验 Dim CL, CH, UseHi, UseLo As Byte Dim I, Index As Integer CRC16Lo = &HFF 'CRC16Lo为CRC寄存器低8位 CRC16Hi = &HFF 'CRC16Hi为CRC寄存器高8位 CL = &H1 CH = &HA0 'A001 H 是CRC-16多项式代码 For I = 0 To num - 1 CRC16Lo = CRC16Lo Xor value(I) '每一个数据与CRC寄存器异或 For Index = 0 To 7 UseHi = CRC16Hi UseLo = CRC16Lo CRC16Hi = CRC16Hi \ 2 CRC16Lo = CRC16Lo \ 2 '右移一位 If ((UseHi And &H1) = &H1) Then '如果高位字节最后一位是1的话 CRC16Lo = CRC16Lo Or &H80 '低位字节右移后前面补1 End If If ((UseLo And &H1) = &H1) Then '如果LSB 为1,则与多项式进行异或 CRC16Hi = CRC16Hi Xor CH CRC16Lo = CRC16Lo Xor CL End If Next Index Next I End Sub Function F_FLOAT(A_H As Byte, A_L As Byte) '频率 Dim E_H As Single Dim E_L As Single E_H = A_H E_L = A_L F_FLOAT = (E_H * 256 + E_L) / 100 End Function Function PF_FLOAT(A_H As Byte, A_L As Byte) '功率因数值PFA、PFB、PFC、PFS Dim E_H As Single Dim E_L As Single E_H = A_H E_L = A_L PF_FLOAT = (E_H * 256 + E_L) / 10000 End Function Function U_FLOAT(A_H As Byte, A_L As Byte) '电压值UA、UB、UC Dim E_H As Single Dim E_L As Single Dim E_DPT As Single E_H = A_H E_L = A_L U_FLOAT = ((E_H * 256 + E_L) / 10000) * 250 End Function Function I_FLOAT(A_H As Byte, A_L As Byte) '电流值IA、IB、IC Dim E_H As Single Dim E_L As Single E_H = A_H E_L = A_L I_FLOAT = ((E_H * 256 + E_L) / 10000) * 5 End Function Function PQS_FLOAT(A_H As Byte, A_L As Byte) ' Dim E_H As Single Dim E_L As Single E_H = A_H E_L = A_L PQS_FLOAT = (E_H * 256 + E_L) / 10000 * 250 * 5 End Function Function DMD_FLOAT(A_H As Byte, A_L As Byte) ' Dim E_H As Single Dim E_L As Single E_H = A_H E_L = A_L DMD_FLOAT = (E_H * 256 + E_L) / 10000 * 250 * 5 * 3 End Function Function UNBL_FLOAT(A_H As Byte, A_L As Byte) ' Dim E_H As Single Dim E_L As Single E_H = A_H E_L = A_L UNBL_FLOAT = (E_H * 256 + E_L) / 10000 End Function |