tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルVB2005で、シリアル通信について
記事No8887
投稿日: 2009/04/27(Mon) 13:43
投稿者AMI
お世話になっております。
現在PCとFA機器との通信をRS232Cで行おうと思っております。

(FA機器には、コマンドがありたとえばPCから「DATE?」と
送信すると自動的に「2008/04/26」
といった形にレスポンスがきます)

そこで現在、下記コードを記載し、PCからFA機器に対して、
シリアル通信を行おうとしております。
232Cのラインモニタもつなげているので、データの送受信の流れは見えております。
VB側から「DATE?」と送信はできました。
しかし、その答えの「「2008/04/26」を受信することが出来ません。
ラインモニタ上では、そのレスポンスは帰ってきております。

受信イベントが下記の処理だとおもうのですが、
まったくはしりません。

*****************************
'--------------------------------------------------------------------------------
    'データ受信イベント
    '--------------------------------------------------------------------------------
    Private Sub _com_DataReceived(ByVal sender As Object, _
                                  ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
                                  Handles _com.DataReceived

        Dim addmsg As New AddMessageDelegate(AddressOf AddMessage)
        Dim strDataReceived As String

        'Select Case e.EventType
        '    Case SerialData.Chars
        '    Case SerialData.Eof
        'End Select

        Try
            strDataReceived = _com.ReadLine
        Catch ex As Exception
            strDataReceived = ex.Message
        End Try
        txtMessage.Invoke(addmsg, New Object() {"[RCV]" + strDataReceived})

        'txtMessage.Invoke(addmsg, New Object() {"[RCV]" + SerialData.Chars})

    End Sub
******************************



VB2005を使用
下記が現在使用しているコードです。

Imports System.IO.Ports
Imports System.Threading

Public Class Form1

    Private WithEvents _com As New System.IO.Ports.SerialPort

    Delegate Sub AddMessageDelegate(ByVal str As String)

    '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    'テキストボックスにメッセージを表示する
    '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Private Sub AddMessage(ByVal str As String)
        txtMessage.Text = DateTime.Now.ToString("HH:mm:ss") + " " + _
                          str + ControlChars.CrLf + _
                          txtMessage.Text
    End Sub

    '--------------------------------------------------------------------------------
    'データ受信イベント
    '--------------------------------------------------------------------------------
    Private Sub _com_DataReceived(ByVal sender As Object, _
                                  ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
                                  Handles _com.DataReceived

        Dim addmsg As New AddMessageDelegate(AddressOf AddMessage)
        Dim strDataReceived As String

        'Select Case e.EventType
        '    Case SerialData.Chars
        '    Case SerialData.Eof
        'End Select

        Try
            strDataReceived = _com.ReadLine
        Catch ex As Exception
            strDataReceived = ex.Message
        End Try
        txtMessage.Invoke(addmsg, New Object() {"[RCV]" + strDataReceived})

        'txtMessage.Invoke(addmsg, New Object() {"[RCV]" + SerialData.Chars})

    End Sub

    '--------------------------------------------------------------------------------
    'エラー受信イベント
    '--------------------------------------------------------------------------------
    Private Sub _com_ErrorReceived(ByVal sender As Object, _
                                   ByVal e As System.IO.Ports.SerialErrorReceivedEventArgs) _
                                   Handles _com.ErrorReceived

        Dim addmsg As New AddMessageDelegate(AddressOf AddMessage)
        Dim strErrorMessage As String = "ErrorReceived"

        Select Case e.EventType
            Case SerialError.Frame
                strErrorMessage = "The hardware detected a framing error."
            Case SerialError.Overrun
                strErrorMessage = "A character-buffer overrun has occurred. The next character is lost."
            Case SerialError.RXOver
                strErrorMessage = "An input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the end-of-file (EOF) character."
            Case SerialError.RXParity
                strErrorMessage = "The hardware detected a parity error."
            Case SerialError.TXFull
                strErrorMessage = "The application tried to transmit a character, but the output buffer was full."
        End Select
        txtMessage.Invoke(addmsg, New Object() {"[ERR]" + strErrorMessage})

    End Sub

    '--------------------------------------------------------------------------------
    'Pin変更イベント
    '--------------------------------------------------------------------------------
    Private Sub _com_PinChanged(ByVal sender As Object, _
                                ByVal e As System.IO.Ports.SerialPinChangedEventArgs) _
                                Handles _com.PinChanged

        Dim addmsg As New AddMessageDelegate(AddressOf AddMessage)
        Dim strPinMessage As String = "PinChanged"
        Select Case e.EventType
            Case SerialPinChange.Break
                strPinMessage = "A break was detected on input."
            Case SerialPinChange.CDChanged
                strPinMessage = "The Receive Line Signal Detect (RLSD) signal changed state."
            Case SerialPinChange.CtsChanged
                strPinMessage = "The Clear to Send (CTS) signal changed state."
            Case SerialPinChange.DsrChanged
                strPinMessage = "The Data Set Ready (DSR) signal changed state."
            Case SerialPinChange.Ring
                strPinMessage = "A ring indicator was detected."
        End Select
        txtMessage.Invoke(addmsg, New Object() {"[PIN]" + strPinMessage})

    End Sub

    '--------------------------------------------------------------------------------
    '終了イベント
    '--------------------------------------------------------------------------------
    Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed

        ''ポートがオープンされている場合閉じる
        If (_com.IsOpen = True) Then
            Call _com.Close()
        End If

    End Sub

    '--------------------------------------------------------------------------------
    'フォームロード
    '--------------------------------------------------------------------------------
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ''ポート
        With cmbPortName.Items
            .Clear()
            .Add("COM1")
            .Add("COM2")
            .Add("COM3")
            .Add("COM4")
            .Add("COM5")
            .Add("COM6")
        End With
        cmbPortName.Text = "COM1"
        ''速度
        With cmbBaudRate.Items
            .Clear()
            .Add("2400")
            .Add("4800")
            .Add("9600")
            .Add("19200")
            .Add("38400")
            .Add("57600")
            .Add("115200")
        End With
        cmbBaudRate.Text = "9600"
        ''パリティ
        With cmbParity.Items
            .Add("なし")     '0:Parity.None
            .Add("奇数")     '1:Parity.Odd
            .Add("偶数")     '2:Parity.Even
            .Add("マーク")   '3:Parity.Mark
            .Add("スペース") '4:Parity.Space
        End With
        cmbParity.Text = "なし"
        ''データ長
        With cmbDataBits.Items
            .Add("4")
            .Add("5")
            .Add("6")
            .Add("7")
            .Add("8")
        End With
        cmbDataBits.Text = "8"
        ''ストップビット
        With cmbStopBits.Items
            .Add("なし")    '0:StopBits.None
            .Add("1")       '1:StopBits.One
            .Add("2")       '2:StopBits.Two
            .Add("1.5")     '3:StopBits.OnePointFive
        End With
        cmbStopBits.Text = "1"
        ''受信バッファサイズ
        txtReadBufferSize.Text = "1024"
        ''送信バッファサイズ
        txtWriteBufferSize.Text = "512"
        ''パリティエラー時の置換文字
        txtParityReplace.Text = "?"
        ''Null文字を破棄
        chkDiscardNull.Checked = False
        ''RTSラインを有効
        chkRtsEnable.Checked = False
        ''DTRラインを有効
        chkDtrEnable.Checked = True

        ''コントロール制御
        btnComClose.Enabled = False
        pnlBody.Enabled = False

    End Sub

    '--------------------------------------------------------------------------------
    '「接続」ボタンクリック
    '--------------------------------------------------------------------------------
    Private Sub btnComOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnComOpen.Click

        Try
            With _com
                ''プロパティセット
                .PortName = cmbPortName.Text
                .BaudRate = CInt(cmbBaudRate.Text)
                .Parity = CType(cmbParity.SelectedIndex, Parity)
                .DataBits = CInt(cmbDataBits.Text)
                .StopBits = CType(cmbStopBits.SelectedIndex, StopBits)
                .ReadBufferSize = CInt(txtReadBufferSize.Text)
                .WriteBufferSize = CInt(txtWriteBufferSize.Text)
                .ParityReplace = System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(txtParityReplace.Text)(0)
                .DiscardNull = chkDiscardNull.Checked
                .RtsEnable = chkRtsEnable.Checked
                .DtrEnable = chkDtrEnable.Checked
                ''既にオープンされていないか?
                If (.IsOpen = True) Then
                    MessageBox.Show(.PortName & "は既にオープンされています。", "エラー", _
                                    MessageBoxButtons.OK, MessageBoxIcon.Error)
                    Exit Sub
                End If
                ''ポートオープン
                Call .Open()
                Call AddMessage(" --- " + .PortName + "オープン")
                '****************************************************************************
                Dim strSend As String               'NewLine格納用文字列変数

                strSend = .NewLine 'NewLineを取得
                strSend = strSend.Replace(vbLf, vbCr)       '文字中のLFをCRに置換する場合

                SerialPort1.NewLine = strSend                   '置換したデリミタをNewLineに格納
                '****************************************************************************
                Dim aa As String
                aa = .NewLine
                .NewLine = aa
                '.NewLine = "LFCR"
                '.NewLine = "LF"
                aa = .NewLine
                '.ReceivedBytesThreshold = 1
            End With

            ''コントロール制御
            btnComOpen.Enabled = False
            btnComClose.Enabled = True
            tabComInfo.Enabled = False
            pnlBody.Enabled = True

            'Catch exInvalidOperation As System.InvalidOperationException
            'Catch exArgumentOutOfRange As System.ArgumentOutOfRangeException
            'Catch exArgument As System.ArgumentException
            'Catch exIO As System.IO.IOException
            'Catch exUnauthorizedAccess As System.UnauthorizedAccessException
        Catch ex As Exception

            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)

        End Try

    End Sub

    '--------------------------------------------------------------------------------
    '「切断」ボタンクリック
    '--------------------------------------------------------------------------------
    Private Sub btnComClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnComClose.Click

        ''ポートがオープンされている場合閉じる
        If (_com.IsOpen = True) Then
            Call _com.Close()
            Call AddMessage(" --- " + _com.PortName + "クローズ")
        End If

        ''コントロール制御
        btnComOpen.Enabled = True
        btnComClose.Enabled = False
        tabComInfo.Enabled = True
        pnlBody.Enabled = False

    End Sub

    '--------------------------------------------------------------------------------
    '「文字列送信」ボタンクリック
    '--------------------------------------------------------------------------------
    Private Sub btnSendData_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles btnSendData.Click

        If (txtSendData.Text.Length = 0) Then
            MessageBox.Show("送信文字列を入力してください", "エラー", _
                            MessageBoxButtons.OK, MessageBoxIcon.Error)
            txtSendData.Focus()
            Exit Sub
        End If

        Try
            _com.WriteLine(txtSendData.Text)
            Call AddMessage("[SND]" + txtSendData.Text)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

    End Sub

    '--------------------------------------------------------------------------------
    '「終了」ボタンクリック
    '--------------------------------------------------------------------------------
    Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExit.Click

        Me.Close()

    End Sub
End Class

[ツリー表示へ]
タイトルRe: VB2005で、シリアル通信について
記事No8888
投稿日: 2009/04/27(Mon) 15:00
投稿者オショウ
長々とコード掲載されても、実際に機器の要求仕様が解らないので
コメントのしようがありません。

また不必要な設定をされているところもあるので、これではどこを
どう修正するか指摘のしようもありません。

まず不必要なコードを全て省き、シンプルなものとして実験してみ
ることを勧めます。

デリミタが何であるかで、
           strDataReceived = _com.ReadLine
このような記述にはならないかと。

また、
.ParityReplace = System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(txtParityReplace.Text)(0)
                .DiscardNull = chkDiscardNull.Checked
この部分も勘違いされていると思いますが・・・

※ 機器は何ですか?
  私のFA屋で20年以上やってますので・・・

以上。

[ツリー表示へ]
タイトルRe^2: VB2005で、シリアル通信について
記事No8889
投稿日: 2009/04/27(Mon) 16:29
投稿者AMI
早速のお返事ありがとうございます。
機器はオムロンのPLCになります。
上位リンクコマンドで通信をさせようと考えております。
一回、オショウ 様の指摘した部分を見直してみます。

[ツリー表示へ]
タイトルRe^3: VB2005で、シリアル通信について
記事No8890
投稿日: 2009/04/27(Mon) 17:58
投稿者オショウ
> 機器はオムロンのPLCになります。
> 上位リンクコマンドで通信をさせようと考えております。
> 一回、オショウ 様の指摘した部分を見直してみます。

  オムロンのPLCでしたら、数年前にVB2005で作成した通信クラス
  を保有しています。FINSコマンド体系です。

  シリアル通信設定は、そう差異が無いと思いますが・・・

            devPort = New Ports.SerialPort

            AddHandler devPort.DataReceived, AddressOf OnDataReceived

            CPU_NO = CpuNo

            devPort.BaudRate = Baudrate
            devPort.DataBits = Databit
            devPort.Parity = Paritybit
            devPort.StopBits = Stopbit
            devPort.WriteTimeout = Ports.SerialPort.InfiniteTimeout
            devPort.ReadTimeout = Ports.SerialPort.InfiniteTimeout
            devPort.PortName = "COM" + Port.ToString.Trim
            devPort.Handshake = Ports.Handshake.None
            devPort.ReadBufferSize = 512

            devPort.Open()

            devPort.DiscardInBuffer()
            devPort.DiscardOutBuffer()

            devPort.DtrEnable = True
            devPort.RtsEnable = True

  その時のシリアルポートをオープンする際の設定コードです。

※ 通信タイムウアトは、自分のクラス内で別途やってます。

  デリミタは、&h0D ですので・・・

    Public Sub OnDataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs)

        Dim dev As SerialPort
        Dim bRet As Boolean
        Dim sz As String

        dev = DirectCast(sender, SerialPort)

        If e.EventType = SerialData.Chars Then
            Try
                sz = dev.ReadTo(VbCr)
            Catch ex As Exception
                sz = String.Empty
            End Try
            If sz <> String.Empty Then
                bRet = ConvertData(sz, dt)
                If bRet Then
                    If RecvTimeout IsNot Nothing Then
                        RecvTimeout.Dispose()
                        RecvTimeout = Nothing
                    End If

                    RaiseEvent ReceiveData(dt)

                    If ReceiveDone IsNot Nothing Then
                        ReceiveDone.Set()
                    End If
                End If
            End If
        End If

    End Sub

  実際のプログラムからの抜粋で、不必要な部分を抜いてますので
  このままでは正常に動作しません。
  適宜修正変更して下さい。

