AKI-RS232C ラインモニターキット用モニタソフト 2018/02/23

2018/03/04 Delphi ソースコードを追加
2018/03/03 キット+USB 変換モジュールの画像を追加

秋月電子通商のラインモニタキット (¥3,600)(http://akizukidenshi.com/catalog/g/gK-00045/)用のツールです。

■ FT232RL USB/RS232C 変換モジュール(¥1,400.)(http://akizukidenshi.com/catalog/g/gK-01798/)を合体。パソコンへの接続を USB に変更。
 赤色の配線は、+5V の電源供給です。
 


■ 専用のモニタソフト (Winodws98/95用 )が付属されていますが、自分用に作ってみました。
 付属のモニタソフトと同様に、モニタ表示はリアルタイムではありません。
 「モニタ開始」→「モニタ終了」または1024バイト受信→モニタ結果表示 になります。
 Windows 8.1 (64bit) にて、動作を確認しています。


■ソースコード
 ※シリアル通信には、CPortLib コンポーネントを使っています。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, CPort, Vcl.StdCtrls, Vcl.Grids, CPortCtl,
  IniFiles;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    ComPort1: TComPort;
    Button2: TButton;
    Label1: TLabel;
    Button3: TButton;
    StringGrid1: TStringGrid;
    Button4: TButton;
    ComboBox1: TComboBox;
    Label2: TLabel;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    Label3: TLabel;
    ComComboBox1: TComComboBox;
    Label4: TLabel;
    ComboBox2: TComboBox;
    Label5: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure ComPort1RxChar(Sender: TObject; Count: Integer);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure CheckBox1Click(Sender: TObject);
    procedure CheckBox2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

  TRxData = record
    RxTime : Cardinal;
    RxChar : AnsiChar;
  end;

var
  Form1: TForm1;
  RxDataAry : array of TRxData;
  RxDataCount : integer;
  GTicks : Cardinal;
  GCmdMode : integer;
  GStr : string;
  SeigyoCode : array of string = [
    'NUL', 'SOH', 'STX', 'ETX', 'EOT', 'ENQ', 'ACK', 'BEL', 'BS',  'HT',
    'LF',  'VT',  'FF',  'CR',  'SO',  'SI',  'DLE', 'DC1', 'DC2', 'DC3',
    'DC4', 'NAK', 'SYN', 'ETB', 'CAN', 'EM',  'SUB', 'ESC',  'FS', 'GS',
    'RS',  'US'];

const
  DEL = $7E;
  
implementation

{$R *.dfm}

function Ratemesure: string;
var
  DataCount : integer;
  Baud : array [0..99] of integer;
  m, n : integer;
  BaudRate : integer;
  bps : string;
begin
  result := '';
  if GStr.Length > 100 then begin
    DataCount := GStr.Length;
    m :=0;
    for n := 0 to DataCount div 2 - 1 do begin
      Baud[m] := Ord(GStr[n * 2 + 2]);
      Baud[m] := Baud[m] * 256;
      Baud[m] := Baud[m] + Ord(GStr[n * 2 + 1]) + 15;
      Baud[m] := Trunc(Baud[m] * 108.459); // nsec 108.459=1/9.22MHz
      Inc(m);
      if m = 100 then Break;
    end;
    BaudRate := 5000000; // nsec
    for n := 0 to 50 -1 do begin
      if Baud[n] <> 0  then begin
        if Baud[n] < BaudRate then BaudRate := Baud[n];
      end;
    end;

    if      (3333332 * 0.85 < BaudRate) and (BaudRate < 3333332 * 1.15) then bps :=   '300bps'
    else if (1666666 * 0.85 < BaudRate) and (BaudRate < 1666666 * 1.15) then bps :=   '600bps'
    else if ( 833333 * 0.85 < BaudRate) and (BaudRate <  833333 * 1.15) then bps :=   '1200bps'
    else if ( 416666 * 0.85 < BaudRate) and (BaudRate <  416666 * 1.15) then bps :=   '2400bps'
    else if ( 208332 * 0.85 < BaudRate) and (BaudRate <  208332 * 1.15) then bps :=   '4800bps'
    else if ( 104166 * 0.85 < BaudRate) and (BaudRate <  104166 * 1.15) then bps :=   '9600bps'
    else if (  69444 * 0.85 < BaudRate) and (BaudRate <   69444 * 1.15) then bps :=  '14400bps'
    else if (  52083 * 0.85 < BaudRate) and (BaudRate <   52083 * 1.15) then bps :=  '19200bps'
    else if (  34722 * 0.85 < BaudRate) and (BaudRate <   34722 * 1.15) then bps :=   '28800ps'
    else if (  26041 * 0.85 < BaudRate) and (BaudRate <   26041 * 1.15) then bps :=  '38400bps'
    else if (  17361 * 0.85 < BaudRate) and (BaudRate <   17361 * 1.15) then bps :=  '57600bps'
    else if (   8680 * 0.85 < BaudRate) and (BaudRate <    8680 * 1.15) then bps := '115200bps'
    else if (   4340 * 0.85 < BaudRate) and (BaudRate <    4340 * 1.15) then bps := '230400bps'
    else if (   2170 * 0.85 < BaudRate) and (BaudRate <    2170 * 1.15) then bps := '460800bps'
    else if (   1085 * 0.85 < BaudRate) and (BaudRate <    1085 * 1.15) then bps := '921600bps';
    result := bps;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  str : string;
  i, j :integer;
begin
  with ComPort1 do begin
    BaudRate:= br115200;
    DataBits := dbEight;
    StopBits := sbOneStopBit;
    Open;
    if Connected then begin
      if ComboBox1.ItemIndex >= 0 then begin
        Button1.Enabled := False;
        Button2.Enabled := True;
        Button3.Enabled := False;

        WriteStr(ComboBox1.ItemIndex.Tostring); // 9600bps
        Sleep(100);
        WriteStr('V');
        Sleep(100);
        ReadStr(str, 1024);
        Edit1.Text := str;

        if CheckBox1.Checked then
          WriteStr('d')
        else
          WriteStr('D');
        Sleep(100);
        case ComboBox2.ItemIndex of
          0 : WriteStr('G'); // 双方向
          1 : WriteStr('A');
          2 : WriteStr('B');
        end;

        with StringGrid1 do begin
          for i := 1 to ColCount -1 do begin
            for j := 0 to RowCount - 1 do begin
              Cells[i, j] := '';
            end;
          end;
        end;
        RxDataCount := 0;
        GTicks := GetTickCount;
      end;
    end;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if ComPort1.Connected then begin
    Button1.Enabled := True;
    Button2.Enabled := False;
    Button3.Enabled := True;

    ComPort1.WriteStr('E');
    if GCmdMode = 0 then
      Button3Click(self);
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  i : integer;
  n, m : integer;
  c : AnsiChar;
  j : integer;
  k : integer;
begin
  j := 1;
  for i := 0 to RxDataCount div 2 -1 do begin
    if RxDataAry[i*2].RxTime - GTicks >= 200 then begin
      StringGrid1.Cells[j, 1] := IntToStr(RxDataAry[i*2].RxTime - GTicks);
      GTicks := RxDataAry[i*2].RxTime;
      StringGrid1.ColCount := StringGrid1.ColCount + 1;
      Inc(j);
    end;
    n := Ord(RxDataAry[i * 2].RxChar);
    m := Ord(RxDataAry[i * 2 + 1].RxChar);
    if (n shr 4 = $A)  and (m shr 4 = $B) then begin
      c := AnsiChar(n shl 4 + m and $0F);
      k := Ord(c);
      with StringGrid1 do begin
        Cells[j, 2] := IntToHex(Ord(c), 2);
        if k < $20 then
          Cells[j, 3] := SeigyoCode[Ord(c)]
        else if k = DEL then
          Cells[j, 3] := 'DEL'
        else if k < DEL then
          Cells[j, 3] := string(c)
        else
          Cells[j, 3] := '.';
        Cells[j, 0] := IntToStr(i+1);
      end;
      Inc(j);
    end
    else if (n shr 4 = $8)  and (m shr 4 = $9) then begin
      c := AnsiChar(n shl 4 + m and $0F);
      k := Ord(c);
      with StringGrid1 do begin
        Cells[j, 4] := IntToHex(Ord(c), 2);
        if k < $20 then
          Cells[j, 5] := SeigyoCode[Ord(c)]
        else if k = DEL then
          Cells[j, 5] := 'DEL'
        else if k < DEL then
          Cells[j, 5] := string(c)
        else
          Cells[j, 5] := '.';
        Cells[j, 0] := IntToStr(i+1);
      end;
      Inc(j);
    end;
  end;
end;

procedure TForm1.Button4Click(Sender: TObject);
var
  str : string;
begin
  with ComPort1 do begin
    if Button4.Caption <> '計測中止' then begin
      if Button1.Enabled then begin
        BaudRate := br115200;
        DataBits := dbEight;
        StopBits := sbOneStopBit;
        Open;
        if Connected then begin
          Button1.Enabled := False;
          Label1.Caption := 'ボーレート計測中...';
          Button4.Caption := '計測中止';

          WriteStr('V');
          Sleep(100);
          ReadStr(str, 1024);
          Edit1.Text := str;

          RxDataCount := 0;
          GStr := '';
          WriteStr('M'); //
          GCmdMode := 101;
        end;
      end;
    end
    else begin
      if Connected then begin
        WriteStr('E');
        GCmdMode := 0;
        Label1.Caption := 'ボーレート計測中止';
        Button4.Caption := 'ボーレート計測';
        Button1.Enabled := True;
      end;
    end;
  end;
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  CheckBox2.Checked := not CheckBox1.Checked;
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
  CheckBox1.Checked := not CheckBox2.Checked;
end;

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var
  str : string;
  i : integer;
  Ticks : Cardinal;
begin
  ComPort1.ReadStr(str, Count);
  if GCmdMode = 101 then begin
    GStr := GStr + str;
    Label1.Caption := IntToStr(RxDataCount);
    RxDataCount := RxDataCount + str.Length;
    if RxDataCount > 100 then begin
      Label1.Caption := IntToStr(RxDataCount);
      ComPort1.WriteStr('E');
      GCmdMode := 0;
      ShowMessage(Ratemesure);
      Label1.Caption := Ratemesure;
      Button4.Caption := 'ボーレート計測';
      Button1.Enabled := True;
    end;
  end
  else begin
    Ticks := GetTickCount;
    if RxDataCount < 1024 then begin
      Label1.Caption := IntToStr(RxDataCount);
      for i := 1 to str.Length do begin
        RxDataAry[RxDataCount].RxTime := Ticks;
        RxDataAry[RxDataCount].RxChar := AnsiChar(str[i]);
        Inc(RxDataCount);
        if RxDataCount >= 1024 then begin
          Label1.Caption := IntToStr(RxDataCount);
          Button3.Enabled := True;
          Button2Click(self);
          Break;
        end;
      end;
    end;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
  ini : TIniFile;
begin
  Comport1.StoreSettings(TStoreType.stIniFile, ChangeFileExt(ParamStr(0), '.ini'));
  ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
  try
    with StringGrid1 do begin
      ini.WriteInteger('StringGrid', 'ColWidth', DefaultColWidth);
      ini.WriteInteger('StringGrid', 'RowHeight', DefaultRowHeight);
    end;
    ini.WriteBool('CheckBox', '8Bit', CheckBox1.Checked);
    ini.WriteBool('CheckBox', '8+1Bit', CheckBox2.Checked);
    ini.WriteInteger('ComboBox', 'MoniBaudRate', ComboBox1.ItemIndex);
    ini.WriteInteger('ComboBox', 'MoniHoukou', ComboBox2.ItemIndex);
  finally
    ini.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  ini : TIniFile;
begin
  Setlength(RxDataAry, 1024);
  RxDataCount := 0;
  Edit1.Text := '';
  Label1.Caption := '';

  Comport1.LoadSettings(TStoreType.stIniFile, ChangeFileExt(ParamStr(0), '.ini'));
  ComComboBox1.Text := ComPort1.Port;

  ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
  try
    with StringGrid1 do begin
      DefaultColWidth := ini.ReadInteger('StringGrid', 'ColWidth', DefaultColWidth);
      DefaultRowHeight := ini.ReadInteger('StringGrid', 'RowHeight', DefaultRowHeight);
    end;
    CheckBox1.Checked := ini.ReadBool('CheckBox', '8Bit',True);
    CheckBox2.Checked := ini.ReadBool('CheckBox', '8+1Bit',False);
    ComboBox1.ItemIndex := ini.ReadInteger('ComboBox', 'MoniBaudRate', 4);
    ComboBox2.ItemIndex := ini.ReadInteger('ComboBox', 'MoniHoukou', 0);

  finally
    ini.Free;
  end;
end;

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  ARect,BRect : TRect;
  s : string;
  n : integer;
begin
  ARect := Rect;
  BRect := Rect;

  ARect.Top := Rect.Top + 1;
  ARect.Bottom := Rect.Bottom - 1;
  ARect.Left := Rect.Left;
  ARect.Right := Rect.Right - 1;

  BRect.Top := Rect.Top + 5;
  BRect.Bottom := Rect.Bottom - 1;
  BRect.Left := Rect.Left+1;
  BRect.Right := Rect.Right - 1;

  with StringGrid1 do begin
    if (ARow = 0) or (ACol = 0) then begin
        if ((ARow = 2) or (ARow = 3)) and (ACol = 0) then begin
          Canvas.Brush.Color := clLime;//$00D6D6D6;
          Canvas.Pen.Color := clWhite;//Green;//Black;
          Canvas.RoundRect(ARect.Left,ARect.Top,ARect.Right,ARect.Bottom,8,8);
          Canvas.Font.Height := 16;
          Canvas.Font.Color := clBlack;
        end
        else if ((ARow = 4) or (ARow = 5)) and (ACol = 0) then begin
          Canvas.Brush.Color := clSkyBlue;//Aqua;//$00D6D6D6;
          Canvas.Pen.Color := clWhite;//Blue;//Black;
          Canvas.RoundRect(ARect.Left,ARect.Top,ARect.Right,AREct.Bottom,8,8);
          Canvas.Font.Height := 16;
          Canvas.Font.Color := clBlack;
        end
        else if (ARow = 1) and (ACol = 0) then begin
          Canvas.Brush.Color := clBtnFace;
          Canvas.Pen.Color := clWhite;//Blue;//Black;
          Canvas.RoundRect(ARect.Left,ARect.Top,ARect.Right,AREct.Bottom,8,8);
          Canvas.Font.Height := 16;
          Canvas.Font.Color := clBlack;
        end
        else begin
          Canvas.Brush.Color := clBtnFace;//$00D6D6D6;
          Canvas.FillRect(Rect);
          Canvas.Font.Height := 13;
          Canvas.Font.Color := clGray;
        end;

        DrawText(Canvas.Handle, PChar(Cells[ACol,ARow]),
                   Length(Cells[ACol,ARow]),
                   BRect, DT_CENTER); // DT_CENTERがセンタリング指定
    end
    else begin
      if (ARow = 1) and (ACol > 0) then begin
        s := Cells[ACol, ARow];
        if s <> '' then begin
          Canvas.Brush.Color := clSilver;
          Canvas.FillRect(ARect);
          Canvas.Font.Height := 13;
          Canvas.Font.Color := clBlack;
          Canvas.TextOut(ARect.Left+1,ARect.Top+3, Cells[ACol,ARow]);
        end;
      end
      else if (ARow = 3) and (ACol > 0) then begin
        s := Cells[ACol, 2];
        if s <> '' then begin
          n := StrToInt('$'+ s);
          if (n < $20) or (n = DEL) then begin
            Canvas.Brush.Color := clRed;
            Canvas.FillRect(ARect);
            Canvas.Font.Color := clWhite;
          end
          else if (n > DEL) then begin
            Canvas.Brush.Color := clYellow;
            Canvas.FillRect(ARect);
          end
          else begin
            Canvas.Brush.Color := $0000FF80;//clGreen;//clMoneyGreen;//Lime;
            Canvas.FillRect(ARect);
          end;
          DrawText(Canvas.Handle, PChar(Cells[ACol,ARow]),
                     Length(Cells[ACol,ARow]),
                     BRect, DT_CENTER); // DT_CENTERがセンタリング指定
        end;
      end
      else if (ARow = 5) and (ACol > 0) then begin
        s := Cells[ACol, 4];
        if s <> '' then begin
          n := StrToInt('$'+ s);
          if (n < $20) or (n = DEL) then begin
            Canvas.Brush.Color := clRed;
            Canvas.FillRect(ARect);
            Canvas.Font.Color := clWhite;
          end
          else if (n > DEL) then begin
            Canvas.Brush.Color := clYellow;
            Canvas.FillRect(ARect);
          end
          else begin
            Canvas.Brush.Color := clSkyBlue;//Aqua;
            Canvas.FillRect(ARect);
          end;
          DrawText(Canvas.Handle, PChar(Cells[ACol,ARow]),
                     Length(Cells[ACol,ARow]),
                     BRect, DT_CENTER); // DT_CENTERがセンタリング指定
        end;
      end;
    end;
  end;
end;

end.

■開発環境
 Delphi 10.1 Professional / Windows 8.1 (64bit)

■ダウンロード
 ダウンロード(EXE本体のみ)
 ※アイコンは、作成していません。Delphi デフォルトのままです。