C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: シリアル通信 送信コマンド(VB2008)


(過去ログ 126 を表示中)

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■75068 / inTopicNo.1)  シリアル通信 送信コマンド(VB2008)
  
□投稿者/ ガッキー (1回)-(2015/02/24(Tue) 13:57:19)

分類:[VB.NET/VB2005 以降] 

   仕事で通信プログラムを作る事になったのですが、
   プログラムが初めてなので(まだ3日程)、考え方とコードのご教示頂けないでしょうか。
   
   RS-485通信で送信するプログラムをVB2008で作成しています。

   送信コマンドの仕様ですが
    @STX(HEX)02Hで固定
    ANode No(ASCU)00〜31番までの可変
    BSub Add(ASCU)00と固定
    CSID(ASCU)0で固定
    DMRC(ASCU)01で固定
    ESRC(ASCU)01で固定
    FVAR(ASCU)40orC2の可変
    GReadStAd(ASCU)0000の固定
    HBIT(ASCU)00の固定
    IEle(ASCU)0001or000Bの可変
    JEXT(HEX)03Hで固定
    KBCC(HEX)A〜Jまでの値を利用
   これらをまとめたデータ
    [@STX]+[ANode No]+[BSub Add]+[CSID]+[DEFGHIFINE]+[JEXT]+[KBCC]
   を送信コマンドとして、データを送信します。

   送信はSerialPort.Writeを利用

   私のイメージとしては、
    @入力した文字列をHEX、ASCUコードに変換し、配列の中に代入する。
    A代入された配列の要素を一つに結合して変数に入れる。
    BSerialPort.Write関数を使ってデータを送信する。
   というイメージなのですが、あっていますでしょうか?
   
   途中段階ですが、コードを載せますので、アドバイス等お願い致します。
   
    Dim byttmp(11) As Byte
Dim NodeNo As String
Dim SubAdd As String
Dim SID As String
Dim MRC As String
Dim SRC As String
Dim Var As String
Dim ReadStAd As String
Dim Bit As String
Dim Ele As String
Dim BCC As Byte

'--- 配列初期化
Array.Clear(byttmp, 0, byttmp.Length)

'--- STX
byttmp(0) = 2

'--- Node No(00〜31番)
NodeNo = "00"

'--- サブアドレス
SubAdd = "00"
byttmp(2) = Asc(SubAdd)
byttmp(1) = Asc(NodeNo)

'--- SID
SID = "0"
byttmp(3) = Asc(SID)

'--- MRC
MRC = "01"
byttmp(4) = Asc(MRC)

'--- SRC
SRC = "01"
byttmp(5) = Asc(SRC)

'--- Var
Var = "40"
byttmp(6) = Asc(Var)

'--- ReadStAd
ReadStAd = "0000"
byttmp(7) = Asc(ReadStAd)

'--- Bit
Bit = "00"
byttmp(8) = Asc(Bit)

'--- Ele
Ele = "0001"
byttmp(9) = Asc(Ele)

'--- EXT
byttmp(10) = 3

'--- BCC
Dim i As Integer
For i = 1 To 10
BCC = BCC Xor byttmp(i)
Next

BCC = CByte(BCC)

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


'シリアルポートからデータを送信する.
SerialPort1.Write(byttmp, 0, byttmp.GetLength(0))


   

引用返信 編集キー/
■75069 / inTopicNo.2)  Re[1]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ぽぴ王子 (20回)-(2015/02/24(Tue) 15:39:07)
ぽぴ王子 さんの Web サイト
No75068 (ガッキー さん) に返信

>     @入力した文字列をHEX、ASCUコードに変換し、配列の中に代入する。

この部分が少し違うかもしれません。
送信コマンドの仕様として

1バイト目 02H
2バイト目 30H "0" 
3バイト目 30H "0" 2バイト目と3バイト目を合わせて Node No.
4バイト目 30H "0" 
5バイト目 30H "0" 4バイト目と5バイト目を合わせて Sub Address
6バイト目 30H "0" SID

という感じになるのだと思われます。
(コマンドで Google 検索をしたらそれらしき機器の説明書が見つかりました)
なので Node No. を代入している部分

>         '--- Node No(00〜31番)
>         NodeNo = "00"
> 
>         '--- サブアドレス
>         SubAdd = "00"
>         byttmp(2) = Asc(SubAdd)
>         byttmp(1) = Asc(NodeNo)

は、このような感じになるかと思います。

