プロが教えるわが家の防犯対策術!

はじめまして。
C++Builderの6.0で開発をしているものですが、現在、シリアル通信のモジュールを作成していて、ReadFileを用いて受信側の処理を行っています。ですがステップ実行させてみるとReadFile処理時のCPU使用率が100%になってしまいます。一方、送信のWriteFileではCPU使用率は上がりません。この現象について解決策があれば教えてください。

よろしくお願いします。

A 回答 (2件)

一般にシリアルからの入力は、入力自体が割り込みを起こすのでReadFileは入力データが到達するまでの間はCPUを占有しません。



よって、ReadFileがCPUをつかんでループしてしまう状況(この状況をスピンといいます)の発生要因としては
・シリアル入力のドライバがおかしい
・設定がおかしい
という可能性が高いと思われます。

シリアルポートのデバイスが何であるか?
ドライバは何を使っていて、どういう常態か?
設定はどうなっているか?
いろいろと不明なので自信はありません。

この回答への補足

toysmithさん

回答が遅くなってしまい、申し訳ありません。
こちらの環境及び設定内容を補足致します。
(1)環境
エンジン基板に対してRS232CのストレートケーブルでノートPCと接続

(2)設定内容
DCB構造体の設定
dcb.BaudRate = 57600;
dcb.ByteSize = 8;
dcb.Parity = parity; // NOPARITY:0
dcb.fParity = (parity) ? TRUE : FALSE;

タイムアウトの設定
tout.ReadTotalTimeoutMultiplier = 1;
tout.WriteTotalTimeoutMultiplier = 1;
tout.ReadIntervalTimeout = 2000;
tout.ReadTotalTimeoutConstant = 2000;
tout.WriteTotalTimeoutConstant = 2000;

補足日時:2006/03/06 09:49
    • good
    • 0

C++Builderは使ったことがないので、ReadFileの仕様は知りませんが・・・



「ReadFileを使ってシリアルポートからデータを読み出している」と捉えて宜しいのでしょうか?

ReadFileはおそらくポートにデータが届いていることを前提に読み出すような使い方をするものだと思います。つまり、ポートにデータが届いていなければ、データが届くまでループするのではないでしょうか。

昔、シリアル用のDOSプログラムをCで作っていましたが、Readの割り込みをかけるとポートからデータを読み取れるまで他の割り込みを受け付けてくれず、ハングアップしたような状態になったのを覚えています。

eofのような関数は無いでしょうか?ファイルに読み込めるデータが残っているか否かをチェックする関数です。仮にeof関数と呼びます。eof関数があれば、それを使ってポートにデータが届いているか否かをチェックし、届いていたら届いている分だけ受信するようにReadFile文を書き換えてみてはどうでしょう。

eof関数はループで何度も呼び出しますが、1回呼び出すごとに、データが無ければSleepを0.1秒入れるようにしてみてください。データがあれば連続してeof関数を呼び出します。

このように、データの着信チェックを0.1秒間隔に入れ、着信したらReadFileで取り込むというようにすれば、100%になることは無いと思います。

C++Builderは使ったことがないので自信はありませんが・・・。Windowsのようなマルチスレッド、マルチプロセスのOSでは、Sleepを入れてCPUを開放するのは常套手段です。

この回答への補足

etaroさん

回答が遅くなってしまい、申し訳ありません。
処理としてはetaroさんが言うとおり、「ReadFileを使ってシリアルポートからデータを読み出している」という形です。

現在のモジュールを簡略化してみました。
void DataSend()
{
// ポートオープン処理(DCB,タイムアウトの設定も含む)
if (!comm->Open()) return;

// データ送信
for (i = 0; i < DataSize; i++) // 転送データサイズ分
{
  // プログラムイメージ送信(1バイトデータ)
  if (!comm->Write(Data, 1)) // Data:1バイトデータ
  {
    comm->Close(); // ポートクローズ
    return;
  }

  // echo受信
  if (comm->Read(&rcv, 1) == -1)
  {
    switch (comm->errorno)
    {
     case TIMEOUT_ERR:
       break;
     case PORT_ERR:
       break;
     default:
       break;
    }
    comm->Close();
    return;
  }

  // echo判定
  if (rcv != Data)
  {
    comm->Close();
    return;
  }
}

//////////////////////////////////////////
int Read(char *buf, unsigned long len)
{
  BOOL res;
  DWORD receive;

  if (hcomm == INVALID_HANDLE_VALUE)
  {
    errorno = PORT_ERR;
    return -1;
  }
  // 受信処理
  if (!ReadFile(hcomm, buf, len, &receive, NULL))
  {
    errorno = PORT_ERR;
    return -1;
  }
  // 受信判定
  if (receive == 0)
  {
    errorno = TIMEOUT_ERR;
    return -1;
  }

  errorno = NO_ERR;
  return receive;
}

このような処理になっています。

補足日時:2006/03/06 10:31
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!