ページ 11

RS-485でシリアル通信をしたい

Posted: 2012年1月05日(木) 18:50
by tktkm
はじめまして、tktkmと申します。
私はRS-485でシリアル通信を行うプログラムを書いたのですが、通信がうまくできません。
通信先にあるコマンドを送信すると、それに対する答えを返してくるはずなのですが受信できないのです。
環境はWindowsXP,VisualC++ 6.0を使用しております。
コードは以下の通りです。

コード:

#include <stdio.h>
#include <tchar.h>
#include <afxwin.h>
#include <conio.h>

int funcexit(HANDLE fehandle)
{
	CloseHandle( fehandle );
	printf("Abort End\n");
	exit(0);
	return 0;
}

int main(void)
{

	/*****************************************************
	変数宣言
	*****************************************************/

	HANDLE hPort;
	BOOL Ret;
	DCB dcb;
	COMMTIMEOUTS timeout;
	int MAX = 1024;
	char bSendBuffer[11];
	DWORD dwSendSize;
	DWORD dwErrorMask;
	COMSTAT Comstat;
	unsigned int DataSize;
	char In[12];
	DWORD IRead;
	int kbjudge;
	int i;

	/*****************************************************
	シリアル通信
	*****************************************************/

	//ポートのハンドルを取得
	hPort = CreateFile( _T("COM3"),			//ポート名
			GENERIC_READ | GENERIC_WRITE,	//アクセスモード
			0,								//共有モード(共有しない)
			NULL,							//セキリュティ記述子
			OPEN_EXISTING,					//作成方法(ファイルがあれば開く)
			FILE_ATTRIBUTE_NORMAL,			//ファイル属性
			NULL );							//テンプレートファイルのハンドル
	//成否判定メッセージ
	if( hPort == INVALID_HANDLE_VALUE)
	{
		printf("CreateFile Error\n");
		exit(0);
	}
	printf("CreateFile OK\n");

	Ret = SetupComm( hPort, 1024, MAX );
	//成否判定メッセージ
	if( Ret == FALSE )
	{
		printf("SetupComm Error");
		funcexit( hPort );
	}
	printf("SetupComm OK\n");

	dcb.DCBlength = sizeof(DCB);			//構造体の大きさ
	dcb.BaudRate = 921600;					//ボーレート
	dcb.fBinary = TRUE;						//バイナリーモード
	dcb.ByteSize = 8;						//バイトサイズ
	dcb.Parity = NOPARITY;					//ノンパリティー
	dcb.fParity = FALSE;					//パリティーチェックなし
	dcb.StopBits = ONESTOPBIT;				//1ストップビット

	dcb.fOutxCtsFlow = FALSE;				//CTS信号不使用
	dcb.fOutxDsrFlow = FALSE;				//DSR信号不使用
	dcb.fDtrControl = DTR_CONTROL_DISABLE;	//DTRライン使用不可
	dcb.fRtsControl = RTS_CONTROL_DISABLE;	//RTSライン使用不可

	dcb.fOutX = FALSE;						//XON,XOFFフロー制御を送信時に使用しない
	dcb.fInX = FALSE;						//XON,XOFFフロー制御を受信時に使用しない
	dcb.fTXContinueOnXoff = TRUE;			//
	dcb.XonLim = 512;						//
	dcb.XoffLim = 512;						//
	dcb.XonChar = 0x11;						//送受信のXON文字
	dcb.XoffChar = 0x13;					//送受信のXOFF文字

	dcb.fNull = FALSE;						//nullバイトを廃棄しない
	dcb.fAbortOnError = FALSE;				//エラー時にドライバが終了しない
	dcb.fErrorChar = FALSE;					//パリティーエラー時に置換しない
	dcb.ErrorChar = 0x04;					//パリティーエラーの文字
	dcb.EofChar = 0x03;						//データ終了の文字(非バイナリーモード)
	dcb.EvtChar = 0x02;						//受信時のイベントの文字

	//dcb構造体の内容をセット
	Ret = SetCommState( hPort, &dcb);
	//成否判定メッセージ
	if( Ret == FALSE )
	{
		printf("SetCommState Error\n");
		funcexit( hPort );
	}
	printf("SetCommState OK\n");

	//タイムアウトの設定  トータルタイムアウト = Multiplier * 文字数 + Constant
	timeout.ReadIntervalTimeout = 3000;			//文字読み込み間の時間
	timeout.ReadTotalTimeoutMultiplier = 300;		//受信時の文字数に対する乗数
	timeout.ReadTotalTimeoutConstant = 3000;		//受信時の文字数に対する定数
	timeout.WriteTotalTimeoutMultiplier = 3000;	//送信時の文字数に対する乗数
	timeout.WriteTotalTimeoutConstant = 3000;	//送信時の文字数に対する定数

	//タイムアウトをセット
	Ret = SetCommTimeouts( hPort, &timeout);
	//成否判定メッセージ
	if( Ret == FALSE )
	{
		printf("SetCommTimeouts Error/n");
		funcexit( hPort );
	}
	printf("SetCommTimeouts OK\n");

	//送信データの作成
	strcpy( bSendBuffer, "aaaaa" );		//初期化
	printf("%s\n",bSendBuffer );				//確認

	bSendBuffer[0] = 0x40;						//@
	bSendBuffer[1] = 0x31;						//0
	bSendBuffer[2] = 0x44;						//D
	bSendBuffer[3] = 0x00;						//Null
	bSendBuffer[4] = 0x00;						//Null
	bSendBuffer[5] = 0x00;						//Null
	bSendBuffer[6] = 0x00;						//Null
	bSendBuffer[7] = 0x00;						//Null
	bSendBuffer[8] = 0x00;						//Null
	bSendBuffer[9] = 0x0a;						//CR
	bSendBuffer[10] = 0x0d;						//LF

	for( i = 0 ; i < 11 ; i++ )
	{
		printf("%c",bSendBuffer[i]);
		printf("%d\n",i);
	}
	printf("\n");
	printf("bSendBufferは%s\n",bSendBuffer);	//送信データの確認

	do
	{
		ClearCommError( hPort, &dwErrorMask, &Comstat );				//ポートのエラーをクリア
		DataSize = strlen( bSendBuffer );								//送信データサイズの取得

		printf("DataSize = %d\n",DataSize);								//送信データサイズの確認
		printf("Comatat.cbOutQue = %d\n",Comstat.cbOutQue);				//送信バッファのバイト数

	}while( ( MAX - Comstat.cbOutQue ) <= DataSize );

	//データの送信
	Ret = WriteFile( hPort, bSendBuffer, 11, &dwSendSize, NULL );
	//成否判定メッセージ
	if( Ret == FALSE )
	{
		printf("WriteFile Error\n");
		funcexit( hPort );
	}
	printf("WriteFile OK\n");

	strcpy( In, "abcdefghijk");								//受信バッファの初期化

	while(1)
	{
		//データの受信
		Ret = ReadFile( hPort, In, 11, &IRead, NULL );
		if( Ret == FALSE )
		//成否判定メッセージ
		{
			printf("ReadFile Error\n");
			funcexit( hPort );
		}
		printf("ReadFile OK   ");

		printf("read data size = %x\n",IRead);				//受信データのサイズを確認
		printf("%s\n",In);									//受信したデータを表示

		//キーボードからの入力があったら終了
		kbjudge = kbhit();
		if( kbjudge == 1 )
		{
			printf("This program will be finished.\n");
			break;
		}
		Sleep(1000);



	}

	CloseHandle( hPort );

	printf("Normal End\n");
	Sleep(3000);
	return 0;
}
178行目で受信データのサイズを表示すると0バイトであり、179行目で受信データを見ると初期値のままです。
これは送信がうまくできていないのか、受信がうまくできていないのかもわからないので、どちらに問題があるかだけでもわかれば幸いです。
私としては147行目で送信データサイズを表示すると3バイトになってしまうのでそれが原因ではないかと考えているのですがどうでしょうか。

