VC++6.0 MFC ダイアログベース
RS232Cの通信用のソフトを作成しています。
受信の書き方(アルゴリズム)についてなのですが、
私の書き方では、受信に時間がかかり、次の送信へのタイミングが
必要以上にかかっているので、改善したいと思っています。
アドバイスよろしくお願い致します。
・ソフトについてですが、
測定器とパソコンで通信を行うソフトで、パソコンは
送信→受信→送信→受信→・・・
と交互に送受信を繰り返す仕様です。
(問題としているのは受信待ち時間が長いところです。)
・考え方ですが、COMMTIMEOUTS構造体でタイムアウト時間を設定して、
タイムアウト時間待ち、データが無かったらタイムアウト処理。
データがあった場合は受信処理を行っています。
・タイムアウト時間を0に設定して、::ReadFile()をwhile文で受信があるまで
ループしておくか・・・ 等、考えているのですが、
どのような考え方が一般的なのでしょうか?
Void CSerial::SetReceiveTimer(void){
COMMTIMEOUTS CommTimeout; //COMMTIMEOUTS構造体の設定
GetCommTimeouts(m_hComm,&CommTimeout);
CommTimeout.ReadIntervalTimeout = 20; // タイムアウトの時間
CommTimeout.ReadTotalTimeoutMultiplier = 10; // 受信1Byteあたりの時間
CommTimeout.ReadTotalTimeoutConstant = 300; // 受信関数コール時間(イ
ンターバル0~250ms)
CommTimeout.WriteTotalTimeoutMultiplier = 10; // 送信1Byteあたりの時間
CommTimeout.WriteTotalTimeoutConstant = 20; // 送信関数コール時間
SetCommTimeouts(m_hComm,&CommTimeout);
}
Void CSerial::Receive(void){
// 受信
::ReadFile(
(HANDLE) m_hComm, // ファイルのハンドル
(LPVOID) pszBuf, // データバッファ
(DWORD) sizeof(pszBuf),// 読み取り対象のバイト数
(LPDWORD) &dwRead, // 読み取ったバイト数
(LPOVERLAPPED) NULL // オーバーラップ構造体のバッファ
);
//受信時間待っても受信データがなかった場合タイムアウトエラー
if (dwRead == NULL){
/*タイムアウトエラー処理*/
}
//////////////
//受信処理
}
追記いたします。
> 受信に時間がかかり、次の送信へのタイミングが
> 必要以上にかかっているので、改善したいと思っています。
受信には、通信速度と受信データ数から計算すると 約11.5ms
必要なのですが、実際は 30ms ほどかかっています。
>・考え方ですが、COMMTIMEOUTS構造体でタイムアウト時間を設定して、
> タイムアウト時間待ち、データが無かったらタイムアウト処理。
> データがあった場合は受信処理を行っています。
それも1つの考え方でいいと思います。
>・タイムアウト時間を0に設定して、::ReadFile()をwhile文で受信があるまで
> ループしておくか・・・ 等、考えているのですが、
「非同期通信にてタイムアウト待ち」というならそれも1つの考え方だと思います。
> (問題としているのは受信待ち時間が長いところです。)
> 受信には、通信速度と受信データ数から計算すると 約11.5ms
> 必要なのですが、実際は 30ms ほどかかっています。
相手の測定器の都合があるので必ずしも計算どおりにはうまくいかないと思います。
ITOさん
返事が遅くなってしまいましたが、ありがとうございます。
>相手の測定器の都合があるので必ずしも計算どおりにはうまくいかないと思います。
どの書き方が私の期待に近い動作をしてくれるのか、
試してみようと思います。
> どの書き方が私の期待に近い動作をしてくれるのか、
> 試してみようと思います。
オシロスコープ等で実際どのぐらい掛かっているのか波形でみてみるのがいいですね。
約11.5ms→30msはRS-232Cの場合誤差範囲だと思います。
実際に30mS掛かるのなら、50mS以上はマージンとっておいたほうがいいですね。
>約11.5ms→30msはRS-232Cの場合誤差範囲だと思います。
>実際に30mS掛かるのなら、50mS以上はマージンとっておいたほうがいいですね。
ボーレートにもよりますね。
38.4K以上の場合はまた話が変わります。
掛かっていると言う時間がReadFileの呼び出し開始から帰ってくるまでの時間なら
純粋な通信時間と言う事にはならないと思いますよ。
読み込む側が読み込み始めたタイミング、もしくはそれ以前にデータの送信が始まって
いるかどうかは受信側ではわからないと思いますし。データが来ている事がわかっていて
受信に行くならわかりもしますけれど、タイムアウトが20ミリ秒ならギリギリタイムアウト
しないタイミングで送信された場合はトータルで30ミリ秒くらい掛かってしまうのではな
いでしょうか。
SetCommMaskとかWaitCommEventを使って受信したタイミングで取りにいくと言うのも
有りではないかと思うんですけれど。
もしかして
> データがあった場合は受信処理を行っています。
というのは、「SetCommMaskとかWaitCommEventを使って受信したタイミングで取りにいく」
事を言ってます?
もしそうなら見当外れのレスでしたね。
ITOさんありがとうございます。
>オシロスコープ等で実際どのぐらい掛かっているのか波形でみてみるのがいいですね。
オシロを持っていないので、波形は見れないのですが、
実際に見て気がつくことありそうですね。
>ボーレートにもよりますね。38.4K以上の場合はまた話が変わります。
ボーレートは計測器に合わせて 19.2~1.2Kbps です。
11.5msは ボーレート 9.6Kbpsで計算しました。
PATIOさんありがとうございます。
>掛かっていると言う時間がReadFileの呼び出し開始から帰ってくるまでの時間なら
>純粋な通信時間と言う事にはならないと思いますよ。
PATIOさんのおっしゃる通り、ReadFile()の呼び出しから、
関数を抜けるまでの時間を言っていました。
DWORD After,Before;
Before = ::GetTickCount(); //ReadFile()前の時間
::ReadFile(m_hComm,pszBuf,sizeof(pszBuf),&dwRead,NULL);
After = GetTickCount(); //ReadFile()後の時間
//後 - 前 = ReadFile()時間
TRACE(受信時間 = %dms \n,After - Before);
>SetCommMaskとかWaitCommEventを使って受信したタイミングで取りにいく」
>事を言ってます?
タイムアウトは
COMMTIMEOUTS CommTimeout; //COMMTIMEOUTS構造体の設定
この構造体完全依存です。危険かな。。
//受信時間待っても受信データがなかった場合タイムアウトエラー
if (dwRead == NULL){
/*タイムアウトエラー処理*/
} else {
/* 受信処理 */
}
PATIOさん、ITOさん。
今日下記のようにReadFile()の呼び出しから、関数をを抜けるまでの時間を見たら、
約30msほどだったと思ったのですが、“約60ms”でした!!
申し訳ございませんでした。
①::ReadFile()直前で、受信バッファのバイト数を見た所 「0バイト」でした。
ReadFile()を呼び出した後、受信が始まっているようでした。
::ClearCommError(m_hComm, &dwErrors, &ComStat);
//受信バッファのバイト数が格納されます。
dwCount=ComStat.cbInQue; //ReadFile直前では 0!!
②CommTimeout.ReadIntervalTimeout = 10/*←20*/; // タイムアウトの時間
20msを10msにした所 ReadFile() に掛かる時間は
60ms ⇒ 50ms になったのですが
CommTimeout.ReadIntervalTimeout = 1/*←20*/; // タイムアウトの時間
で試してみても約50msでした。
誤記です。
>jetT 2007/09/06(木) 15:06:39
>PATIOさん、ITOさん。
>今日下記のようにReadFile()の呼び出しから、関数をを抜けるまでの時間を見たら、
この下記は、この記述の事です。
DWORD After,Before;
Before = ::GetTickCount(); //ReadFile()前の時間
::ReadFile(m_hComm,pszBuf,sizeof(pszBuf),&dwRead,NULL);
After = GetTickCount(); //ReadFile()後の時間
//後 - 前 = ReadFile()時間
TRACE(受信時間 = %dms \n,After - Before);
>SetCommMaskとかWaitCommEventを使って受信したタイミングで取りにいく」
>事を言ってます?
>タイムアウトは
>COMMTIMEOUTS CommTimeout; //COMMTIMEOUTS構造体の設定
>この構造体完全依存です。危険かな。。
質問に対する回答が合っていないし意味不明ですね。申し訳ございません。
受信したタイミングでReadFile()を呼び出していません。
受信前にReadFile()を呼び出して、ここで受信データを待っています。
待つ時間は COMMTIMEOUTS CommTimeout; 構造体に完全に依存しています。
最初の方でITOさんも言われていますけれど、
計測器側の送信タイミングだとかハードウエア的な処理で
送信処理自体が遅いなどの要因まで考えてしまうと理論値通りを期待するのは
少々酷かなと言う気もしますね。
測定機器側の送信所要時間(送信開始から完了までの時間)がボトルネックになって
いるって事は無いですか?
実際にどの程度のスピードで測定機器から出力されているのかがわからないと
単純にインターフェイスの速度とデータ量からだけで計算するのは現実に合っていない
のではないかと思いますけれど。
計測器側(相手側)の設計もjetTさんが関与しているならば、送受信の
タイミングもjetTさんが合わせられますのでかなり計算値に近づけられる
と思います。
計測器側(相手側)の設計が他のメーカの場合、送受信のタイミングは
メーカに依存します。
社外秘出なければ、計測器側(相手側)とはどんなものですか、もしシーケンサー
の場合は中のソフトにも依存します。
実際の送信時間を計るのにオシロスコープを使うというのが出ていますが、サウン
ドカードを一枚潰す覚悟でオシロスコープに使う、というのを試してみてはどうで
しょうか。
その場合、処理開始から送信開始までの時間や受信終了から処理終了まで
の時間を計るためのマーカになる信号を混ぜないといけませんが。
あと、GetTickCountだと精度が低いので、この使い方の場合別の関数のほう
が良いです。
MSDN英語版だと
>Windows NT 3.5 and later
> The system timer runs at approximately 10ms.
>Windows NT 3.1
> The system timer runs at approximately 16ms.
>Windows 95 and later
> The system timer runs at approximately 55ms.
で、最悪55ms誤差が出ます。
良くて10msが保障されているのみなので、ちょっと不味いかと思います…。