RS-232C

アバター
tana
記事: 33
登録日時: 14年前

RS-232C

投稿記事 by tana » 13年前

先に断っておきます。
自分はゲームプログラミングとは全く関係ないことをやっています!
専門はハード屋さんですから!

今はハードウェアと通信を行い、データのサンプリング、変換までをHWで行い、結果をPCに送るというシンプルな制御ソフトを作っています。
んで、そのためにRS-232Cを使ったシリアル通信を行っています。
ポートオープンからクローズまで、ユーザーが想定外の操作をできないよう、ありとあらゆる誤操作の要因を潰せたのはよかったのですが、
そこでまったく予想していなかったバグに遭遇。

ポートオープンが成功しない。
ポートオープンしてから、HW側に制御信号を送信し、HWからの応答を受け取って初めてポートオープン成功と判断するように
プログラムを組んだはずが、なぜかHWに制御信号が届いていないという事態に。
C++を触るのは久しぶりかつほぼ初心者なので、出来る限りシンプルに作ったはずが、なぜか動かない。
HW側のバグかとも思い検証するも、それらしき箇所は見当たらない。
で、いよいよ面倒になったので、ターミナルソフトを使っての検証を行うと、こちらは上手くいく。
そうなると結局は制御プログラムが間違ってるという結論に至る。
また厄介なことに、ターミナルソフトを使った後ならなぜかポートオープンが成功するという罠。

で、原因をとことん検証した結果、以下のポートオープン関数に問題がありました。

CODE:

bool ComPortCtrl::ComPortOpen(LPCTSTR portNum, int brs)
{
	if (portNum==NULL)
		return false;

	//
	//シリアル通信設定
	//
	dcb.DCBlength = sizeof(DCB);	//DCB構造体の長さ

	//ポートの取得
	hPort = CreateFile(portNum,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

	if(hPort == INVALID_HANDLE_VALUE){
		return false;
	}

	//バッファの設定
	if(!SetupComm(hPort,BUFFSIZE,BUFFSIZE))
		return false;

	GetCommState(hPort,&dcb);

	//通信条件設定
	dcb.BaudRate = brs;		//伝送速度
	dcb.fBinary = true;		//バイナリモード
	dcb.ByteSize = COMBITSIZE;		//データサイズ
	dcb.fParity = NOPARITY;	//パリティの有無
	dcb.StopBits = ONESTOPBIT;	//ストップビット数

	//ハードウェアフロー制御
	dcb.fOutxCtsFlow = false;		//CTSハードウェアフロー制御
	dcb.fOutxDsrFlow = false;		//DSRハードウェアフロー制御
	dcb.fDtrControl = DTR_CONTROL_DISABLE;		//DTR制御
	dcb.fRtsControl = RTS_CONTROL_DISABLE;		//RTS制御

	//ソフトウェアフロー制御
	dcb.fOutX = false;
	dcb.fInX = false;
	dcb.fTXContinueOnXoff = true;
	dcb.XonLim = 512;
	dcb.XoffLim = 512;
	dcb.XonChar = 0x11;
	dcb.XoffChar = 0x13;

	//Others
	dcb.fNull = true;
	dcb.fAbortOnError = true;
	dcb.fErrorChar = false;
	dcb.ErrorChar = 0x00;
	dcb.EofChar = 0x03;
	dcb.EvtChar = 0x02;

	//タイムアウト時間設定
	timeout.ReadIntervalTimeout = 500;	//タイムアウト時間:500msec
	timeout.ReadTotalTimeoutMultiplier = 0;	//一文字辺りの読込み時間
	timeout.ReadTotalTimeoutConstant = 500;	//エラー検出用タイムアウト時間:500msec

	timeout.WriteTotalTimeoutMultiplier = 0;	//一文字辺りの書込み時間
	timeout.WriteTotalTimeoutConstant = 500;	//エラー検出用タイムアウト時間:500msec

	if(!SetCommTimeouts(hPort,&timeout))
		return false;

	if(!PurgeComm(hPort,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR))
		return false;

	return true;
}
実はとても初歩的なミスをしていて、>というコメントの上に

CODE:

if(!SetCommState(hPort,&dcb))
return false;
を書いておかなければいけなかったんです。
厳密に言えば、SetCommState()処理ですね。
これやらないと、通信速度とかの諸々の設定が反映されないという。

このバグのために丸二日を費やしてしまったことを反省せねばなりません。
ターミナルソフトで通信できた後なら、ターミナルの設定が反映された後なんで動くわけです。
実はいよいよ今日やっていてダメだったら、こちらの掲示板で聞くつもりでした。
こんな下らないミスを指摘されていたら恥ずかしくて悶え死んでいましたねww


HWとSWの両方を自作するとなると色々問題が出てくるので、なにが原因なのか突き止めるのが大変なんですが、
後の自分のために、こんなこともあるよという経験を日記にして残しておきたいと思います。以上!

コメントはまだありません。