急いで書いたコードなのできれいに成形できておりませんが、よろしければご指導の程よろしくお願い致します。

Re: RS-485でシリアル通信をしたい

Posted: 2012年1月05日(木) 20:41
by beatle
ロジックアナライザかオシロスコープを使って,信号がきちんと出ているか確認できませんか?

Re: RS-485でシリアル通信をしたい

Posted: 2012年1月05日(木) 22:23
by tktkm
beatleさん、ご回答ありがとうございます。
beatle さんが書きました:ロジックアナライザかオシロスコープを使って,信号がきちんと出ているか確認できませんか?
今オシロスコープを使って確認してみたところ、信号はちゃんと送信できていることがわかりました。

したがって、受信部分のプログラムに問題があるか、通信先が故障しているか、送信データが通信先の要求している形式と異なっているということでしょうか。
ちなみに、送信先はミネベア株式会社のベクトルセンサ用ディジタルトランスミッタCSD-594であり、説明書にはASCIIコードで「@,0,D,Null,Null,Null,Null,Null,Null,CR,LF」と送信するように記述してありました。

Re: RS-485でシリアル通信をしたい

Posted: 2012年1月05日(木) 22:44
by beatle
CRは0x0dでLFは0x0aですが間違っていませんか?

Re: RS-485でシリアル通信をしたい

