tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルVB2010 シリアル受信通信 byte で上手くいかない
記事No11868
投稿日: 2017/08/05(Sat) 14:11
投稿者MSAKA
No11856でご指導いただいた続きです

前回は送信が旨く行かないのをバイナリーにしては如何かと提案を頂き 
送信側はすんなり解決しました  その気になって受信側を始めたのですが
難航 あれこれ調べても問題は解決する知識は無いようで万歳状態です

以下のようなコードです (Windous7 64Bit VB2010)
(元コードは 金澤ソフト設計 が提供している sample0008)

受信イベントを受けて表示する部分を加工しています 

   Private Sub RcvDataToTextBox(data As String)
        Dim LenX As Integer
        Dim I As Integer
        Dim DD As String
        LenX = Len(data)
        Dim s(LenX) As String

        DD = ""
        Dim bytes() As Byte = System.Text.Encoding.GetEncoding(932).GetBytes(data)
        For I = 1 To LenX
            s(I) = BitConverter.ToString(bytes)
            DD = DD & s(I)
        Next
        RcvTextBox.AppendText(DD)
    End Sub

無線機に FEFE66000600FD を変換したものをPortに書き込みます

そうすると以下のように返ってきます( ”−”らしきものは勝手につくらしい)

3F-66-063F-66-063F-66-063F-74-3F3F-74-3F3F-74-3F

これは期待している値ではないので改めて
SerialDebuggerFree.exe なる通信試験ソフトで確認すると
(同時に表示されるtimeなど省略します Recv:以降が通信内容)
0001 IDとTime Recv:FEFE 6600 06
0002 IDとTime Recv:00FD FEFE 0066  
0003 IDとTime Recv:FBFD 
と表示されます (細切れになるのは他のEventの為?)

この16進部分が無線機に返されます 
FEFE 6600 06 00FD までががPCから送った内容(無線機もそれに対応した動きをします)
それ以降 FEFE 0066 FBFD が成功を意味しているようです
(無線機からPCへの送信なので 66 と 00 が逆になっています)

SerialDebuggerFreeと同じ返信を期待してあれこれ調べて試みたのですが
力不足で及ばず勉強やり直しです

どこが誤っているのでしょうか   よろしくご指導ください

[ツリー表示へ]
タイトルRe: VB2010 シリアル受信通信 byte で上手くいかない
記事No11870
投稿日: 2017/08/07(Mon) 07:28
投稿者shu
>    Private Sub RcvDataToTextBox(data As String)
dataをstringで渡していますが受信データは文字列ではないのではないですか?

>         Dim LenX As Integer
>         Dim I As Integer
>         Dim DD As String
>         LenX = Len(data)
>         Dim s(LenX) As String
>
>         DD = ""
>         Dim bytes() As Byte = System.Text.Encoding.GetEncoding(932).GetBytes(data)



>         For I = 1 To LenX
>             s(I) = BitConverter.ToString(bytes)
>             DD = DD & s(I)
>         Next
BitConverter.ToString(Byte())の結果は
各要素を16進にしてハイフンで区切った文字列なので
このループは同じ文字列を文字列長だけ連結することになるかと
思います。
hhttps://msdn.microsoft.com/ja-jp/library/3a733s97(v=vs.110).aspx


>         RcvTextBox.AppendText(DD)
>     End Sub
>
> 無線機に FEFE66000600FD を変換したものをPortに書き込みます
>
> そうすると以下のように返ってきます( ”−”らしきものは勝手につくらしい)
>
> 3F-66-063F-66-063F-66-063F-74-3F3F-74-3F3F-74-3F
なのでこれは
{3F,66,06}
{3F,74,3F}
という2つのバイト列が取得出来ていることになります。ただShift-Jis文字列から
バイト列に変換しているのでデータが欠落している可能性があります。