>         '--- Node No(00〜31番)
>         NodeNo = "00"
> 
>         '--- サブアドレス
>         SubAdd = "00"
>         byttmp(1) = CByte(Asc(NodeNo.SubString(0,1)))
>         byttmp(2) = CByte(Asc(NodeNo.SubString(1,1)))
>         byttmp(3) = CByte(Asc(SubAdd.SubString(0,1)))
>         byttmp(4) = CByte(Asc(SubAdd.SubString(1,1)))

以下 byttmp のサイズもそれに合わせて大きくなると思います。
この場合は

>         Dim byttmp As List(Of Byte())

のように宣言して

>         '--- Node No(00〜31番)
>         NodeNo = "00"
> 
>         '--- サブアドレス
>         SubAdd = "00"
>         byttmp.Add(CByte(Asc(NodeNo.SubString(0,1))))
>         byttmp.Add(CByte(Asc(NodeNo.SubString(1,1))))
>         byttmp.Add(CByte(Asc(SubAdd.SubString(0,1))))
>         byttmp.Add(CByte(Asc(SubAdd.SubString(1,1))))
(中略)
>         'シリアルポートからデータを送信する.
>         SerialPort1.Write(byttmp.ToArray(), 0, byttmp.Count)

と書いたほうがいいかもしれませんね。

引用返信 編集キー/
■75070 / inTopicNo.3)  Re[2]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ぽぴ王子 (21回)-(2015/02/24(Tue) 15:40:58)
ぽぴ王子 さんの Web サイト
No75069 (ぽぴ王子 さん) に返信

ちなみにVBのコードはうろ覚えで書いたので、間違っているかもしれません。
その場合はゴメンナサイ。
引用返信 編集キー/
■75071 / inTopicNo.4)  Re[3]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ガッキー (2回)-(2015/02/24(Tue) 18:19:25)
No75070 (ぽぴ王子 さん) に返信
> ■No75069 (ぽぴ王子 さん) に返信
> 
> ちなみにVBのコードはうろ覚えで書いたので、間違っているかもしれません。
> その場合はゴメンナサイ。

 お返事遅くなりました。ご回答ありがとうございます。
 非常にわかりやすくて参考になりました。
 
 もう一点、疑問があるのですが、Aの可変番号なのですが、
 Aはデザイン画面でコンボボックスを配置し、コンボボックス内から値を選択(00〜31)番して、
  その値をbyttmpに代入する(ご教示頂いた内容で)
>  2バイト目 30H "0" 
>  3バイト目 30H "0" 2バイト目と3バイト目を合わせて Node No.
  考えなのですが、コードとデザインの関連がよくわからない状態です。
  
  今あるコードを載せてみますので、わかり難いかもしれませんが、ご指摘等頂けないでしょうか。

 ◆デザイン側
  トップダウンメニューのNameをcmbNodeNoに変更
 
  ◆コード側
  '---NodeNo格納用のクラス定義.
  Private Class NodeNoItem
        Inherits Object

        Private m_name As String = ""
        Private m_value As Integer = 0

        '表示名称
        Public Property NAME() As String
            Set(ByVal value As String)
                m_name = value
            End Set
            Get
                Return m_name
            End Get
        End Property

        'NodeNo設定値.
        Public Property NodeNo() As Integer
            Set(ByVal value As Integer)
                m_value = value
            End Set
            Get
                Return m_value
            End Get
        End Property

        'コンボボックス表示用の文字列取得関数.
        Public Overrides Function ToString() As String
            Return m_name
        End Function

    End Class

  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
   'ノードNo選択コンボボックスに選択項目をセットする.
        Dim Node As NodeNoItem

        Node = New NodeNoItem
        Node.NAME = "00"
        cmbNodeNo.Items.Add(Node)
        cmbNodeNo.SelectedIndex = 0

        Node = New NodeNoItem
        Node.NAME = "01"
        cmbNodeNo.Items.Add(Node)
        cmbNodeNo.SelectedIndex = 1
  End Sub
  
  '---データ送信を行う処理
  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    'シリアルポートをオープンしていない場合、処理を行わない.
        If SerialPort1.IsOpen = False Then
            Return
        End If

    Dim byttmp(24) As Byte
        Dim NodeNo As String
    
    '--- Node No(00〜31番)
        NodeNo = Node.NAME
        byttmp(1) = (CByte(Asc(NodeNo.Substring(0, 1))))

  以上、よろしくお願いいたします。
 

