技術担当:服部
製品及び開発品に関わるお問い合わせはお問い合わせフォームか次のメールアドレスにご連絡ください。
新着情報
(平成30年3月28日時点)
① PDAT2型最新版ソフトウエア
最新版V1.4のインストーラと概要説明書をアップしました。
② PDATシリーズ情報を更新
製造データ自動転送無線ネットワークシステムPDAT1型の詳細をアップデートしました。
③ PDMSシリーズ情報の更新
マイコン搭載型測定子機の試作品情報を掲載致しました。
製品販売に付いて
最新のソフトウエア
最新版をダウンロードする
最新の技術資料
最新版をダウンロードする
品質保証と製造物責任
ここでは主にコンピュータと親機との通信に係わるソフトウエアについてご紹介致します。このソフトウエアを検証する際にはコンピュータと有線通信が確率された親機(ベース設定された無線モジュール)が必要になります。
親機とコンピュータ間の通信にはコンピュータと子機間の通信も含まれますが、ここでは純粋にコンピュータと親機間の通信に限って説明致します。コンピュータ上で使用する言語はC#としました。
RFEM2400/LPR2430ERAの通信ファームウエアを用いて通信を行おうとする場合、LPRDemo2を用いて最初からProtocolModeに設定しておくことをお勧め致します。また、SoftwareResetも電源投入時には初期化が行われるので、改めて行う必要は御座いません。唯一必要なのは通信ファームウエアがハングアップした時ですが、無線モジュール自体が通信を受付なくなる為、SoftwareReset命令を送っても、実行されません。
ここでは親機とコンピュータ間のデータの遣り取りを行う次の2命令について紹介致します。
GetRegister 0X03 親機保有のレジスター値を読み出す
SetRegister 0X04 親機保有のレジスターに新しい数値を書き込む
親機のバンク及びレジスター構成は子機のそれと同じです。従って親機のレジスターにアクセスする場合は子機の場合と同じになります。但し、親機は有線通信でコンピュータと繋がっている為、ネットワークアドレスは不用です。従って、パケットの文字列構成は次の様になります。
[SOP][長さ][通信番号][命令][付帯情報]
親機に名前を設定する場合は
byte Reg = 0X1C; // UsetTag
byte Bank = 0X00; // 第0バンク
byte Span = 0X04; // 4文字の場合
通信番号は0X00、長さは9バイト(11-2)
[0XFB][0X09][0X00][0X04][0X1C][0X00][0X04]['B']['a']['s']['e']
となります。このパケットを親機に送ると親機から次の返信があります。
[0XFB][0X02][0X00][0X14]
これで親機の名前が"Base"に変更になりました。
今度は親機の名前を呼び出してみましょう。読み出しの構文は
[0XFB][0X05][0X01][0X03][0X1C][0X00][0X04] となります。この時、通信番号は変えましょう。ここでは+1の0X01にしてあります。
親機からの返信は
[0XFB][0X09][0X00][0X13][0X1C][0X00][0X04]['B']['a']['s']['e']
となります。後は['B']以降の文字を読んで、文字列にすれば完了します。
市販のUSB素子を使用した場合、仮想COMポートでUSB通信を行うことになります。仮想COMポートはRS232C通信と同じ方式でUSB通信を行う方法です。この方法でUSB通信を行うには先ず仮想COMポートを開くところから始まります。次は一例です。
using System.IO;
using System.IO.Ports;
定数を定義します
const int Buffer_Wait_Time = 10;
const byte SOP = 0XFB;
const int Max_BufferLength = 256;
構造体を定義します。
// Virtual Com Port Type
public struct VirtualComport_Type
{
// PC側の値
public BaudRate Baud_Rate;
public Parity Parity;
public int Data_Bits;
public StopBits StopBits;
// Base側の値
public SerialRate SerialRate;
public SerialParam ParityStop;
}
変数を定義します
public bool received = false;
public bool connected = false;
public bool SOP_Detected = false;
public int Receive_Buffer_Length = 0;
public string comPortName = "COM1";
public static SerialPort port = new SerialPort();
public static VirtualComport_Type VirtualComport;
public static byte[] USB_Receive_Buffer = new byte[Max_BufferLength];
ここからはCOMPortを開くルチーンです。
///<summary>
/// 通信ポートをオープンする
/// 自動受信あり
/// 戻り値:開けた場合はTRUE
///</summary>
public static bool ComPort_Open()
{
bool okay = false;
try
{
// COMPortの削除
port.Dispose();
// 開始
port = new SerialPort(comPortName, (int)VirtualComport.Baud_Rate, VirtualComport.Parity, VirtualComport.Data_Bits,
VirtualComport.StopBits);
port.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
port.ErrorReceived += new SerialErrorReceivedEventHandler(port_ErrorReceived);
port.Disposed += new EventHandler(Port_Disposed);
port.Open();
port.DiscardOutBuffer();
port.RtsEnable = false;
okay = true;
}
catch (Exception)
{
}
return okay;
}
この場合USB回路が受信した時に受信割込みルチーンport_ErrorReceivedが必要になります。
/// <summary>
/// 自動受信にイベントハンドラー
/// 戻り値:無し
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
SerialPort port = (SerialPort)sender;
// 待ち時間
Thread.Sleep(Buffer_Wait_Time);
// 読み出し開始
do
{
byte Temp = (byte)port.ReadByte();
if (Temp == SOP)
{
Receive_Buffer_Length = 0;
USB_Receive_Buffer = new byte[Data_Buffer_Size];
SOP_Detected = true;
}
USB_Receive_Buffer[Receive_Buffer_Length++] = Temp;
}
while (port.BytesToRead > 0) ;
// Detecting SOP is start
if (SOP_Detected)
{
if (Receive_Buffer_Length>1)
{
int TempLength = USB_Receive_Buffer[1]; // パケットの長さ
if (Receive_Buffer_Length > TempLength + 1) // Receiving.Lengthが4以上
{
// 受信終了
Done = true;
// 受信した
received = true;
}
}
}
}
catch (Exception)
{
SOP_Detected = false;
Done = false;
received = false;
}
}
このイベントハンドラーではSOP(0XFB)が到来すると文字をバッファーに書き込みを始め、TempLengthまで読むと読みを終了します。この後は処理又は次の読みルチーンに入ります。
/// <summary>
/// エラーを受信した場合
/// </summary>
/// <param name="Sender"></param>
/// <param name="e"></param>
private static void port_ErrorReceived(object Sender, SerialErrorReceivedEventArgs e)
{
SerialPort port = (SerialPort)Sender;
port.DiscardInBuffer();
SOP_Detected = false;
Done = true;
received = false;
}
因ってUSB_Receive_Bufferの中には受信したデータが、変数receivedは受信が完了したか否かの情報が格納されています。従って、受信イベントルチーンの最後に受信データに解析ルチーンを設けるれば処理が完了します。
一度オープンしたCOMPortは必ずClose及びDisposeしてください。開いたままにしておくとソフトウエアが終了してもCOMPortが開いたままになってしまいます。
///<summary>
/// 通信ポートをクローズする
/// delayは閉じる迄の待ち時間
/// 戻り値:なし
///</summary>
public static bool ComPort_Close()
{
try
{
port.Disposed -= new EventHandler(Port_Disposed);
if (port.IsOpen) port.Close();
port.Dispose();
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// ポートが無くなった場合
/// </summary>
/// <param name="Sender"></param>
/// <param name="e"></param>
private static void Port_Disposed(object Sender, EventArgs e)
{
SerialPort port = (SerialPort)Sender;
try
{
port.Dispose();
Thread.Sleep(100);
port = new SerialPort(comPortName, (int)VirtualComport.Baud_Rate, VirtualComport.Parity, VirtualComport.Data_Bits, VirtualComport.StopBits);
port.Open();
port.RtsEnable = false;
connected = true;
}
catch (Exception)
{
connected = false;
}
}
親機に命令を送るパケットは子機用のそれと非常に似通っていますが、一番大きな違いは子機用にはネットワークアドレスが付加されるのに対して親機用にはネットワークアドレスが不要です。
次は一例です。親機のUserTagを”Base"に変更するパケットです。
const int Max_BufferLength = 20;
int BufferLength = 9;
byte[] SendBuffer = new byte[Max_BufferLength]; // Max_BufferLengthは長めに設定
SendBuffer[0] = 0XFB; // SOP
SendBuffer[1] = 0X09; // パケットの長さ
SendBuffer[2] = 0X00; // 通信番号
SendBuffer[3] = 0X04; // 命令(Set Register)
SendBuffer[4] = 0X1C; // Bankの番号(UserTag)
SendBuffer[5] = 0X00; // Registerの番号(UserTag)
SendBuffer[6] = 0X04; // Spanの番号(名前文字列の長さ
SendBuffer[7] = 'B'; // 名前第1文字
SendBuffer[8] = 'a'; // 名前第2文字
SendBuffer[9] = 's'; // 名前第3文字
SendBuffer[10] = 'e'; // 名前第4文字
これでパケットは出来上がりです。後はこれをUSB回線に流します。
次に示す送信ルチーンは親機用及び子機用としても使えます。
///<summary>
/// 命令を送信する → ポートは開いている事が条件
///</summary>
public static bool Send_Command()
{
bool sent = false;
// 送った信号の履歴
received = false;
if (connected)
{
try
{
// 受信指標の初期化
received = false;
// portが開いていない時は開く
port.DiscardOutBuffer();
// 送信
port.Write(Send_Buffer, 0, Parameter.BufferLength);
// 送信終了
sent = true;
}
catch (Exception)
{
sent = false;
}
}
return sent;
}
これで親機にパケットが送信されました。親機からは返信がありますが、受信イベントルチーンが親機からのパケットをキャッチしてくれます。