1.VB和PLC通讯RS232,如果需要实时监控读数据,需要使用Timer控件,那么如何处理写入数据最合适?
2.为什么在操作界面中菜单时,读写通讯会停止?Private Sub Timer1_Timer() Dim tmp As String
Dim ch As String
Dim A(4) As Double
Dim B(4) As DoubleCall WR_D(CommFX, 0, 0, "D", 0, 3, A, 16)'读16bit数据
Label3.Caption = A(1)
Label4.Caption = A(2)
Label5.Caption = A(3)'DoEvents If Set_Value = True Then
Call BW(CommFX, 0, 0, "M", 0, 8, Int(Text1.Text)) '写所有的M点
Set_Value = False
End If
If W_Value = True Then For J = 1 To 3
If an_set(J) = True Then
B(J) = Val(Text2(J).Text)
an_set(J) = False
End If
Next
Call WW_D(CommFX, 0, 0, "D", 0, 3, B, 16)'写16bit数据
W_Value = False
End IfX = BR(CommFX, 0, 0, "X", 0, 8) '读所有的X0-X7点
' DoEvents
Label1.Caption = X
For n = 0 To 7
ch = Mid(X, n + 1, 1)
Select Case n
Case 0
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 1
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 2
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 3
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 4
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 5
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 6
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 7
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
End Select
Next n
' DoEvents
Y = BR(CommFX, 0, 0, "Y", 0, 8) '读所有的Y0-Y7点
DoEvents
Label2.Caption = Y
For n = 0 To 7
ch = Mid(Y, n + 1, 1)
Select Case n
Case 0
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 1
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 2
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 3
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 4
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 5
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 6
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 7
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
End Select
Next n
End Sub
2.为什么在操作界面中菜单时,读写通讯会停止?Private Sub Timer1_Timer() Dim tmp As String
Dim ch As String
Dim A(4) As Double
Dim B(4) As DoubleCall WR_D(CommFX, 0, 0, "D", 0, 3, A, 16)'读16bit数据
Label3.Caption = A(1)
Label4.Caption = A(2)
Label5.Caption = A(3)'DoEvents If Set_Value = True Then
Call BW(CommFX, 0, 0, "M", 0, 8, Int(Text1.Text)) '写所有的M点
Set_Value = False
End If
If W_Value = True Then For J = 1 To 3
If an_set(J) = True Then
B(J) = Val(Text2(J).Text)
an_set(J) = False
End If
Next
Call WW_D(CommFX, 0, 0, "D", 0, 3, B, 16)'写16bit数据
W_Value = False
End IfX = BR(CommFX, 0, 0, "X", 0, 8) '读所有的X0-X7点
' DoEvents
Label1.Caption = X
For n = 0 To 7
ch = Mid(X, n + 1, 1)
Select Case n
Case 0
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 1
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 2
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 3
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 4
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 5
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 6
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
Case 7
If ch = "1" Then Shape1(n).BackColor = QBColor(12)
If ch = "0" Then Shape1(n).BackColor = QBColor(10)
End Select
Next n
' DoEvents
Y = BR(CommFX, 0, 0, "Y", 0, 8) '读所有的Y0-Y7点
DoEvents
Label2.Caption = Y
For n = 0 To 7
ch = Mid(Y, n + 1, 1)
Select Case n
Case 0
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 1
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 2
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 3
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 4
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 5
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 6
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
Case 7
If ch = "1" Then Shape2(n).BackColor = QBColor(12)
If ch = "0" Then Shape2(n).BackColor = QBColor(10)
End Select
Next n
End Sub
1)建议你将COM口接收PLC数据放MSCOMM控件的ONCOMM事件来完成.
2)请详细叙述通信协议.
'* 函数目的 : 得到一个由位软元件组成的二进制数据 (此二进制数从 "P_BitNo" 开始到 "P_BitNumber" 结束)
'* 参数意义 : ComPort - 用来与PLC通信的串口对象
'* : P_Station - PLC地址
'* : P_Delay - 0
'* : P_BitType - "X""Y""M"(大写的字符串)
'* : P_BitNo - 想要取得的,位软元件的起始地址
'* : P_BitNumber - 想要取得的,位软元件的个数
'* 函数返回 : BR = 返回一个string型的字符
'*收信息前有一段时间的Delay,此Delay不小于50Ms
Dim instring As String
Dim NumS As String
Dim GetAck As Boolean
ComPort.InBufferCount = 0
ComPort.OutBufferCount = 0
instring = ComPort.Input
instring = ""
NumS = BR_ENG(P_Station, P_Delay, P_BitType, P_BitNo, P_BitNumber)
ComPort.Output = NumS
TimeDelay 50
If ComPort.InBufferCount >= 8 + P_BitNumber Then '判断ComPort.InBufferCount >= 8 + P_BitNumber
GetAck = False
Do
instring = instring + ComPort.Input
If Len(instring) > 1 And InStr(1, instring, ACK) > 0 Then '判断接受确认返回字符ACK
'返回字符串处理
BR = Mid(instring, 6, P_BitNumber) GetAck = True
Exit Do
End If
Loop Until Len(instring) > 1 And InStr(1, instring, Nak) > 0 '判断接受错误返回字符Nak
If Not GetAck Then
MsgBox "未收到相应字符,确认失败!!", vbCritical + vbOKOnly, "系统信息"
Exit Function
End If
Else
ComPort.InBufferCount = 0
End If
End Function
Private Function BR_ENG(ByVal P_Station As Integer, ByVal P_Delay As Integer, ByVal P_BitType As String, ByVal P_BitNo As String, ByVal P_BitNumber As Integer) As String
'* 函数目的 : 根据参数组成一个命令,此命令使PLC返回一个从 "P_BitNo号" 开始到 "P_BitNumber" 结束二进制数
'* 参数意义 : P_Station - PLC地址
'* P_Delay - 0
'* P_BitType - "X""Y""M"(大写的字符串)
'* P_BitNo - 想要取得的,位软元件的起始地址
'* P_BitNumber - 想要取得的,位软元件的个数
'* 函数返回 : BR_ENG = 返回一个String型的命令串
'*本函数只用于BR
Dim vp_Station, vP_BitNumber, NumS As String
Dim vP_Bitlength As Integer
vp_Station = IIf(P_Station >= 0 And P_Station < 16, "0" + Hex$(P_Station), "00")
vp_Delay = Right("00" & Hex(P_Delay), 1)
vP_BitNumber = Right("00" & Hex(P_BitNumber), 2)
vP_Bitlength = Len(P_BitNo)
NumS = vp_Station & "FFBR" & vp_Delay & P_BitType & Right("00000" & Right(Str(P_BitNo), vP_Bitlength), 5 - Len(P_BitType)) & vP_BitNumber
BR_ENG = Chr(5) + NumS + SumChk(NumS)
End Function以上为读bit位信息功能块
Public Sub BW(ByRef ComPort As Object, ByVal P_Station As Integer, ByVal P_Delay As Integer, ByVal P_BitType As String, ByVal P_BitNo As Integer, ByVal P_BitNumber As Integer, ByVal P_Value As Double)
'* 函数目的 : 把"P_Value"的二进制数形式设置从 "P_BitNo" 开始到 "P_BitNumber" 结束的位软元件状态。
'* 参数意义 : ComPort - 用来与PLC通信的串口对象
'* P_Station - PLC地址
'* P_Delay - 0
'* P_BitType - "X""Y""M"(大写的字符串)
'* P_BitNo - 想要取得的,位软元件的起始地址
'* P_BitNumber - 想要取得的,位软元件的个数
'* P_Value - 十进制整数
'以Bit为单位,写入位元件的状态
Dim NumS As String
Dim instring As String
Dim GetAck As Boolean
ACK$ = Chr$(&H6)
Nak$ = Chr$(&H15)
ComPort.InBufferCount = 0
ComPort.OutBufferCount = 0
instring = ComPort.Input
instring = ""
NumS = BW_ENG(P_Station, P_Delay, P_BitType, P_BitNo, P_BitNumber, P_Value)
ComPort.Output = NumS
GetAck = False
Do
instring = instring + ComPort.Input
If Len(instring) > 1 And InStr(1, instring, ACK) > 0 Then '判断接受确认返回字符ACK
' TimeDelay 10
GetAck = True
Exit Do
End If
Loop Until Len(instring) > 1 And InStr(1, instring, Nak) > 0 '判断接受错误返回字符Nak
If Not GetAck Then
MsgBox "未收到相应字符,确认失败!!", vbCritical + vbOKOnly, "系统信息"
Exit Sub
End If
End Sub
Private Function BW_ENG(ByVal P_Station As Integer, ByVal P_Delay As Integer, ByVal P_BitType As String, ByVal P_BitNo As String, ByVal P_BitNumber As Integer, ByVal P_Value As Double) As String
'* 函数目的 : 根据参数组成一个命令,此命令使PLC设置从 "P_BitNo" 开始到 "P_BitNumber" 结束位软元件
'* 参数意义 : P_Station - PLC地址
'* P_Delay - 0
'* P_BitType - "X""Y""M"(大写的字符串)
'* P_BitNo - 想要取得的,位软元件的起始地址
'* P_BitNumber - 想要取得的,位软元件的个数
'* P_Value - 十进制整数
'* 函数返回 : BW_ENG = 返回一个String型的命令串
'*本函数只用于BW
Dim vp_Station, vP_Value, vP_BitNumber, NumS As String
Dim vP_Bitlength As Integer
vp_Station = IIf(P_Station >= 0 And P_Station < 16, "0" + Hex$(P_Station), "00")
vp_Delay = Right("00" & Hex(P_Delay), 1)
vP_BitNumber = Right("00" & Hex(P_BitNumber), 2)
vP_Bitlength = Len(P_BitNo)
NumS = vp_Station & "FFBW" & vp_Delay & P_BitType & Right("00000" & Right(Str(P_BitNo), vP_Bitlength), 5 - Len(P_BitType)) & vP_BitNumber & DecTo2(P_Value, P_BitNumber)
BW_ENG = Chr(5) & NumS & SumChk(NumS)
End Function以上为写bit位功能块
If ComErr = True Then
Lab_Comm.Caption = "通讯错误.无效端口.!"
Exit Sub
End If
Timer_RW.Enabled = True '打开定时通讯扫描
End SubPrivate Sub Timer_RW_Timer()
If ComErr = True Then
Lab_Comm.Caption = "通讯错误.无效端口.!"
Exit Sub
End If
If NotTimOut = True And TimOut = False Then
CommFX.RThreshold = 5 '设定产生OnComm事件的接收缓冲区字符数
Select Case WriteData
Case "寄存器"
Case "写", "置位", "复位", "停止", "运行"
End Select
Else
TimOut = True
If k = 0 Then ' 实时监控通讯循环,每次K+1来判断应该发送第几次命令
Call BR(CommFX, 0, 0, "X", 0, 8) '读所有的X0-X7点
ElseIf k = 1 Then
Call BR(CommFX, 0, 0, "Y", 0, 8) '读所有的Y0-Y7点
End If
End If
Timer_RW.Enabled = False
Timer_Com.Enabled = True
End Sub
Private Sub CommFX_OnComm()
Dim GetData As String
Dim Data As String
Dim i As Integer
If CommFX.CommEvent = comEvReceive Then
Timer_Com.Enabled = False
GetData = CommFX.Input
Lab_Comm.Caption = "通讯正常.!"
If NotTimOut = True And TimOut = False Then
NotTimOut = False
Timer_RW = True
Else
Data = Mid(GetData, 6, 8)
For i = 1 To 8
If Mid(Data, i, 1) = 1 Then
If k = 0 Then
Shape1(i - 1).BackColor = &HFF&
Else
Shape2(i - 1).BackColor = &HFF&
k = -1
End If
Else
If k = 0 Then
Shape1(i - 1).BackColor = &HC0C0C0
Else
Shape2(i - 1).BackColor = &HC0C0C0
k = -1
End If
End If
Next i
k = k + 1
TimOut = False '实时监控通讯处理完毕
Timer_RW.Enabled = True
End If
End If
End Sub
改为OnComm处理数据后,在点界面菜单时是好多了,但是点击窗体,在弹出 MsgBox "******"信息时,发送和接受灯会停止,郁闷?不知是什么原因?请高手指教!!
'* 函数目的 : 得到一个由位软元件组成的二进制数据 (此二进制数从 "P_BitNo" 开始到 "P_BitNumber" 结束)
'* 参数意义 : ComPort - 用来与PLC通信的串口对象
'* : P_Station - PLC地址
'* : P_Delay - 0
'* : P_BitType - "X""Y""M"(大写的字符串)
'* : P_BitNo - 想要取得的,位软元件的起始地址
'* : P_BitNumber - 想要取得的,位软元件的个数
Dim instring As String
Dim NumS As String
Dim GetAck As Boolean
ComPort.InBufferCount = 0
ComPort.OutBufferCount = 0
ComPort.RThreshold = 8 + P_BitNumber
instring = ""
NumS = BR_ENG(P_Station, P_Delay, P_BitType, P_BitNo, P_BitNumber)
ComPort.Output = NumS
End Function
Private Function BR_ENG(ByVal P_Station As Integer, ByVal P_Delay As Integer, ByVal P_BitType As String, ByVal P_BitNo As String, ByVal P_BitNumber As Integer) As String
'* 函数目的 : 根据参数组成一个命令,此命令使PLC返回一个从 "P_BitNo号" 开始到 "P_BitNumber" 结束二进制数
'* 参数意义 : P_Station - PLC地址
'* P_Delay - 0
'* P_BitType - "X""Y""M"(大写的字符串)
'* P_BitNo - 想要取得的,位软元件的起始地址
'* P_BitNumber - 想要取得的,位软元件的个数
'* 函数返回 : BR_ENG = 返回一个String型的命令串
'*本函数只用于BR
Dim vp_Station, vP_BitNumber, NumS As String
Dim vP_Bitlength As Integer
vp_Station = IIf(P_Station >= 0 And P_Station < 16, "0" + Hex$(P_Station), "00")
vp_Delay = Right("00" & Hex(P_Delay), 1)
vP_BitNumber = Right("00" & Hex(P_BitNumber), 2)
vP_Bitlength = Len(P_BitNo)
NumS = vp_Station & "FFBR" & vp_Delay & P_BitType & Right("00000" & Right(Str(P_BitNo), vP_Bitlength), 5 - Len(P_BitType)) & vP_BitNumber
BR_ENG = Chr(5) + NumS + SumChk(NumS)
End Function
比如PLC会提供一个DDE通讯程序,这个DDE通讯程序会包含了RS232数据包和控制字的翻译.
PC上只需要和这个DDE程序通讯就可以控制PLC了.
很多组态软件也是从底层上封装了串口通讯协议,再翻译成控制字来和PC程序打交道的.
如果你的工程不需要使用MDI窗体,那么直接在工程属性里把工程类型改成"ActiveX EXE",TIMER控件就能不受影响了.....弹个MSGBOX也卡不住的.记得要一个可发布的类,以及一个Sub Main,工程的"部件"属性要改为"独立方式",入口要设置为Sub Main.....
你可以将你程序中的DoEvents,这样可以大大的减缓你的程序“卡”的情况。