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

解决方案 »

  1.   

    LZ:
    1)建议你将COM口接收PLC数据放MSCOMM控件的ONCOMM事件来完成.
    2)请详细叙述通信协议.
      

  2.   

    Public Function BR(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) As String
        '*  函数目的  :  得到一个由位软元件组成的二进制数据 (此二进制数从 "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位功能块
      

  3.   

    Private Sub Timer_Com_Timer()
        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 "******"信息时,发送和接受灯会停止,郁闷?不知是什么原因?请高手指教!!
      

  4.   

    Public Function BR(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)
        '*  函数目的  :  得到一个由位软元件组成的二进制数据 (此二进制数从 "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
      

  5.   

    LZ:把你那些MsgBox注释,用标签作消息提示。因为MsgBox会中断进程。
      

  6.   

    我看别人都做成.DLL文件,在程序中调用是不是要好一点???
      

  7.   

    发现窗口菜单在点击弹出窗口时也会影响TIMER触发????
      

  8.   

    根据我的经验,一般PC和PLC通讯都是可以通过PLC提供的通讯程序来进行.
    比如PLC会提供一个DDE通讯程序,这个DDE通讯程序会包含了RS232数据包和控制字的翻译.
    PC上只需要和这个DDE程序通讯就可以控制PLC了.
    很多组态软件也是从底层上封装了串口通讯协议,再翻译成控制字来和PC程序打交道的.
      

  9.   


    如果你的工程不需要使用MDI窗体,那么直接在工程属性里把工程类型改成"ActiveX EXE",TIMER控件就能不受影响了.....弹个MSGBOX也卡不住的.记得要一个可发布的类,以及一个Sub Main,工程的"部件"属性要改为"独立方式",入口要设置为Sub Main.....
      

  10.   

    卡住可能是MSGBOX引起的,建议你不要用这个函数,提示信息可以用别的方式来。
    你可以将你程序中的DoEvents,这样可以大大的减缓你的程序“卡”的情况。
      

  11.   

    单线程可以使用doevents 但也不太好。因为你用doevents的时候 cpu会适用100% 最后在doevents 后面加上 一个slepp 或者 等待线程完成的东西。楼上说的 ActiveX EXE 这个应该也不难吧,可以实现简单的多线程通讯.http://www.vbplc.com 我看到过这个博客上面写过这方面的。祝好运