※ PLC通信クラスにしていますので、その受信イベントの中から
  受信データを元プログラムに戻す為にRaiseEvent使ってます。

※ RecvTimeoutは、通信タイムアウトを通信クラス内で別途定義し
  使っているものです。

  宣言は以下・・・
    Private RecvTimeout As Threading.Timer
    Private ReceiveDone As ManualResetEvent

以上。(あくまで)参考まで・・・

[ツリー表示へ]
タイトルRe^4: VB2005で、シリアル通信について
記事No8893
投稿日: 2009/04/28(Tue) 08:16
投稿者AMI
早速のお返事ありがとうございました。
昨日オショウさんのコードを参考に作り変えてみたところ、
うまく受信することができました。
やっと第一歩が踏み出せそうです。
また、今から作り出すので、またよろしくお願いします。

[ツリー表示へ]
タイトルRe^5: VB2005で、シリアル通信について
記事No8896
投稿日: 2009/04/28(Tue) 10:05
投稿者AMI
現在、送信ボタンを設けて、送信時には、下記コマンドを発行して、
受信まで、いくのですが、連続して、送信したい場合、
'*********************************************************
       Try
            '送信コマンド発行
            _com.WriteLine(txtSendData.Text)
            Call AddMessage("[SND]" + txtSendData.Text)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
