Top Page VB2013でSWRをビジュアル表示
自作工程のメモとして
Feb.2015


 今年(2014)はKiCADに続いて何か新しいものにチャレンジしてみようと VisualBasic(以 降VBと略す)に取り組むことにしました。
昔、N88Basicを遊び程度に使ったことがありましたが、以前からWeb上で眺めていたVBの記述は、ひとつの命令を記述するのにやたらと英 語が長く続く印象があり、敬遠していました。しかし、「Visual Studio Express 2013 for Windows Desktop」(以下、VS Express 2013 for Desktop)もUpdate 3まで更新されて提供されているのをみて、インストールしました。

教材は、主にWeb上で諸先輩が提供されているサンプルと、色々迷った挙句、購入した一冊が次の 「VisualBasic2013逆引き大全555の極意」本です。その他の初心者本も見てみましたが、この本に決めたのは実現したいことが引けるという ことが決め手でした。

(2014年12月には、出来上がっていましたがWeb上にUPするのが億劫になり、2ヶ月遅れでやっと掲載できました)



VB2013 555の極意      SDAA_Vew

Edit by SeaMonkey Composer.

1.仕様
ソフトを作成するにしても、 実現したいことが明確になっていないと始まりませんので、次のような目標を立てました。
また、ソフト名称は、SDAAtool (Screw Driver Antenna Analysis tool)としています。

■ 目標
使用しているScrewdriverアンテナのSWR特性をビジュアル表示する。

■ 仕様
1.別掲載の「Hi-Q-4/160 コントローラ製作」 で使用しているコントローラを使用する。
2.コントロールは、CI-Vを拡張して使用する。
3.CI-V拡張コマンドは、アドレス部やコマンドを変更できるようにする。
4.コントローラを操作している赤外線リモコンと同じ動作をパソコン(以降PCと略す)からも操作できるようにする。
5.
■ CI-Vコマンドの拡張
1.コントローラ側のアドレスを"E1"、PC側を"E2"とする。(変更可能)
2.拡張コマンドを"AA"とする。(変更可能)
3.サブコマンドを使用して各々の指示をする。
4.コマンドの確認は、コントローラ側のレスポンスではなく、送出信号の衝突を検出して再送をする。

■ CI-Vコマンド・レスポンスのデータ形式

CI-V_Ext_Specification
*周波数は、百Hzまでとし、実際の送出はKHzまでのデータを送出している。
*連番は、00〜99を繰り返し、レスポンス(返送されるデータ)の欠落を検出するため付加している。


2.Hi-Q-4/160 コントローラ側の処理

Hi-Q-4/160 コントローラ側は、ハードの変更は無くソフトの追記のみで実現できましたが、手間がかかったのが可変長のコマンドを受け取るCI-Vの受信(割り込み)処理でした。