Posted: 2012年1月06日(金) 18:22
by tktkm
ご回答ありがとうございます。
返事が遅れてしまってすいません。
beatle さんが書きました:CRは0x0dでLFは0x0aですが間違っていませんか?
初歩的ミスでお恥ずかしいです。
その部分を修正してみましたが、相変わらず受信はできませんでした。
他に考えられる原因はありますでしょうか。

Re: RS-485でシリアル通信をしたい

Posted: 2012年1月06日(金) 18:31
by beatle
tktkm さんが書きました:私としては147行目で送信データサイズを表示すると3バイトになってしまう
この記述を見逃していました.tktkmさんはstrlen関数の働きを誤解しています.
strlen関数は,与えられたchar配列の,先頭からナル文字までの長さを測ります.
strlenに渡した配列には「@,0,D,Null,Null,Null,Null,Null,Null,CR,LF」が格納されていますから,strlenとしては「長さ3」という結果を出すわけです.
だから期待した11バイトが出力されていないのだと思います.

Re: RS-485でシリアル通信をしたい

Posted: 2012年1月06日(金) 20:42
by tktkm
ご回答ありがとうございます。
beatle さんが書きました:
tktkm さんが書きました:私としては147行目で送信データサイズを表示すると3バイトになってしまう
この記述を見逃していました.tktkmさんはstrlen関数の働きを誤解しています.
strlen関数は,与えられたchar配列の,先頭からナル文字までの長さを測ります.
strlenに渡した配列には「@,0,D,Null,Null,Null,Null,Null,Null,CR,LF」が格納されていますから,strlenとしては「長さ3」という結果を出すわけです.
だから期待した11バイトが出力されていないのだと思います.
strlen関数はそのような意味だったのですね。確かに勘違いしておりました。
では長さが3になるのは当然であり、実際の出力電圧を見ても問題はないようなので他の部分が間違っているということですね。

Re: RS-485でシリアル通信をしたい

Posted: 2012年1月07日(土) 07:41
by beatle
[quote="tktkm"]

コード:

	do
	{
		ClearCommError( hPort, &dwErrorMask, &Comstat );				//ポートのエラーをクリア
		DataSize = strlen( bSendBuffer );								//送信データサイズの取得

		printf("DataSize = %d\n",DataSize);								//送信データサイズの確認
		printf("Comatat.cbOutQue = %d\n",Comstat.cbOutQue);				//送信バッファのバイト数

	}while( ( MAX - Comstat.cbOutQue ) <= DataSize );
僕だけかもわかりませんが,このあたりの処理が何をやっているか分かりません.
送信バッファにDataSize分空きが発生するまで待つという感じでしょうか.
だとすると,DataSizeが3ですから,3バイト空いた瞬間にループを抜け,結果として3バイトしか送信できないということかもしれませんね.