'*********************************************************

何回も下記のように処理していますが、おそらく、一つの送信に対しての受信が
あるとおもうのですが、これはどのように取得すればいいのでしょうか?
下記のように処理をすると、不定期に受信イベントが発生して、
どの送信の受信なのかが区別がつきません。

'*********************************************************
   '--------------------------------------------------------------------------------
    '「文字列送信」ボタンクリック
    '--------------------------------------------------------------------------------
    Private Sub btnSendData_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles btnSendData.Click

       Try
            '送信コマンド発行
            _com.WriteLine(txtSendData.Text)
            Call AddMessage("[SND]" + txtSendData.Text)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        Try
            '送信コマンド発行
            _com.WriteLine(txtSendData.Text)
            Call AddMessage("[SND]" + txtSendData.Text)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try


        Try
            '送信コマンド発行
            _com.WriteLine(txtSendData.Text)
            Call AddMessage("[SND]" + txtSendData.Text)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub
'*********************************************************



ちなみに下記がデータ受信処理になります。

'*********************************************************

    '--------------------------------------------------------------------------------
    'データ受信イベント
    '--------------------------------------------------------------------------------
    Private Sub _com_DataReceived(ByVal sender As Object, _
                                  ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
                                  Handles _com.DataReceived

        Dim addmsg As New AddMessageDelegate(AddressOf AddMessage)

        Dim sz As String


        If e.EventType = SerialData.Chars Then
            Try
                sz = Trim(_com.ReadTo(vbCr))
            Catch ex As Exception
                sz = String.Empty
            End Try

    End Sub
'*********************************************************

[ツリー表示へ]
タイトルRe^6: VB2005で、シリアル通信について
記事No8897
投稿日: 2009/04/28(Tue) 11:51
投稿者オショウ
> 現在、送信ボタンを設けて、送信時には、下記コマンドを発行して、
> 受信まで、いくのですが、連続して、送信したい場合、

  一度の送信に対し、レスポンスを受信してから次の送信に
  移行しないと、このように連続した場合、以前の送信され
  た処理が完了しない間に次のコマンドをPLCが受信して
  しまい、エラーレスポンスが出てしまうことになります。

  非同期的処理の場合、ManualResetEventかAutoResetEvent
  クラスを使って、待ち合わせを行わないといけないかと。

  で、このクラスの生成で、最大待ち時間設定をすることに
  になりますので、実質的な受信タイムアウト処理が行える
  ことになります。

以上。

[ツリー表示へ]
タイトルRe^7: VB2005で、シリアル通信について
記事No8898
投稿日: 2009/04/28(Tue) 17:37
投稿者AMI
お返事ありがとうございます。
早速アドバイスどおり、「ManualResetEvent」の
処理を調べて、下記のように実装したところ、
送信・受信を交互に繰り返すようになりました。

そこで、もう一つ問題がでてきて、
「e.EventType」
で、受信処理の成否をみているのですが、
連続的に処理していて、ある処理回数以上になると、
「SerialError.Overrun」
が出て、受信できなくなってしまいます。
おそらくエラーメッセージからして、受信バッファーの
設定値以上のデータがきてるので、エラーを吐き出しているとおもうのですが、
これの回避方法はあるのでしょうか?
例:受信バッファがいっぱいになりそうになると、シリアル送信処理をやめて、
受信バッファの処理に走る等

以上の件よろしくお願いお願いします。



   Private Sub Serial_Send(ByVal Str_Send As String)

        '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++非同期用処理
        Call Main()
        '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        Try
            '送信コマンド発行
            '_com.WriteLine(txtSendData.Text)
            'Call AddMessage("[SND]" + txtSendData.Text)
            _com.WriteLine(Str_Send)
            Call AddMessage("[SND]" + Str_Send)

        Catch ex As Exception
            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++非同期用処理
        Call MyMethod()
        '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    End Sub


    Public Shared Sub Main()

        '非シグナル状態でManualResetEventオブジェクトを作成
        manualEvent = New ManualResetEvent(False)

        'スレッドを作成し、開始する
        Dim t1 As New Thread(New ThreadStart(AddressOf MyMethod))
        t1.Name = "1"
        t1.Start()

        'シグナル状態になるまでスレッドをブロックする
        manualEvent.WaitOne()

        Console.WriteLine("メインスレッド終了")

        Console.ReadLine()
    End Sub
    Public Shared Sub MyMethod()
        Console.WriteLine("{0}:スレッド開始", Thread.CurrentThread.Name)

        '何か仕事をするものとする
        Thread.Sleep(1000)

        'シグナル状態にする
        manualEvent.Set()

        Console.WriteLine("{0}:スレッド終了", Thread.CurrentThread.Name)
    End Sub

[ツリー表示へ]
タイトルRe^8: VB2005で、シリアル通信について
記事No8899
投稿日: 2009/04/28(Tue) 21:21
投稿者オショウ
> そこで、もう一つ問題がでてきて、
> 「e.EventType」
> で、受信処理の成否をみているのですが、
> 連続的に処理していて、ある処理回数以上になると、
> 「SerialError.Overrun」
> が出て、受信できなくなってしまいます。

  AddMessageした直後に
    bRet = manualEvent.WaitOne(1000, False)
    とかして、受信完了待ちするんですが・・・

  当然、受信イベントの方では、受信した直後に
  manualEvent.Set
    として、WaitOneしている部分の待ちを解除しま
  す。

  受信が無い場合、1000ミリ秒のタイムアウトを
  設定していますので、bRet の真偽を判断して、
  次処理を行うか、タイムアウト処理を行うか分
  岐します。

以上。

[ツリー表示へ]
タイトルRe^9: VB2005で、シリアル通信について
記事No8900
投稿日: 2009/04/30(Thu) 09:22
投稿者AMI
>
>   AddMessageした直後に
>     bRet = manualEvent.WaitOne(1000, False)
>     とかして、受信完了待ちするんですが・・・
>
>   当然、受信イベントの方では、受信した直後に
>   manualEvent.Set
>     として、WaitOneしている部分の待ちを解除しま
>   す。
>
>   受信が無い場合、1000ミリ秒のタイムアウトを
>   設定していますので、bRet の真偽を判断して、
>   次処理を行うか、タイムアウト処理を行うか分
>   岐します。

早速のお返事ありがとうございます。
現在下記のようにコマンドボタンを押したときに、
2回送信を行い、受信を「sz」に受信しております。
そこで「SD_AAA?」を送信して、それを「Label1」に表示
次に、「SD_BBB?」を送信して、それを「Label2」に表示
としたいのですが、一回目受信した後に、
        Call Serial_Send("SD_BBB?")
        Label2.Text = sz
上記処理をしているのですが、送信して、受信待ちしてないみたいで、
        Label2.Text = sz
を通過した後に、受信処理が走って、szが更新されます。
(現状では、一回目のszの値がそのまま保持されていて、Label1・Label2ともに
同じ値です)
現状のコードを記載します。

'***********************************************************************
'コマンドクリック処理
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Call Serial_Send("SD_AAA?")
        Label1.Text = sz

        Call Serial_Send("SD_BBB?")
        Label2.Text = sz

    End Sub
'***********************************************************************

'***********************************************************************
'送信処理
    Private Sub Serial_Send(ByVal Str_Send As String)

        Try
            '送信コマンド発行
            _com.WriteLine(Str_Send)
            Call AddMessage("[SND]" + Str_Send)


            Dim bret As Boolean
            '非シグナル状態でManualResetEventオブジェクトを作成
            manualEvent = New ManualResetEvent(False)

            'スレッドを作成し、開始する
            Dim t1 As New Thread(New ThreadStart(AddressOf MyMethod))
            t1.Name = "1"
            t1.Start()

            'シグナル状態になるまでスレッドをブロックする
            'manualEvent.WaitOne()
            bret = manualEvent.WaitOne(1000, False)
            If bret = True Then

            End If

        Catch ex As Exception
            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try


    End Sub
'***********************************************************************

'***********************************************************************
'データ受信処理
    Private Sub _com_DataReceived(ByVal sender As Object, _
                                  ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
                                  Handles _com.DataReceived

        Dim addmsg As New AddMessageDelegate(AddressOf AddMessage)

        If e.EventType = SerialData.Chars Then
            Try
                sz = Trim(_com.ReadTo(vbCr))
            Catch ex As Exception
                sz = String.Empty
            End Try

            manualEvent.Set()

            'DataReceivedイベント(受信イベント)ハンドラはセカンダリスレッド(2次スレッド)から呼び出されます。即ち、受信イベント処理は2次スレッドで行われます。
            'そのため Windows.Forms の UI 要素(コントロール)にアクセスする場合は Control.Invoke() メソッドを使用する必要があります。
            txtMessage.Invoke(addmsg, New Object() {"[RCV]" + sz})

        End If
    End Sub
'***********************************************************************

[ツリー表示へ]
タイトルRe^10: VB2005で、シリアル通信について
記事No8901
投稿日: 2009/04/30(Thu) 12:16
投稿者オショウ
> '送信処理
>     Private Sub Serial_Send(ByVal Str_Send As String)
>
>         Try
>             '送信コマンド発行
>             _com.WriteLine(Str_Send)
>             Call AddMessage("[SND]" + Str_Send)
>
>
>             Dim bret As Boolean
>             '非シグナル状態でManualResetEventオブジェクトを作成
>             manualEvent = New ManualResetEvent(False)

● このタイミングでmanualEventを生成しても遅い・・・

             Dim bret As Boolean
             '非シグナル状態でManualResetEventオブジェクトを作成
             manualEvent = New ManualResetEvent(False)

             '送信コマンド発行
             _com.WriteLine(Str_Send)
             Call AddMessage("[SND]" + Str_Send)

  とすべき・・・

>             'スレッドを作成し、開始する
>             Dim t1 As New Thread(New ThreadStart(AddressOf MyMethod))
>             t1.Name = "1"
>             t1.Start()

● このスレッド処理が何をしているか解りませんが、非常に重い処理を
  行う可能性があるならば、シリアル通信の受信モレを起こす可能性が
  あるので、シリアル送受信の最中に別負荷を発生するようなコーディ
  ングは好ましくありません。

  最近はCPUが高機能化していますので、難なく受信できますが基本
  送受信最中には行わないのがFA的にはベスト!

以上。

[ツリー表示へ]
タイトルRe^11: VB2005で、シリアル通信について
記事No8902
投稿日: 2009/04/30(Thu) 13:22
投稿者AMI
アドバイスを元に下記のように変更しました。
オブジェクト生成を「WriteLine」の前で行うようにして、
動かした所、
一回目の
            bret = manualEvent.WaitOne(1000, False)
の比較では、「true」が帰ってきているのですが、
二回目の送信時では、「false」が帰ってきており、
(ラインモニタ上では、レスポンスは返ってきているのは確認しました)
パソコン側がうまく受信していないものと思い、
強引にGOTOで、「TRUE」になるまで、連続して再送処理をしたのですが、
何回しても「false」になり、無限ループ状態になってしまいました。
うまく受信するポイントがあるのでしょうか?


'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
コマンドクリック
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Call Serial_Send("SD_AAA?")
        Label1.Text = sz

        Call Serial_Send("SD_BBB?")
        Label2.Text = sz


    End Sub
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
送信処理
    Private Sub Serial_Send(ByVal Str_Send As String)

        Try
            Dim bret As Boolean
            '非シグナル状態でManualResetEventオブジェクトを作成
            manualEvent = New ManualResetEvent(False)

eee:
            _com.WriteLine(Str_Send)
            Call AddMessage("[SND]" + Str_Send)


            bret = manualEvent.WaitOne(1000, False)

            If bret = True Then
                'bret = manualEvent.Reset
            Else
                GoTo eee
            End If

        Catch ex As Exception
            MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

    End Sub
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
受信処理

    Private Sub _com_DataReceived(ByVal sender As Object, _
                                  ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
                                  Handles _com.DataReceived

        Dim addmsg As New AddMessageDelegate(AddressOf AddMessage)

        'Dim dev As SerialPort


        If e.EventType = SerialData.Chars Then
            Try
                sz = Trim(_com.ReadTo(vbCr))
            Catch ex As Exception
                sz = String.Empty
            End Try

            manualEvent.Set()

            'DataReceivedイベント(受信イベント)ハンドラはセカンダリスレッド(2次スレッド)から呼び出されます。即ち、受信イベント処理は2次スレッドで行われます。
            'そのため Windows.Forms の UI 要素(コントロール)にアクセスする場合は Control.Invoke() メソッドを使用する必要があります。

            txtMessage.Invoke(addmsg, New Object() {"[RCV]" + sz})


        End If

    End Sub
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

> > '送信処理
> >     Private Sub Serial_Send(ByVal Str_Send As String)
> >
> >         Try
> >             '送信コマンド発行
> >             _com.WriteLine(Str_Send)
> >             Call AddMessage("[SND]" + Str_Send)
> >
> >
> >             Dim bret As Boolean
> >             '非シグナル状態でManualResetEventオブジェクトを作成
> >             manualEvent = New ManualResetEvent(False)
>

[ツリー表示へ]
タイトルRe^12: VB2005で、シリアル通信について
記事No8903
投稿日: 2009/04/30(Thu) 13:37
投稿者オショウ
もう少し厳密に書いた方がよかったですネ!・・・

まず、manualEvent の生成は、Form_Load とかで先にやっておきます。

次に、Serial_SendのAddMessage直前で、manualEvent.Reset()します。

要は、
1. Resetして
2. WaitOne(1000,False) で待って
3. 受信部分で、Setして
4. WaitOneを抜ける

を、ぐるぐる繰り返すことになります。
Form_Closingとかで、manualEventを後処理すればよいかと。

※ シリアリの非同期通信で、送受信の同期処理ができれば・・・
  タイムアウトしてもキビキビ動くようにするなら1000msを150〜250ms
  程度まで短縮してもよいかと。

以上。

[ツリー表示へ]
タイトルRe^13: VB2005で、シリアル通信について
記事No8904
投稿日: 2009/04/30(Thu) 14:15
投稿者AMI
> もう少し厳密に書いた方がよかったですネ!・・・
>
> まず、manualEvent の生成は、Form_Load とかで先にやっておきます。
>
> 次に、Serial_SendのAddMessage直前で、manualEvent.Reset()します。
>
> 要は、
> 1. Resetして
> 2. WaitOne(1000,False) で待って
> 3. 受信部分で、Setして
> 4. WaitOneを抜ける
早速のお返事ありがとうございます。

上記内容を考慮して、Loadイベントに「manualEvent」の生成を行い、
AddMessage直前で、manualEvent.Reset()処理を行いましたが、
やはり結果は一緒でした。

結局
「Button1_Click」イベントが終わった後に、
「_com_DataReceived」イベントが発生して、
データを受信してしまいます。
その受信イベントにはきちんと、2回目の受信データも格納されていますが、
思い通りの処理にはなりません。
原因がなかなかつかめていない状況です。

[ツリー表示へ]
タイトルRe^14: VB2005で、シリアル通信について
記事No8905
投稿日: 2009/04/30(Thu) 15:12
投稿者AMI
現状報告をさせていただきます。
受信処理の「_com_DataReceived」
の中で、下記処理をおこなっているのですが、
(受信メッセージを確認するために)

txtMessage.Invoke(addmsg, New Object() {"[RCV]" + sz})
これをコメントにして、なおかつ、デバッグモード(F9でデバッグしながらコードをおっていました)
ではなくて、通常のモードで走らせたら、正常に受信しました。

なにかすごい不安です。
根本的になにかちがうのでしょうか?

[ツリー表示へ]
タイトルRe^15: VB2005で、シリアル通信について
記事No8906
投稿日: 2009/04/30(Thu) 16:22
投稿者オショウ
> txtMessage.Invoke(addmsg, New Object() {"[RCV]" + sz})
> これをコメントにして、なおかつ、デバッグモード(F9でデバッグしながらコードをおっていました)
> ではなくて、通常のモードで走らせたら、正常に受信しました。

  それが最大の問題でしたネ!

  例えデバッグモードででも、キーボードからのステップ実行なら
  イベントの発生順序が変化しますので、こういうケースの場合、
  IDEの統合環境ででも送受信の最中では、ステップ実行で止め
  た場合、思い通り動作にはならないことがあります。

  ブレークポイントを設定する場所も、デバッグの内容によっては
  選びますので、送受信の切れ目に設定するとか・・・

  送受信の途中に設定したい場合、正常にルーチンを抜けない場合
  も当然あります。

  お気をつけ下さい。

※ デバイスとの通信デバッグは、一般的なステップ実行の方法では
  うまく動作しません。慣れるしかないかと・・・

● 私がやったFA関係で最大のデバイス数とのマルチスレッド的な動作
  では・・・

  GP−IBボード×2枚(各々6台のデバイス接続)
  RS-232C×2枚(4ポート・2ポート+本体1=7ポート)
  DIO×2枚(32/32と16/16)

  ボードはインターフェース社のもので本体PCIと拡張BOX使って
  ます。

  これらをほぼ同時的に通信させて制御・計測しています。
  それでいて、Pentium4 2.4GHz メモリ512MB ですが、CPU負荷は、
  最高で20%ぐらい・・・

  なんとかなるもんです。

  がんばってください!

以上。

[ツリー表示へ]