none
VB2008 SerialPort中DataReceived事件的大量接收數據的應用 RRS feed

  • 問題

  • 請教各位大大,小弟之前有詢問過關於SerialPort中DataReceived的應用方式,目前遇到一個型號的PLC每次只能傳輸131個字元,當訊息過長時則訊息會停留在本身的BUFFER中,若回應碼長度為262個字元,則會分為2段字串以chr(13)做為間隔

    在小弟的理解中DataReceived事件是SerialPort元件送信時所產生的次執行緒,若要呼叫它須利用委派方式.
    這是小弟的語法
      Me.Invoke(New EventHandler(AddressOf SerialPort1_DataReceived))
    如此下的語法會出現異常中斷訊息如下:
    無法將型別 'System.EventArgs' 的物件轉換為型別 'System.IO.Ports.SerialDataReceivedEventArgs'。

    請教各位大大這個次執行緒的正確呼叫方式該如何利用

    新手上路
    2010年1月11日 上午 08:44

解答

  • 不然就用遞迴呼叫, 也就是當條件為收前半段時, 再度呼叫 SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)

    你只要這樣寫就會呼叫自己
    SerialPort1_DataReceived(sender , e)

    另外我注意到一件事, 你有使用 Handles SerialPort1.DataReceived 子句 , 我建議你不要用這種方式委派, 用AddHandler去委派事件函式就好, 不然你有Handles又有AddHandler很容易亂掉

    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    • 已標示為解答 eblue 2010年1月19日 上午 08:56
    2010年1月13日 上午 04:28
    版主