■ 割り込みによる受信処理(PIC 18F452 , MikroC PRO for PIC 6.4)

         void interrupt() {
             if (INTCON.TMR0IF) {
                  t0_count++;
                  TMR0L = 131;                      // 131 to 256 = 125count(≒0.1mS)
                  INTCON.TMR0IF = 0;
              }

             if(PIR1.RCIF){

               if (UART1_Data_Ready() == 1) {            // If data is received,
                         uart_rd = UART1_Read();    // read the received data,
                    switch (civ_count) {

                    case 10:        if (uart_rd == 0xFD)
                                        civ_count++;
                                        else civ_count = 0;
                                    break;
                    case 9:         if (extn_count == 4)
                                       Ext_bcd[0] = uart_rd;
                                       civ_bcd[3] = 0;
                                       civ_count++;
                                    break;
                    case  8:        civ_bcd[0] = uart_rd;
                                    civ_count++;
                                    break;
                    case  7:        civ_bcd[1] = uart_rd;
                                    civ_count++;
                                    break;
                    case  6:        if (extn_count == 4){
                                         if(uart_rd == 0xfd) {
                                             civ_count = 11;
                                             break;
                                         }
                                    }
                                    civ_bcd[2] = uart_rd;
                                    civ_count++;
                                    break;
                    case  5:        if (extn_count == 3){
                                       switch (uart_rd ){
                                           case 0x01:
                                           case 0x02:
                                           case 0x03:
                                           case 0xF1:
                                           case 0xF2:
                                               Extn_sub = uart_rd;
                                               extn_count++;
                                               break;
                                           default:
                                               Extn_sub = 0;
                                               extn_count = 0;
                                               break;
                                       }
                                    }
                                    if(uart_rd == 0xfd)
                                        civ_count = 0;
                                        else civ_count++;
                                    break;
                    case  4:        if (uart_rd == ExtnCIVcmd)  // 拡張 自作CI-Vコマンドなら
                                         extn_count++;
                                         else extn_count = 0;
                                    if(uart_rd == 0xfd)
                                        civ_count = 0;
                                        else civ_count++;
                                    break;
                    case  3:        if (uart_rd == HostCIVadd)  // 拡張 PCからのコマンドなら
                                         extn_count++;
                                         else extn_count = 0;
                                    if(uart_rd == 0xfd)
                                        civ_count = 0;
                                        else civ_count++;
                                    break;
                    case  2:        if (uart_rd == ContCIVadd)  // 拡張 Hi-Q_CONTへのコマンドなら
                                         extn_count = 1;
                                         else extn_count = 0;
                                    if(uart_rd == 0xfd)
                                        civ_count = 0;
                                        else civ_count++;
                                    break;
                    case  1:        if (uart_rd == 0xFE)
                                        civ_count++;
                                        else civ_count = 0;
                                    break;
                    case  0:        if (uart_rd == 0xFE)
                                        civ_count++;
                                        else civ_count = 0;
                                    break;
                    default:        break;
                    }
                }
                PIR1.RCIF = 0;

              }
              if(INTCON.INT0IF == 1) {  //RB0/INT割込み 赤外線リモコン

                  INTCON.INT0IE = 0;    //RB0/INT割込みの禁止
                    switch(IN_red) {
                        case 0:
                            t0_count = 0;
                            IN_red++;
                            TMR0L = 131;    // 131 to 256 = 125count(≒0.1mS)
                            INTCON.TMR0IE = 1; //Timer0/INT割込みの許可
                            break;
                        case 1:
                        if(xxx == 0) xxx = t0_count;
                            if((t0_count >= 40) && (t0_count <= 62)){   //実測4.9mS
                                t0_count = 0;
                                IN_red++;
                            }else{                                      //範囲を外れた
                                IN_red = 0;
                                INTCON.TMR0IE = 0; //Timer0/INT割込みの禁止
                            }
                            break;
                        case 66:
                            IR_flag = 1;
                            IN_red = 0;
        //                    SENS_1 = 0;                   // Debug用LED点灯●
                            break;
                        default:
                            if((IN_red >= 2) && (IN_red <= 65)) {   // 8Byte = 64bit
                                if(t0_count >= 21){                 // 2.1mS以上なら無効
                                    IN_red = 0;
                                    INTCON.TMR0IE = 0; //Timer0/INT割込みの禁止
                                }else{
                                    irx = (IN_red - 2) / 8;
                                    IR_buff[irx] = IR_buff[irx] >> 1;
                                    if(t0_count <= 12){             // 1.2mSが敷居値
                                        IR_buff[irx].B7 = 0;
                                    }else{
                                        IR_buff[irx].B7 = 1;
                                    }
                                    t0_count = 0;
                                    IN_red++;
                                }
                            }
                            break;
                    }

                  INTCON.INT0IF = 0;    //RB0/INT0割込みフラグクリアー
                  INTCON.INT0IE = 1;    //RB0/INT0割込みの許可
              }
              if(INTCON3.INT1IF == 1) {  //回転検出

                  INTCON3.INT1IE = 0;    //RB1/INT1割込みの禁止
                    switch(Motor_U1D2 ) {     // 方向レジスター
                        case 1:                 // UP方向
                            SENSOR_SW_CNT++;
        //          if ( SENSOR_SW_CNT >= 0 ) { Limit_U1D2 = 0; }
                            break;
                        case 2:                 // DW方向
                            SENSOR_SW_CNT--;
        //          if ( SENSOR_SW_CNT < SENSOR_MAX ) { Limit_U1D2 = 0; }
                            break;
                        default:
                            break;
                    }
                  INTCON3.INT1IF = 0;    //RB1/INT1割込みフラグクリアー
                  INTCON3.INT1IE = 1;    //RB1/INT1割込みの許可
              }
              if(INTCON3.INT2IF == 1) {  //電流オーバー

                  INTCON3.INT2IE = 0;    //RB2/INT2割込みの禁止
                  M_shut();             // モーターを即時遮断
                    switch(Motor_U1D2 ) {     // 方向レジスター
                        case 1:                 // UP方向
                            Limit_U1D2 = 1;
                            break;
                        case 2:                 // DW方向
                            Limit_U1D2 = 2;
                            SENSOR_SW_CNT = 0;  // 回転カウンターをゼロにする。
                            break;
                        default:
                            break;
                    }
                  INTCON3.INT2IF = 0;    //RB2/INT2割込みフラグクリアー
                  INTCON3.INT2IE = 1;    //RB2/INT2割込みの許可
              }
        }

