トップ回答者
【質問】ハイパーターミナル上の文字データの取り込みについて

質問
-
シリアル通信(受信)を行い、指定された文字列をCOMポートを経由し、
情報をハイパーターミナルやTeraTermに表示するようにする通信機器があります。
表示されたハイパーターミナル上の文字を、
C#などのアプリケーション開発の際にキーとして使用するため、
String変数に格納したいと思います。
SerialPortAPIを使用し、以下のように記述しましたが、
変数に格納できません。
/* 変数の宣言と初期化 */
string res = "";
/* シリアルポートを開く */
SerialPort port = new SerialPort("COM12", 9600, Parity.None, 8, StopBits.One);
port.Open();/* 最後まで読み込む */
res = port.ReadTo("\r");
textBox1.Text = res/* シリアルポートを閉じる */
port.Close();
原因がわかりません。
ソース自体が誤っているのか、何なのかいまだに疑問符です。
ご存知の方がおられましたら知恵をお貸し願えないでしょうか?
回答
-
ポートをOpenした後に、次の2行を加えたらどうなりますか?
Code Snippetport.DtrEnable = True
port.RtsEnable = Trueおそらくは、RS-232CのDTR信号がONにならないために、通信機器からみてPCが接続されていないと判断され、
うまくいかないと思われます。
(アナログモデムでDTRとかERというランプがありますが、あれがOFFになっている状態と考えてください)
# というか、最近ではアナログモデム自体使わないか。
ここから先は余談というかウンチクみたいになるので、読み飛ばしてください。
RS-232Cでは、最低3本の線で接続すれば通信できます。(SD、RD、GND)
ただし、これでは接続相手の機器が接続されているか判断がつきません。
そのためDTR(Data Terminal Ready)という信号線があり、これをONにして機器が接続されている事を知らせます。
あとRTS(Request To Send)ですが、相手機器からみてデータ送信可能だよ、と言う事を知らせます。
-
簡単なターミナルソフトを作っているような感じなので、慣れれば簡単なんですけど、なれないと難しいですね。
根本的な問題としては、通信機器から必ずデータが16バイト+"\r"付きでくる事を期待している部分と、
ReadToやReadLine使う事で、その部分で(データを受信するまで)止まってしまう事だと思います。
通常、こういったシリアルポートを使った通信の場合、以下の方法で通信バッファから変数に格納します。
-
ポーリング方式
ループの中で受信バッファにデータがあるか常にチェックし、データがあれば変数に格納する。 -
割り込みを使う(今で言うイベントみたいなもの)
受信バッファにデータが入ると割り込みが発生し、その中でデータを変数に格納する。
.NETの場合ですが、受信バッファにデータが入ればイベント(昔で言う割り込みですね)が発生するので、
その部分でデータを変数に格納すればいいと思います。
そして変数に格納後、"\r"がなんらかの処理を行うようにすれば良いと思います。
(この部分は、イベント内でなく、イベントから戻ってから行った方が良いかな?)
非同期受信に関しては、以下のサイトが参考になると思います。
http://www.microsoft.com/japan/msdn/netframework/skillup/core/article2.aspx
-
すべての返信
-
これだけの情報では何が問題か判りませんので、考えられる原因を列挙してみます。
変数に格納できないとの事ですが、何らかの例外が発生しているのでしょうか?
COMポートの番号は正しいのでしょうか? また、通信速度等は通信機器と合致しているのでしょうか?
指定したCOMポートは他のアプリケーション(ハイパーターミナルやTeraTerm等)でオープンしていないでしょうか?
情報機器からデータを受信する前に、情報機器に対して何らかの文字列を送信する必要があるのではないでしょうか?
もう少し情報があれば適切な回答が出来ると思います。
(例えばハイパーターミナルやTeraTermを使うときに、どういった操作を行うとか)
# 通信アナライザがあれば原因をつかむのも楽なんだけど。
-
早速のご返答ありがとうございます。
ご説明が不足していたようですので追記させていただきます。
通信機器の通信方式
・RS-232Cで接続する。
・ボーレートは9600bpsで、変更できない。
・8ビットのデータビットを使用する。
・パリティは付与しない
・ストップビットは1bitである。
通信機器の動作
・この機器はICトークンの固有情報(UID)を読み込むとシリアルポートを通してデータを送信する。
・機器がトークンを認識しない限り何もしない
・機器がトークンを認識すると、トークンが離れない限り、1秒間隔でUIDをシリアルポートを通して送信する。
・トークンから離れると送信をやめる。
・UIDの形式は16進数で16桁あり、最後にCRコードを送信する。
問題
・接続するCOMポート番号はデバイスマネージャで確認しており、間違いはない。
・パソコンRS-232Cポートがないため、泣く泣くUSB-Serial変換アダプタを介して接続している。
・作成したプログラムのコンパイルエラーはない。
このような状況です。
-
ポートをOpenした後に、次の2行を加えたらどうなりますか?
Code Snippetport.DtrEnable = True
port.RtsEnable = Trueおそらくは、RS-232CのDTR信号がONにならないために、通信機器からみてPCが接続されていないと判断され、
うまくいかないと思われます。
(アナログモデムでDTRとかERというランプがありますが、あれがOFFになっている状態と考えてください)
# というか、最近ではアナログモデム自体使わないか。
ここから先は余談というかウンチクみたいになるので、読み飛ばしてください。
RS-232Cでは、最低3本の線で接続すれば通信できます。(SD、RD、GND)
ただし、これでは接続相手の機器が接続されているか判断がつきません。
そのためDTR(Data Terminal Ready)という信号線があり、これをONにして機器が接続されている事を知らせます。
あとRTS(Request To Send)ですが、相手機器からみてデータ送信可能だよ、と言う事を知らせます。
-
ご回答ありがとうございました。
余談も大変参考になりました。
DTRとRTSを有効にしてみましたが結果は変わりませんでした。
接続コネクタから機器本体につながっている配線をみてみると、
2本しかつながっていませんでした。
どうやらグランドと送信用の線しか使っていないようです。
あまり望ましくありませんが、
関数内で無限ループをさせてみました。
string Data = "";
while(true)
{
Data = SerialPort1.ReadLine();
if (Data.Length > 16)
{
return;
}}
当然ですが画面が砂時計になり固まりました。
で、if (Data.Length > 16)の位置にブレークポイントを張って、
何回かF5でプログラムを回し、Dataをウォッチウィンドゥで見てみたところ、
何回目かで変数に入りました。
何度か繰り返すと、ブレークポイントで意図的にプログラムを止めて、
何回か回せば変数には入る。
しかしながら意図的にプログラムを止めない限り変数には入らないという理不尽な状態になりました。
変数はグローバル変数でとってあり、
Form_loadイベント内にすべてのプログラムを記述しました。
この状況で、次にすべきことは何なのか、ご教授いただきたく存じます。
無知で申し訳ありません。
-
簡単なターミナルソフトを作っているような感じなので、慣れれば簡単なんですけど、なれないと難しいですね。
根本的な問題としては、通信機器から必ずデータが16バイト+"\r"付きでくる事を期待している部分と、
ReadToやReadLine使う事で、その部分で(データを受信するまで)止まってしまう事だと思います。
通常、こういったシリアルポートを使った通信の場合、以下の方法で通信バッファから変数に格納します。
-
ポーリング方式
ループの中で受信バッファにデータがあるか常にチェックし、データがあれば変数に格納する。 -
割り込みを使う(今で言うイベントみたいなもの)
受信バッファにデータが入ると割り込みが発生し、その中でデータを変数に格納する。
.NETの場合ですが、受信バッファにデータが入ればイベント(昔で言う割り込みですね)が発生するので、
その部分でデータを変数に格納すればいいと思います。
そして変数に格納後、"\r"がなんらかの処理を行うようにすれば良いと思います。
(この部分は、イベント内でなく、イベントから戻ってから行った方が良いかな?)
非同期受信に関しては、以下のサイトが参考になると思います。
http://www.microsoft.com/japan/msdn/netframework/skillup/core/article2.aspx
-