引用返信 編集キー/
■75078 / inTopicNo.5)  Re[4]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ぽぴ王子 (22回)-(2015/02/25(Wed) 10:37:33)
ぽぴ王子 さんの Web サイト
No75071 (ガッキー さん) に返信
>  もう一点、疑問があるのですが、Aの可変番号なのですが、
>  Aはデザイン画面でコンボボックスを配置し、コンボボックス内から値を選択(00〜31)番して、
>   その値をbyttmpに代入する(ご教示頂いた内容で)
> >  2バイト目 30H "0" 
> >  3バイト目 30H "0" 2バイト目と3バイト目を合わせて Node No.
>   考えなのですが、コードとデザインの関連がよくわからない状態です。
>   
>   今あるコードを載せてみますので、わかり難いかもしれませんが、ご指摘等頂けないでしょうか。

コードを読ませていただきました。問題の部分というか、わかっていない部分はこのあたりでしょうか。

>         '--- Node No(00〜31番)
>         NodeNo = Node.NAME
>         byttmp(1) = (CByte(Asc(NodeNo.Substring(0, 1))))

追いかけるのが大変になるので、とりあえずは対象の部分だけあればいいかもしれません。

まず byttmp(1) は Byte 型の一項目というのはわかりますよね。
その中には Byte 型、つまり 1 バイト分しか入りません。
MSDN で Asc を調べていただくとわかりますが Asc("00") では 1 文字目の "0" のアスキーコードしか取得できません。
なので 1 文字目のアスキーコードと 2 文字目のアスキーコードをそれぞれ別に求めて byttmp には 2 つの項目として
設定する必要があります。


>         byttmp(1) = CByte(Asc(NodeNo.Substring(0, 1)))
>         byttmp(2) = CByte(Asc(NodeNo.Substring(1, 1)))

前に書いたこのコードは NodeNo.Substring(0, 1) で先頭の文字 1 文字( 1 番目の引数は開始文字位置なので 0 から始まります)を
取得して、そのアスキーコードを求めて、そのアスキーコードを CByte で Byte 型に変換しています。
(Integer から Byte へは暗黙のキャストがあるはずなので必要ないかもしれませんが、念のため)

2 行目は同様に NodeNo.Substring(1, 1) で 2 文字目の 1 文字を取得し、そのアスキーコードを求めています。

> >  2バイト目 30H "0" 
> >  3バイト目 30H "0" 2バイト目と3バイト目を合わせて Node No.

これは NodeNo が "00" という値として仮定して書いているのでちょっとわかりにくいですが "31" という値が入っていた
とするならば、 1 文字ずつのアスキーコードが入るので、こういった感じになります。

> >  2バイト目 33H "3" 
> >  3バイト目 31H "1" 2バイト目と3バイト目を合わせて Node No.

こんな感じの説明で大丈夫でしょうか。

引用返信 編集キー/
■75079 / inTopicNo.6)  Re[1]: シリアル通信 送信コマンド(VB2008)
□投稿者/ 魔界の仮面弁士 (211回)-(2015/02/25(Wed) 12:07:14)
No75068 (ガッキー さん) に返信
>    送信コマンドの仕様ですが

こういうことで良いのかな…。

Dim STX() As Byte = {&H2}       '02H固定
Dim NodeNo As String = "01"     'ASCII 2桁 "00"〜"31"
Dim SubAdd As String = "00"     'ASCII 2桁 "00" 固定
Dim SID As String = "0"         'ASCII 1桁 "0" 固定
Dim MRC As String = "01"        'ASCII 2桁 "01" 固定
Dim SRC As String = "01"        'ASCII 2桁 "01" 固定
Dim Var As String = "40"        'ASCII 2桁 "40" or "C2"
Dim ReadStAd As String = "0000" 'ASCII 4桁 "0000" 固定
Dim Bit As String = "00"        'ASCII 2桁 "00" 固定
Dim Ele As String = "000B"      'ASCII 4桁 "0001" or "000B"
Dim BCC As Byte

Dim sendText As String = NodeNo & SubAdd & SID & MRC & SRC & Var & ReadStAd & Bit & Ele
Dim sendBinary() As Byte = System.Text.Encoding.ASCII.GetBytes(sendText)

BCC = 0
Array.ForEach(sendBinary, Sub(b) BCC = BCC Xor b)

Dim buffer() As Byte = STX.Concat(sendBinary).Concat({BCC}).ToArray()