所有回覆

  • eblue:
       為什麼你會用Me.Invkoe ? 而不是用 AddHandler ?
       像這樣
       AddHandler myRS232.DataReceived, AddressOf my_DataReceived

     另外在MSDN中有提到,

    EventHandler 為預先定義的委派,表示事件的事件處理常式方法 (不論事件是否會產生事件資料)。如果事件不會產生事件資料,請以 EventArgs 替代泛型型別參數,否則,請提供您自己的自訂事件資料型別,並替代泛型型別參數。


    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    2010年1月11日 上午 08:59
    版主
  • HI~~BILL大大又麻煩你教我了!
    我一開始也是用這個
    AddHandler SerialPort1.DataReceived, AddressOf SerialPort1_DataReceived
    但是卻不會有任何動作

    這是我在收送信部分的語法
    送信: (這樣會產生一段262個字元的回應碼,PLC會將前131個字元的資料丟出,剩下的會在buffer中,)
         Dim SXDLOT3 As String
            Dim SXDLOT1 As String = ""
            Me.cunt_LOOP = 0
            Label2.Text = Now
                                SXDLOT3 = "@00" + "RD" + "0100" + "0060" 
                    SXDLOT3 = SXDLOT3 + fcs(SXDLOT3) + "*" + Chr(13)
                    SerialPort1.Write(SXDLOT3)
                    myResetEvent.WaitOne(100, False)
                    System.Threading.Thread.Sleep(100)
           Label3.Text = Now

    收信:
     Public Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            dim S1 As String
            Dim i As Integer = 0
            RemoveHandler SerialPort1.DataReceived, AddressOf SerialPort1_DataReceived
            Dim xx As Integer
            xx = SerialPort1.BytesToRead
            Try
                    While Microsoft.VisualBasic.Right(S1, 1) <> Chr(13)
                        S1 &= SerialPort1.ReadExisting
                    End While
            Catch ex As Exception
            Finally
                Application.DoEvents()
                AddHandler SerialPort1.DataReceived, AddressOf SerialPort1_DataReceived
                myResetEvent.Set()
            End Try
        End Sub
    所以當我要將被分割存在buffer區中的資料收回,需在觸發一次收信的程式

    測試觸發
     Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            AddHandler SerialPort1.DataReceived, AddressOf SerialPort1_DataReceived
      End Sub

    也許是我誤解大大的意思..這樣無法觸發收信的程序


    新手上路
    2010年1月11日 上午 09:32
  • 你應該在Form_load 或之前 (當然是在產生SerialPort1執行個體之後) 就要先呼叫    AddHandler SerialPort1.DataReceived, AddressOf SerialPort1_DataReceived 而不是寫在button2.click吧

    補充: 我有一個疑問, 你收完前半段不用發什麼訊息告訴PLC已經收完前半段了嗎 ?

    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    2010年1月11日 上午 10:21
    版主
  • bill大大!應該是小弟的說法造成您的誤解了,在送信前我已將AddHandler 這段語法宣告,然後再進入PC對PLC的收送信
    但以現在小弟所學的來看 送信程序會觸發收信程序! 但因PLC一次能丟出的資料有限所以必須分段將回應碼收齊
    所以目前小弟想做的是
    當我丟出信號後 會一直做收信的動作直到回應碼暫存區中的位元=0 才停止收碼動作
    我buttion1 中的第1行就是AddHandler這句語法+對PLC下達命令的指令(複製時未複製到)
    這時會觸發收碼的次執行緒..到這邊在執行上有還OK
    但是當資料大於PLC一次通信的字元量時,這時需在觸發一次收碼的信號,讓PLC將剩餘資料丟出
    所以目前小弟是卡再說..如何讓PLC再丟出資料來
    簡單來說目前PC對PLC之間是一問一答 變成一問N答(直到將PLC內資料全部清空為止)






    新手上路
    2010年1月11日 上午 11:55
  • 讓我先知道一件事, 收了前半段, PC有需要丟啥訊號給  PLC嗎 ?還是PLC送出前半段後, 接著就送出後半段 ?

    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    2010年1月11日 下午 12:19
    版主
  • 恩~PC只丟出一次訊號給PLC!PLC的動作就如同大大想的 送出前半段後就接這送出後半段!
    若不行只好在下達命令時限制一次所詢問的數量了!
    新手上路
    2010年1月12日 上午 01:41
  • 這樣你應該直接收完就好, 你可以設一個變數去記錄收到幾個  Chr(13), 當這個變數值 =2時則跳出接收的迴圈
    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    2010年1月12日 上午 06:41
    版主
  • 我也測過這種方式
    收碼語法如下:
                Dim x As Integer = 0
                Do
                    While Microsoft.VisualBasic.Right(S1, 1) <> Chr(13)
                        S1 &= SerialPort1.ReadExisting
                    End While
                        S2=S2+S1
                       ' S1="" 將S1清空再收 則無法跳出迴圈
                    x += 1
                Loop Until x = 2

    收碼狀態
    第一次通訊 PLC應回應 A字串 chr(13) B字串+"*"+chr(13)
    第一次收碼 得 A字串
    第二次通訊 PLC應回應 A字串 chr(13) B字串+"*"+chr(13)
    第二次收碼 得 B字串+"*"+
    目前來看 第2次的通訊才能把B字串收進來..但第2次通訊所應得的資料(A字串 chr(13) B字串+"*"+chr(13)
    )會在buffer中
    新手上路
    2010年1月13日 上午 03:23
  • 不然就用遞迴呼叫, 也就是當條件為收前半段時, 再度呼叫 SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)

    你只要這樣寫就會呼叫自己
    SerialPort1_DataReceived(sender , e)

    另外我注意到一件事, 你有使用 Handles SerialPort1.DataReceived 子句 , 我建議你不要用這種方式委派, 用AddHandler去委派事件函式就好, 不然你有Handles又有AddHandler很容易亂掉

    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    • 已標示為解答 eblue 2010年1月19日 上午 08:56
    2010年1月13日 上午 04:28
    版主
  • 感謝大大的提醒.這邊我會注意的
    關於收碼的語法變更如下

                Static x As Integer
                While Microsoft.VisualBasic.Right(S1, 1) <> Chr(13)
                    S1 &= SerialPort1.ReadExisting
                End While
                x += 1

               If x = 1 Then
                    While Microsoft.VisualBasic.Right(S2, 1) <> Chr(13)
                        S2 &= SerialPort1.ReadExisting   '會進入無窮迴圈,因為S2=""
                    End While
                    x += 1
                End If

                If x >= 2 Then
                    x = 0
                Else
                    SerialPort1_DataReceived(sender, e)
                End If

    如此測試看來..應該是要在觸發一個信號,讓PLC將資料丟出來,否則前段碼收完,再收第2次仍是前段碼的位置但已無資料..所以是空的


    新手上路
    2010年1月13日 上午 05:35
  • 有一個測試的方法, 先不要管條件要不要跳出來, 你一進Received時先把Handler remove, 然後用While 迴圈
    在迴圈中用 ReadByte去讀, 每讀一個Byte, 就用 MessageBox.Show把內容值給顯示出來 (最好在裡面也加上是第幾個Byte)
    試試它讀到哪後就不再讀取就知道PLC怎麼回應的了

    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    2010年1月13日 上午 05:46
    版主
  • 經測試結果
    PLC將A字串丟完就停止回應了!
    我也有去查詢其他論壇及資料
    這款OMRON的C200HX 僅支援C MODE 格式的通訊
    所以每次通訊最大的字元數為131個
    目前來看應該只能跟之前一樣一次讀取30個暫存區 分次讀取了
    新手上路
    2010年1月14日 上午 04:56