3.PC側のソフト

VBを初めて使うため、Web上の諸先輩が公開されている記述を参考にして自分流に変更を加えてみました。
文頭の 「VisualBasic2013逆引き大全555の極意」本よりはるかに参考になり、90%以上はWeb上からの引用で、極意本は必要とする関数(古い 言い方ですが)を調べるのに役立ちました。

■ データの送信・受信の処理
何かの参考になればと、一部を掲載しておきます。

    '--------------------------------------------------------------------------------------
    '■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    '■  [Start]ボタンを押して、データ送信を行う
    '■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    '
    Private Sub SndButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SndButton.Click

        'シリアルポートのオープン確認
        If SerialPort1.IsOpen = False Then
            Return
        End If

        OpenJob(sender, e)
        RecvJob10()

        '周波数・スイープ幅情報を読み取る

        FMaxIdx = 0                      ' FreqVal(65000) 配列の指標をゼロにする ***
        RMaxIdx = 0                      ' RetnVal(65000) 配列の指標をゼロにする ***
        Dim FreqDiv As Integer

        'CenterFreqBoxに数字以外の文字が有れば除外する
        Dim str As String = ""
        Dim c As Char
        For Each c In CenterFreqBox.Text
            If c >= "0" And c <= "9" Then
                str = str & c
            End If
        Next
        '指定周波数が1,700KHz〜60,000KHzの範囲外なら、14,000にする。
        FreqCenter = Integer.Parse(str)
        If FreqCenter < LowerLimitFreq Or FreqCenter > UpperLimitFreq Then  '下限設定 = 1.7MHz
            FreqCenter = 14000
        End If
        'テキストBOXに書き戻す ("#,0")は、カンマ付書式 
        CenterFreqBox.Text = FreqCenter.ToString("#,0")

        '周波数の幅をコンボボックスから取り出す.
        Dim fwidth As FreqWidthItem
        fwidth = CmbFreqWidth.SelectedItem
        FreqWidth = fwidth.FREQWIDTH

        'ビューの分割ステップをコンボボックスから取り出す.
        Dim dvstep As VewCivNumbItem
        dvstep = CmbDivNumb.SelectedItem
        XstepMax = dvstep.VEWDIVNUMB

        '周波数の上限・下限を算出し、ステップを算出し表示する
        FreqLow = FreqCenter - FreqWidth
        FreqHigh = FreqCenter + FreqWidth
        FreqStep = FreqWidth * 2 / XstepMax '単位は KHz◆■◆
        FreqDiv = FreqWidth / 5             '表示用
        LabelLowF.Text = FreqLow.ToString("#,0") & "KHz"
        LabelHighF.Text = FreqHigh.ToString("#,0") & "KHz"
        LabelCenterF.Text = FreqCenter.ToString("#,0") & "KHz"
        LabelDiv.Text = "(" & FreqDiv.ToString() & "KHz/Div)"

        Dim i As Integer, ix As Integer, iy As Integer, tmp As Integer
        FreqNow = FreqLow

        '        While FreqNow <= FreqHigh
        exi = 0                        '送出データの連番
        While FreqNow <= FreqHigh + (FreqStep * 1)

            If exi = 100 Then exi = 0 '■ exi ■ が100を超えたら0にする

            If FreqNow >= LowerLimitFreq And FreqNow <= UpperLimitFreq Then
                i = FreqNow
                tmp = i \ 1000
                VfoNow(0) = IntToBcd(tmp)
                i = i - (tmp * 1000)
                tmp = i \ 10
                VfoNow(1) = IntToBcd(tmp)
                i = i - (tmp * 10)
                tmp = i * 10
                VfoNow(2) = IntToBcd(tmp)

                VfoNow(3) = IntToBcd(exi)


                'TxBuf = {&HFE, &HFE, &HE1, &HE2, &HAA, &H3, &H30, &H20, &H14, &H0, &HFD}
                TxBuf = {&HFE, &HFE, ConAdr, My_Adr, ConCmd, &H3, VfoNow(2), VfoNow(1), VfoNow(0), VfoNow(3), &HFD}

                '----------------------------------------------------------------
                'Txバッファの中身をHexの文字に変換(1バイト=2文字)
                TxComp = ""
                For i = 0 To 10
                    TxComp = TxComp & ByteToHex(TxBuf(i))
                Next i

                TxCmdNo = 3
                '----------------------------------------------------------------
                Try

                    '----------------------------------------------------------------
                    '送出文字が受信バッファに入ったのを確認する
                    'TxCmdNoがゼロ(受信処理)にならなければ再送(3回)
                    i = 0
                    iy = 0
                    While i < 3

                        While iy < 3
                            'バイナリデータ送出
                            SerialPort1.Write(TxBuf, 0, 11)
                            'RecvJob()
                            For ix = 0 To 30
                                If TxCmdNo = 0 Then     '戻り信号が合致した
                                    Exit While
                                Else
                                    RecvJob0()
                                End If
                            Next ix
                            RecvJob()
                            iy += 1
                        End While

                        'RecvJob()
                        For ix = 0 To 30
                            If exi = retex Then
                                Exit While
                            Else
                                RecvJob0()
                            End If
                        Next ix
                        'MsgBox("RET  Time Over ")
                        RecvJob()
                        i += 1
                    End While
                    '----------------------------------------------------------------

                Catch ex As Exception
                    MsgBox(TxCmdNo & "SndButton_Click:" & ex.Message)
                End Try

                'RecvJob()
            Else
                RetnVal(RMaxIdx) = 1000
                RMaxIdx += 1
            End If
            FreqVal(FMaxIdx) = FreqNow
            FMaxIdx += 1         '指標に1プラス
            FreqNow += FreqStep
            exi += 1

            If (CheckBreak.Checked) Then    '途中で停止する処理

                Exit While
            End If

        End While
        RecvJob10()
        CloseJob(sender, e)
        RecvJob()
        'MsgBox("FMaxIdx=" & FMaxIdx & "  RMaxIdx= " & RMaxIdx)
        'MsgBox("FMaxIdx=" & FMaxIdx & "  FreqNow= " & FreqNow)

        ImgPlot()           '描画


    End Sub

    '■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    '  データ受信が発生したときのイベント処理
    '■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
    '
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived

        Dim data As String = ""
        Dim Freqdata As String = ""
        Dim tmprx As Integer = 0
        Dim PosFD As Integer = 0
        Dim PosFE03 As Integer = 0
        Dim PosFE7A03 As Integer = 0
        Dim PosRdo As Integer = 0
        Dim HitPtn As String = "FEFE"
        Dim BgnCIV As String = "FEFE"
        Dim BgnPos As Integer = 0
        Dim BgnFlg As String = "FEFE"
        Dim FreqPtn2 As String = 0
        Dim RetInt As Integer = 0
        Dim msgmsg As String = ""       'デバッグ用
        'Dim HitByte As String
        'Dim i As Integer

        'シリアルポートのオープン確認
        If SerialPort1.IsOpen = False Then
            Return
        End If

        AdrSet()

        'HitByte = "&HFE" & "&HFE" & My_Adr & ConAdr & ConCmd & "&H3"
        HitPtn = HitPtn & ByteToHex(My_Adr) & ByteToHex(ConAdr) & ByteToHex(ConCmd) & "03"
        BgnFlg = BgnFlg & ByteToHex(My_Adr) & ByteToHex(RdoAdr)

        Try
            '受信データを読み込む


            'data = SerialPort1.ReadExisting()
            tmprx = SerialPort1.Read(RxBuf, 0, 1000)
            'MsgBox(tmprx)

            '受信バッファの中身をHexの文字に変換(1バイト=2文字)
            For i As Integer = 0 To tmprx - 1
                CEdata = CEdata & ByteToHex(RxBuf(i))
                'CEdata = CEdata & RxBuf(i)
                'i += 1
            Next i

            'Private FreqVal(65000)
            'Private RetnVal(65000)
            'Private FMaxIdx As Integer
            'Private RMaxIdx As Integer
            'Private CEdata As String         'Constant extraction 定数抽出

            '文字列 data ConstExtdata に指定した文字 "&HFD" が含まれるかを調べ、
            '   あれば位置を格納する=>PosFD
            '
            PosFD = 0
            msgmsg = "f1  "
            While 1
                PosFD = CEdata.IndexOf("FD", 0)
                If PosFD = -1 Then
                    Exit While
                End If

                If TxCmdNo = 0 Then

                    PosFE03 = CEdata.IndexOf(HitPtn, 0)
                    If PosFE03 > -1 And (PosFE03 + 18) = PosFD Then

                        retex = Val(CEdata.Substring(PosFE03 + 16, 2))  '送出順 10 20...90 10
                        RetInt = Val(CEdata.Substring(PosFE03 + 14, 2)) * 100
                        RetInt += Val(CEdata.Substring(PosFE03 + 12, 2))
                        RetnVal(RMaxIdx) = RetInt
                        RMaxIdx += 1
                        If (CheckVew.Checked) Then
                            data = data & CEdata.Substring(PosFE03 + 14, 2)
                            data = data & CEdata.Substring(PosFE03 + 12, 2)
                            data = data & CEdata.Substring(PosFE03 + 16, 2) & " "
                        End If

                    End If
                    msgmsg = "f2  "
                    '自動的にRigの周波数を取り込むチェックがされていたら
                    If (CheckAutoF.Checked) Then
                        'If (CheckAutoF.Checked) And OneTime = 1 Then
                        PosFE7A03 = CEdata.IndexOf(BgnFlg, 0)     'FEFE007A ?

                        'Rigからの周波数データを取り込む=>Freqdata
                        If PosFE7A03 > -1 And (PosFE7A03 + 20) = PosFD Then
                            FreqVFO = Val(CEdata.Substring(PosFE7A03 + 16, 2)) * 1000
                            FreqVFO = FreqVFO + Val(CEdata.Substring(PosFE7A03 + 14, 2)) * 10
                            FreqVFO = FreqVFO + Val(CEdata.Substring(PosFE7A03 + 12, 1))
                            Freqdata = FreqVFO.ToString()
                            TxCmdNo = 0
                            'Invokeを使って中心周波数の入力兼表示Boxに書き込む
                            Dim args(0) As Object
                            args(0) = Freqdata
                            Invoke(New Delegate_RcvDataToCenterFreqBox(AddressOf Me.RcvDataToCenterFreqBox), args)

                            OneTime = 0
                        End If

                    End If
                End If
                msgmsg = "f3  "

                If TxCmdNo >= 1 And TxCmdNo < 9 Then
                    BgnPos = CEdata.IndexOf(BgnCIV, 0)

                    If BgnPos > -1 And BgnPos < PosFD Then
                        'If TxComp = CEdata.Substring(BgnPos, PosFD + 2) Then
                        If TxComp = CEdata.Substring(BgnPos, PosFD - BgnPos + 2) Then
                            'MsgBox(TxComp & "aaaaa" & CEdata.Substring(BgnPos, PosFD + 2))
                            TxCmdNo = 0
                        End If
                    End If

                End If
                msgmsg = "f4  "
                '処理したFDまでを削除して詰める
                CEdata = CEdata.Remove(0, PosFD + 2)

                'MsgBox(CEdata)

            End While
            msgmsg = "f5  "
            '
            If (CheckVew.Checked) Then
                '受信したデータをテキストボックスに書き込む()
                Dim args(0) As Object
                args(0) = data
                Invoke(New Delegate_RcvDataToTextBox(AddressOf Me.RcvDataToTextBox), args)
            End If

        Catch ex As Exception
            MsgBox(msgmsg & TxCmdNo & "SerialPort1_DataReceived:" & ex.Message)

        End Try

    End Sub
    '--------------------------------------------------------------------------------------

*受信部は、1バイトをHexで表し英数2文字に拡張して処理を実施しています。


3.実行時のノートン Sonar による不具合

開発したソフトを実行しようとすると、Norton Internet Security の Sonar が、怪しいファイルとして認識し、実行ファイルが削除されます。
そこで、以下のように実行許可を設定する必要があります。


Sonar_Vew



4.測定時のサンプル

今までは、スポットで見たSWR特性を目安に運用していましたが、ビジュアルで確認すると安心感が増します。
サンプルは、良い特性を示していますがSDアンテナを振り出す角度によってはSWR特性が悪化するため、今後はその対策をテーマとしたい と考えています。

■ 7MHzを中心に、1MHzに亘って測定したSWR特性(SWR値は、目安です)
SDAA_7M


■ 7MHzを中心に、250KHzに亘って測定したSWR特性(SWR値は、目安です)
SDAA_7MW


■ アイコンも作ってみました。

SDAA_Icon

 

99.追記用(予備)