'この時点で、buffer.Length は 23 を返す。bufferは0〜22。
SerialPort1.Write(buffer, 0, buffer.Length)

引用返信 編集キー/
■75080 / inTopicNo.7)  Re[4]: シリアル通信 送信コマンド(VB2008)
□投稿者/ 魔界の仮面弁士 (212回)-(2015/02/25(Wed) 12:32:30)
No75071 (ガッキー さん) に返信
>   Private Class NodeNoItem
>         Inherits Object
Inherits Object は冗長かと思いますよ。

ところで、NAME はすべて大文字で、NodeNo はパスカルケース記法なのは
意図的にそうされているのでしょうか。


>         Private m_value As Integer = 0
>         Public Property NodeNo() As Integer
提示範囲では、これらが使われている様子が無いので、
ComboBox には .Items.Add("00") などとして、
文字列を直接渡すだけで済むようにも見えます。


>         cmbNodeNo.SelectedIndex = 0
> 
>         cmbNodeNo.SelectedIndex = 1
最後の SelectedIndex で上書きされているので、前者の 0 代入は無意味かと。
cmbNodeNo.SelectedIndex ではなく、Node.NodeNo





>         Node = New NodeNoItem
>         Node.NAME = "00"
>         cmbNodeNo.Items.Add(Node)
管理する値が 2 つ(NodeNo As Integer と NAME As String)だけなのであれば、
KeyValuePair(Of Integer, String) を使うこともできます。


Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim node As New Dictionary(Of Integer, String)()

        '第一引数が、NodeItem.NodeNo に相当(重複不可)。
        '第二引数が、NodeItem.NAME および ToString に相当。
        node.Add( 0, "00")
        node.Add( 1, "01")
        node.Add(31, "31")

        ComboBox1.DataSource = node.ToArray()
        ComboBox1.ValueMember = "Key"
        ComboBox1.DisplayMember = "Value"

        '末尾項目を選択
        ComboBox1.SelectedIndex = node.Count - 1
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If ComboBox1.SelectedIndex <> -1 Then
            'Dim NAME As String = ComboBox1.GetItemText(ComboBox1.SelectedItem)

            Dim item = DirectCast(ComboBox1.SelectedItem, KeyValuePair(Of Integer, String))
            Dim NAME As String    = item.Value
            Dim NodeNo As Integer = item.Key

            '
            '
        End If
    End Sub
End Class

引用返信 編集キー/
■75085 / inTopicNo.8)  Re[2]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ガッキー (3回)-(2015/02/25(Wed) 14:48:39)
■魔界の仮面弁士さん
■ぽぴ王子さん

お返事遅くなりました。ご回答ありがとうございます!
これから内容の確認を行い、コードを修正してみます。
確認作業中に疑問が出てきましたら、改めて質問を投げさせて頂きます。

また、その他に思いついた点等ありましたら、追記して頂けると非常に助かります。

引用返信 編集キー/
■75113 / inTopicNo.9)  Re[3]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ガッキー (4回)-(2015/02/27(Fri) 16:19:53)
お世話になります。

書き込んで頂いた内容を整理しまして、以下のようなコードに修正しました。
また、確認中に出た疑問なのですが
下記のコードで、送信を行うと★部分の箇所で

 「インデックスが範囲を超えています。負でない値で、コレクションのサイズよりも小さくなければなりません。
 パラメータ名: index」