[ツリー表示へ]
タイトルRe^2: VB2010 シリアル受信通信 byte で上手くいかない
記事No11874
投稿日: 2017/08/07(Mon) 19:40
投稿者MSAKA
shu さん 早々ありがとうございます 苦戦していますのでよろしくお願いします

OS Windows 7 64Bit 

> >    Private Sub RcvDataToTextBox(data As String)
> dataをstringで渡していますが受信データは文字列ではないのではないですか?
>>>そのとおりですが問題ありますか

BitConverter.ToString(Byte())の結果は
> 各要素を16進にしてハイフンで区切った文字列なので
> このループは同じ文字列を文字列長だけ連結することになるかと
> 思います。
> hhttps://msdn.microsoft.com/ja-jp/library/3a733s97(v=vs.110).aspx
>>>そのとおりですね 無駄なことをやていました
>
> > 3F-66-063F-66-063F-66-063F-74-3F3F-74-3F3F-74-3F
> なのでこれは
> {3F,66,06}
> {3F,74,3F}
> という2つのバイト列が取得出来ていることになります。ただShift-Jis文字列から
> バイト列に変換しているのでデータが欠落している可能性があります。 
>>> ここは不明検証していません

**** ひょっとして受信イベント処理との整合性に問題があるのでしょうか

データ受信が発生したときのイベント処理   (やっていること良く理解できません)

Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived

        'シリアルポートをオープンしていない場合、処理を行わない.
        If SerialPort1.IsOpen = False Then
            Return
        End If

        Try
            '受信データを読み込む.
            Dim data As String
            data = SerialPort1.ReadExisting()

            '受信したデータをテキストボックスに書き込む.
            Dim args(0) As Object  
            args(0) = data
            Invoke( New Delegate_RcvDataToTextBox( AddressOf Me.RcvDataToTextBox ), args )
        Catch ex As Exception
            MsgBox( ex.Message )
        End Try

    End Sub

    受信データをテキストボックスに書き込む.

以下のコードです  s = BitConverter.ToString(bytes) の結果を検証するために
            幾つかのよけいなコードを記述してあります

   Private Sub RcvDataToTextBox(data As String)
        Dim Z As Integer
        Dim LenX As Integer
        Dim I As Integer
        Dim DD As String
        Dim RecX As String
        LenX = Len(data)
        Dim s As String
        Dim SData As String
        Dim RData As String
        Dim Y As String

        DD = ""
        RecX = ""
        SData = ""
        RData = ""

        Dim bytes() As Byte = System.Text.Encoding.GetEncoding(932).GetBytes(data)
        s = BitConverter.ToString(bytes)
        For I = 0 To LenX - 1  ' Step 2
            SData = Mid(data, I + 1, 1)
            Z = Asc(SData)
            If Z < 10 Then Y = "0" & Hex(Z) Else Y = Hex(Z)
            RData = RData & Y
            DD = DD & Hex(bytes(I))  
            RecX = RecX & bytes(I) 
            'Stop
        Next
        RcvTextBox.AppendText(DD)  'で示す値 >>  3F6663F743F
        TextBox1.AppendText(RecX)  'で示す値 >>  6310266311663 
        TextBox2.AppendText(RData)  'で示す値 >>  3F66063F743F
        'Stop
    End Sub
ちなみに s = BitConverter.ToString(bytes)  で示す値 >>  3F-66-06-3F-74-3F

Dim bytes() As Byte = System.Text.Encoding.GetEncoding(932).GetBytes(data)
で受け取った文字列は上記方法では全て同じでした  当たり前ですね 
受け取った時点で違っていることになりませんか

VBA(2003と古いです)で以下のコードで受信が動いています

RECDATA$ = ec.Ascii  'ポートから受信
Lenx = Len(RECDATA$)

 For i = 1 To Lenx
  P$ = Mid$(RECDATA$, i, 1)
   If P$ = Chr$(&HFD) Then Exit For 
  Next i     ’ここまでのFor nextは意味がなさそう
 For k = 1 To Lenx
  P$ = Mid$(RECDATA$, k, 1)
  m = Asc(P$)
   If m < 16 Then X$ = "0" + Hex$(m) Else X$ = Hex$(m)
  D$ = D$ + X$   ’この文字列から必要な部分を切り取りする
Next k

これで無線機から変換した (たとえば FEFE66000600FEを変換)を送ってると受信文字列を変換して 
FEFE00660600FE を読み取れます
  
無線機からの文字列はPCから送るのと同様 16進数のコードを文字列にしているはずで
以下がPC側から送る文字列の変換
PR$ = Chr$(&HFE) + Chr$(&HFE) ' データ始まりの同期コード
RE$ = Chr$(&H66)              ' 無線機のアドレス
TX$ = Chr$(&H0)               ' PCのアドレス
CMA$ = Chr$(&H6)              ' コマンド
CMA$ = Chr$(&H0)              ' サブコマンド
FI$ = Chr$(&HFD)              ' 終わりのコード
TxString = PR$ + RE$ + TX$ + CMA$ + CMB$ + FI$ '合成して送る

尚 VB2010 でのPCから無線機への送信は以下のコードで上手く働きます

  Private Sub SndButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SndButton.Click
        Dim N As Integer = 5
        Dim bytOut() As Byte = New Byte(N + 1) {}
        bytOut(0) = &HFE
        bytOut(1) = &HFE
        bytOut(2) = &H66
        bytOut(3) = &H0
        bytOut(4) = &H6
        bytOut(5) = &H0
        bytOut(N + 1) = &HFD
        SerialPort1.Write(bytOut, 0, bytOut.Length)
     End Sub

これのリアルタイムでの受信バージョンができれば良いのですが・・・ご指導をよろしくお願いします

的外れな回答や記述などがあればお叱りいただきたく

[ツリー表示へ]
タイトルRe^3: VB2010 シリアル受信通信 byte で上手くいかない
記事No11880
投稿日: 2017/08/09(Wed) 08:47
投稿者shu
> > >    Private Sub RcvDataToTextBox(data As String)
> > dataをstringで渡していますが受信データは文字列ではないのではないですか?
> >>>そのとおりですが問題ありますか
問題ありです。文字列でないものを文字列として扱ったら動作は保証されません。



>             data = SerialPort1.ReadExisting()
>
これは文字列データを読むものなので不適切です。

例えば
        Dim bytes = SerialPort1.BytesToRead
        Dim data = New Byte(bytes-1) {}
        SerialPort1.Read(data, 0, bytes)
のようにbyte配列を用意してReadで読むようにした方がよいです。

[ツリー表示へ]
タイトルRe^3: VB2010 シリアル受信通信 byte で上手くいかない
記事No11885
投稿日: 2017/08/14(Mon) 14:30
投稿者魔界の仮面弁士
> (元コードは 金澤ソフト設計 が提供している sample0008)
検索したら下記がヒットしました。これのことですよね?
次回からは URL も分かるように書いていただけると回答しやすいです。
http://www.kana-soft.com/tech/sample_0008.htm
http://www.kana-soft.com/tech/code/sample_0008.zip


さて、そのサンプルの 4 ページ目を見ると、
http://www.kana-soft.com/tech/sample_0008_4.htm
》 サンプルプログラムでは、文字列の受信なので、ReadExisting()メソッドを
》 利用しましたが、バイナリデータを受信する場合、Read()メソッドを利用します。
と書かれています。

しかしながら No11874 のコードを見る限り、Read に変更することなく、
引き続き ReadExisting を使っていました。ここに問題があるわけです。


今回受信する
> 無線機に FEFE66000600FD を変換したものをPortに書き込みます
は文字列ではなくバイナリですから、Char 型や String 型で読み書きするメンバーは
一切使用できません。


【使っても良いメンバー】
SerialPort1.BytesToRead プロパティ
SerialPort1.Read( Byte(), Integer, Integer ) メソッド
SerialPort1.ReadByte( ) メソッド
SerialPort1.Write( Byte(), Integer, Integer ) メソッド


【使ってはいけないメンバー】
SerialPort1.Read( Char(), Integer, Integer ) メソッド
SerialPort1.ReadChar( ) メソッド
SerialPort1.ReadExisting( ) メソッド
SerialPort1.ReadLine( ) メソッド
SerialPort1.ReadTo( String ) メソッド
SerialPort1.Write( String ) メソッド
SerialPort1.Write( Char(), Integer, Integer ) メソッド


電文データが「文字列」ではないため、下記も使ってはいけません。
> Delegate Sub Delegate_RcvDataToTextBox( data As String )
> LenX = Len(data)
> System.Text.Encoding.GetEncoding(932)
> Z = Asc(SData)
> SData = Mid(data, I + 1, 1)


受信したデータを解析する際も、String 型に変換したりはせず、
Byte 配列のまま取り扱うようにしてみてください。

[ツリー表示へ]
タイトルRe^3: VB2010 シリアル受信通信 byte で上手くいかない
記事No11886
投稿日: 2017/08/14(Mon) 14:49
投稿者魔界の仮面弁士
Private Delegate Sub Delegate_RcvDataToTextBox( data As String )
は今回使わないで下さい。
受信データが文字列ではなくバイナリーである以上、
元データを As String に変換してから扱うのは御法度です。


> System.Text.Encoding.GetEncoding(932)
これも今回、出番が無いですね。


SerialPort1_DataReceived の中では、データは「Byte 配列」のまま取り扱いましょう。
たとえばこんな感じ。

'この TextBox1 は MultiLine = True にしておく
Private Sub RcvDataToTextBox(data() As Byte)
    TextBox1.AppendText(BitConverter.ToString(data) & vbNewLine)
End Sub


Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    If Not SerialPort1.IsOpen() Then
        Return    ''シリアルポートをオープンしていない場合、処理を行わない。
    End If

    Dim receivedData(SerialPort1.BytesToRead - 1) As Byte
    SerialPort1.Read(receivedData, 0, receivedData.Length)

    Invoke(New Action(Of Byte())(AddressOf Me.RcvDataToTextBox), receivedData)
End Sub




> RecX = RecX & bytes(I)
これだと、たとえば元データが
 bytes = New Byte() {1, 2, 3, 2, 1}  '5バイト
 bytes = New Byte() {12, 32, 1}  '3バイト
 bytes = New Byte() {123, 21}  '2バイト
のいずれであっても、連結結果が "12321" になってしまい、区別できませんね。

10進数で確認したいなら、せめて『RecX &= "," & CStr(bytes(I))』のようにします。
これなら、上記 3 パターンでも ",1,2,3,2,1"、",12,32,1"、",123,21" となり、区別できます。


> Z = Asc(SData)
> If Z < 10 Then Y = "0" & Hex(Z) Else Y = Hex(Z)
> RData = RData & Y
Hex 関数を使うと、先頭の "0" が抜け落ちてしまうので、
上記のような処理を書いていたのだと思いますが、
「2 桁の 16 進数」として得たいのであれば、
  Y = Z.ToString("X2")
だけで OK です。

[ツリー表示へ]
タイトルRe^4: VB2010 シリアル受信通信 byte で上手くいかない
記事No11887
投稿日: 2017/08/15(Tue) 07:59
投稿者MSAKA
YuO さん  shuさん
魔界の仮面弁士さん

おかげで目的の無線機からの受け取りが出来るようになりました
入り口でひっかかっていたのが何とか進められそうです
訳のわかっていない私に根気よく色々とアドバイスいただき
本当にありがとうございました

> Private Delegate Sub Delegate_RcvDataToTextBox( data As String )
> は今回使わないで下さい。
> 受信データが文字列ではなくバイナリーである以上、
> 元データを As String に変換してから扱うのは御法度です。
はい わかりました
> System.Text.Encoding.GetEncoding(932)
> これも今回、出番が無いですね。
そのようで
>
> SerialPort1_DataReceived の中では、データは「Byte 配列」のまま取り扱いましょう。
> たとえばこんな感じ。
>
> 'この TextBox1 は MultiLine = True にしておく
> Private Sub RcvDataToTextBox(data() As Byte)
>     TextBox1.AppendText(BitConverter.ToString(data) & vbNewLine)
> End Sub
>
>
> Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
>     If Not SerialPort1.IsOpen() Then
>         Return    ''シリアルポートをオープンしていない場合、処理を行わない。
>     End If
>
>     Dim receivedData(SerialPort1.BytesToRead - 1) As Byte
>     SerialPort1.Read(receivedData, 0, receivedData.Length)
>
>     Invoke(New Action(Of Byte())(AddressOf Me.RcvDataToTextBox), receivedData)
> End Sub
このコード大変参考になりました

> > RecX = RecX & bytes(I)
> これだと、たとえば元データが
>  bytes = New Byte() {1, 2, 3, 2, 1}  '5バイト
>  bytes = New Byte() {12, 32, 1}  '3バイト
>  bytes = New Byte() {123, 21}  '2バイト
> のいずれであっても、連結結果が "12321" になってしまい、区別できませんね。
>
> 10進数で確認したいなら、せめて『RecX &= "," & CStr(bytes(I))』のようにします。
> これなら、上記 3 パターンでも ",1,2,3,2,1"、",12,32,1"、",123,21" となり、区別できます。
>
>
> > Z = Asc(SData)
> > If Z < 10 Then Y = "0" & Hex(Z) Else Y = Hex(Z)
> > RData = RData & Y
> Hex 関数を使うと、先頭の "0" が抜け落ちてしまうので、
> 上記のような処理を書いていたのだと思いますが、
> 「2 桁の 16 進数」として得たいのであれば、
>   Y = Z.ToString("X2")
> だけで OK です。
仰せのとおりです 便利な方法ですね 以降利用させていただきます

[ツリー表示へ]
タイトルRe: VB2010 シリアル受信通信 byte で上手くいかない
記事No11878
投稿日: 2017/08/08(Tue) 16:22
投稿者YuO
> 前回は送信が旨く行かないのをバイナリーにしては如何かと提案を頂き 
> 送信側はすんなり解決しました  その気になって受信側を始めたのですが
> 難航 あれこれ調べても問題は解決する知識は無いようで万歳状態です

根本部分を認識しましょう。
バイナリで送信・受信するならば,大原則としてデータはByte()型のみで扱います。
String型を介してはいけません。String型を介するのは,テキストのプロトコルのみです。


>    Private Sub RcvDataToTextBox(data As String)

なぜ,dataがString型なのですか。
dataが受信データでバイナリで受信するならば,ここはByte()であるはずです。

[ツリー表示へ]
タイトルRe^2: VB2010 シリアル受信通信 byte で上手くいかない
記事No11881
投稿日: 2017/08/10(Thu) 10:38
投稿者MSAKA
YuOさん

ありがとうございます シリアル通信を理解せずにやっているので初歩的な相談をしてしまうこと
ご迷惑でしょうがよろしくお願いいたします


> 根本部分を認識しましょう。 >>> 仰せのとおりです
> バイナリで送信・受信するならば,大原則としてデータはByte()型のみで扱います。
> String型を介してはいけません。String型を介するのは,テキストのプロトコルのみです。
>
> >    Private Sub RcvDataToTextBox(data As String)
>
> なぜ,dataがString型なのですか。
> dataが受信データでバイナリで受信するならば,ここはByte()であるはずです。

>>> 誤解してました 全く そのとおりですね 

例えば
        Dim bytes = SerialPort1.BytesToRead
        Dim data = New Byte(bytes-1) {}
        SerialPort1.Read(data, 0, bytes)
のようにbyte配列を用意してReadで読むようにした方がよいです。

>>> 基本を理解せずにやろうとしているのでアチコチでぶつかります
    上記を試みましたが入り口
    Dim bytes = SerialPort1.BytesToRead >>> 型が定義されていない と

蹴られました  あれこれ調べましたが判らず
これは何処で定義する必要があるのでしょうか

[ツリー表示へ]
タイトルRe^3: VB2010 シリアル受信通信 byte で上手くいかない
記事No11882
投稿日: 2017/08/10(Thu) 12:35
投稿者YuO
引用部には>をつけ,返信自体には>>>のような物を前置せずに書いてください。
どこが引用かわからなくなっています。

また,プレビューで確認して,他人の引用の中に自身の文が入っていないかを確認してください。
引用部は色が変わるので,投稿者の文を見付けてから引用を読む場合に,投稿者の文が読み飛ばされます。


> > 例えば
> >         Dim bytes = SerialPort1.BytesToRead
> >         Dim data = New Byte(bytes-1) {}
> >         SerialPort1.Read(data, 0, bytes)
> > のようにbyte配列を用意してReadで読むようにした方がよいです。
>
> >>> 基本を理解せずにやろうとしているのでアチコチでぶつかります
>     上記を試みましたが入り口
>     Dim bytes = SerialPort1.BytesToRead >>> 型が定義されていない と
>
> 蹴られました  あれこれ調べましたが判らず
> これは何処で定義する必要があるのでしょうか

※shuさんの文について,引用記号を1段追加しました。
プロジェクトの設定で,Option InferをOffかつOption StrictをOnにしているのでしょうか。
そうであれば,
Dim bytes As Integer = SerialPort1.BytesToRead
のように型を明示する必用があります。
または,Option InferをOnにしてください。

[ツリー表示へ]
タイトルRe^4: VB2010 シリアル受信通信 byte で上手くいかない
記事No11883
投稿日: 2017/08/11(Fri) 16:15
投稿者MSAKA
YuOさん  ありがとうございます

> 引用部には>をつけ,返信自体には>>>のような物を前置せずに書いてください。
> どこが引用かわからなくなっています。
>
> また,プレビューで確認して,他人の引用の中に自身の文が入っていないかを確認してください。
> 引用部は色が変わるので,投稿者の文を見付けてから引用を読む場合に,投稿者の文が読み飛ばされます。
上記の2件 了解しました
>
> ※shuさんの文について,引用記号を1段追加しました。
> プロジェクトの設定で,Option InferをOffかつOption StrictをOnにしているのでしょうか。
> そうであれば,
> Dim bytes As Integer = SerialPort1.BytesToRead
> のように型を明示する必用があります。
> または,Option InferをOnにしてください。
型の明示で旨く働きました 

しかし 結果は同じでstringでもbyteでも16進に変換処理して返ってくる値は同じでした
希望値にはなりません 根本的な違いがあるのだと思います 考えられる原因は無いでしょうか
違うサンプルソースを探して試してみようと思います もしあるようなら教えていただけると幸いです

[ツリー表示へ]
タイトルRe^5: VB2010 シリアル受信通信 byte で上手くいかない
記事No11884
投稿日: 2017/08/11(Fri) 17:57
投稿者魔界の仮面弁士
> しかし 結果は同じでstringでもbyteでも16進に変換処理して返ってくる値は同じでした
> 希望値にはなりません 根本的な違いがあるのだと思います 考えられる原因は無いでしょうか

どのように確認しているのか分からない以上、その確認方法が適切であるのかは判断できませんし、
そもそもどういうコードを書いて受送信しているのかさえ分かりません。

そちらで記述あるいは修正したソースコードを伝えてもらわないことには、
どこに間違いがあるかを掲示板で指摘することは困難でしょう。

[ツリー表示へ]