というエラーがbyttmp(i)の箇所で吐き出されます。For文を消してBCC = BCC Xor byttmp(0)にすると吐き出されないのですが、これの出現する原因と対処方法を教えて頂けないでしょうか。


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim byttmp As New List(Of Byte)
        Dim NodeNo As String
        Dim SubAdd As String = "00"
        Dim SID As String = "0"
        Dim MRC As String = "01"
        Dim SRC As String = "01"
        Dim Var As String = "40"
        Dim ReadStAd As String = "0000"
        Dim Bit As String = "00"
        Dim Ele As String = "0001"
        Dim BCC As Byte

        '--- STX
        byttmp.Add(2)

        '--- Node No(00〜31番)
        NodeNo = ComboBox1.Text          '---コンボボックスから値を取得
        byttmp.Add(CByte(Asc(NodeNo(0))))
        byttmp.Add(CByte(Asc(NodeNo(1))))

        '--- サブアドレス
        byttmp.Add(CByte(Asc(SubAdd(0))))
        byttmp.Add(CByte(Asc(SubAdd(1))))

        '--- SID
        byttmp.Add(CByte(Asc(SID(0))))

        '--- MRC
        byttmp.Add(CByte(Asc(MRC(0))))
        byttmp.Add(CByte(Asc(MRC(1))))

        '--- SRC
        byttmp.Add(CByte(Asc(SRC(0))))
        byttmp.Add(CByte(Asc(SRC(1))))

        '--- Var
        byttmp.Add(CByte(Asc(Var(0))))
        byttmp.Add(CByte(Asc(Var(1))))

        '--- ReadStAd
        byttmp.Add(CByte(Asc(ReadStAd(0))))
        byttmp.Add(CByte(Asc(ReadStAd(1))))
        byttmp.Add(CByte(Asc(ReadStAd(2))))
        byttmp.Add(CByte(Asc(ReadStAd(3))))

        '--- Bit
        byttmp.Add(CByte(Asc(Bit(0))))
        byttmp.Add(CByte(Asc(Bit(1))))

        '--- Ele
        byttmp.Add(CByte(Asc(Ele(0))))
        byttmp.Add(CByte(Asc(Ele(1))))
        byttmp.Add(CByte(Asc(Ele(2))))
        byttmp.Add(CByte(Asc(Ele(3))))

        '--- EXT
        byttmp.Add(3)

        '--- BCC
        Dim i As Integer = 0
        BCC = 0
        For i = 0 To byttmp.Count
★            BCC = BCC Xor byttmp(i)
        Next

        byttmp.Add(BCC)


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

        'シリアルポートからデータを送信する.
        SerialPort1.Write(byttmp.ToArray(), 0, byttmp.Count)

    End Sub



引用返信 編集キー/
■75114 / inTopicNo.10)  Re[4]: シリアル通信 送信コマンド(VB2008)
□投稿者/ shu (703回)-(2015/02/27(Fri) 16:28:33)
No75113 (ガッキー さん) に返信
> 「インデックスが範囲を超えています。負でない値で、コレクションのサイズよりも小さくなければなりません。
>  パラメータ名: index」
>
> というエラーがbyttmp(i)の箇所で吐き出されます。For文を消してBCC = BCC Xor byttmp(0)にすると吐き出されないのですが、これの出現する原因と対処方法を教えて頂けないでしょうか。
>

> For i = 0 To byttmp.Count
> ★ BCC = BCC Xor byttmp(i)
> Next

インデックスは0から始まるので最大インデックス値は要素数より1少なくなります。

引用返信 編集キー/
■75115 / inTopicNo.11)  Re[5]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ミーシャ (2回)-(2015/02/27(Fri) 16:34:50)
Listのインデックスは0から始まるので、最後の要素のインデックスは(要素数-1)です。
つまり、

For i = 0 To byttmp.Count - 1

となります。
引用返信 編集キー/
■75116 / inTopicNo.12)  Re[4]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ぽぴ王子 (23回)-(2015/02/27(Fri) 16:38:52)
ぽぴ王子 さんの Web サイト
No75113 (ガッキー さん) に返信

shu さんがフォローしてくださっていますが、 byttmp の Count は要素数より 1 少なくなります。
例えば 10 要素が追加されていた場合は、 Count プロパティは 9 になります。

なので、修正するとしたらこんな感じです。

        For i = 0 To byttmp.Count - 1
            BCC = BCC Xor byttmp(i)
        Next

あるいは For Each を使用してこんな感じとか。要素数を気にしなくていいので楽です。

        For Each b As Byte In byttmp
            BCC = BCC Xor b
        Next

ただ、 No.75079 で弁士さんが的確なフォローをしてくださっているので、それを応用するならば

        byttmp.ForEach(Sub(b) BCC = BCC Xor b)

こんな感じで書けそうな気がします。 VB は最近全然書いてないのでうろ覚えですが。

引用返信 編集キー/
■75117 / inTopicNo.13)  Re[6]: シリアル通信 送信コマンド(VB2008)
□投稿者/ ガッキー (5回)-(2015/02/27(Fri) 16:58:05)
■ミーシャさん
■shuさん
■ぽぴ王子さん

ご回答ありがとうございます。
書き込んで頂いた内容で修正すると、エラーが消えて無事に送信が行えました。

次は受信コマンドを作成する事になるのですが、作成段階で疑問点が出てきましたら新しい記事を立てる事があるかと思いますので、見かけました時はよろしくお願いいたします。

書き込んで下さった皆様、ありがとうございました!
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -