RS232Cで文字列を送信するCプログラムを作成しています、がうまくいきません。OSはLINUX fedora7です。
状況は、
・RS232対応の測定機器にプログラムを使ってコードを送る
 →エラー表示される(何かしら送信はされている?)。
・確認のためクロスケーブルを用いてPC-PC間で送受信を行う
 →何も受信されない(受信プログラムは動作確認済みのものを使用)。
・ポートやボーレート、パリティ、フロー制御の一致は確認しました。
送信プログラムはThe Linux Serial Programming HOWTOに置かれている受信プログラムのサンプルを基に作成しました。
私のいじったプログラムに問題があるように思っていますが、その点を把握できません。
プログラミングでもそれ以外でも、何か原因に思い当たる節のある方がいましたら、御指導の程よろしくお願いします。

以下にプログラムを記します。
*キーボードから入力した文字列を送信し、eを打ち込むと終了するプログラムのつもりです…(^^;

main(){
int fd,res,;
struct termios oldtio,newtio;
char send[255];

fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {printf("error");
perror(fd); exit(-1); }
**********************
termios設定文、省略(serial HOWTO のサンプルそのまま)
**********************
while(1){
printf("入力待ち\n");
scanf("%s",send);
printf("%s\n",send);

if( *send =='e'){
printf("終了");
break;
}
else{
res = write(fd,send,255);
send[res]=0;
printf("%s,%d\n", send,res);
}
}
tcsetattr(fd,TCSANOW,&oldtio);
}

このQ&Aに関連する最新のQ&A

A 回答 (5件)

>・RS232対応の測定機器にプログラムを使ってコードを送る


> →エラー表示される(何かしら送信はされている?)。

シリアル通信で何かを受け取る機器は、普通「特定のコマンド」を受け取り、受け取ったコマンドに対し、数バイトのレスポンスを返します。

機器によっては、1度コマンドを送ったら、レスポンスを拾ってあげるか、強制リセットのコマンドを送ってあげるまで、次のコマンドに応答しないのが普通です。

例えば、ある機器では、以下のようにしなければなりません。

1.'\x06'が返って来るまで、'\x16'を1文字づつ送り続ける(強制リセットコードの送信)
2.'\x06'が返って来たら、'I'を送って、'\x06'が返って来るのをまつ(初期化コマンドの送信と応答待ち)
3.'\x06'が返って来たら、'S' '1' '0' '0' '\n'の5文字を送って、'\x06'が返って来るのをまつ(設定コマンドの送信と応答まち)
(以下略)

このように「機器ごとに決められた手順」に従って送受信をしないと、機器がエラーを起こし「それっきり」になります(強制リセットのコードを送り付けるか、機器の電源を入れ直してやらない限り、2度と応答しません)

>PC-PC間での送信では同じPCを用いたのでそこまでの差が出るようにも思われません。

いいえ。昨今のPCの速度から考えると「相対的な速度で言えばRS232Cは信じられないくらい遅い」ので、そこがボトルネックになって「送信のオーバーフロー」と「受信のアンダーフロー」が起きます。

「送信のオーバーフロー」とは「PCが大量に一気にシリアルポートに書き込もうとしたら、通信が遅くて、言われたバイト数の一部しか受け付けられないか、1バイトも受け付けられないで、残りを捨ててしまう状態」を言います。もちろん「何バイト書けたか」を見て、残りを送り直ししないと、ちゃんと全部送信出来ません。

「受信のアンダーフロー」とは「PCが一気に大量にシリアルポートから読もうとしたら、通信が遅くて、言われたバイト数の一部しか受け取れないか、1バイトも受け取れないで、そうこうしているうちにタイムアウトエラーになってしまい、途中までしか受信しなかった状態」を言います。もちろん、こっちが受信を途中で止めたのに相手はまだ送信を続けてるでしょうから、続きをちゃんと全部受信してやらないといけません。

送信PCを「製造工場」、受信PCを「商品倉庫」、RS232Cを「輸送トラック」と考えてみて下さい。

「製造工場」も「商品倉庫」も高性能です。でも「輸送トラック」は遅いです。法定速度(決められたボーレート)で走らないとなりません。

「製造工場で日に2万個製造」していて、商品倉庫は「1日に2万個の商品を仕分けできる」としても「輸送トラックは1日に千5百個しか運べない」としたら?

製造工場では「1日にトラックで運べる数しか製造しちゃダメ」ですし、商品倉庫は「トラックが来なきゃ従業員はやる事無し。本日最後に到着するトラックの荷物を仕分けし終わったら、昼前であっても帰ってよし」です。

このように「製造工場と商品倉庫の性能が同じ」でも「輸送トラックが遅い」と「商品を小出しに送り出す」「商品を小分けで受け取る」と言う処理が必要です。

RS232C通信でもそれは同じで「同じPCを用いたとしても、通信媒体の速度が比べられないほど遅ければ、送信と受信は小分けして処理せねばならず、2つのPCの性能がどうのこうのって話は無意味」です。
    • good
    • 0
この回答へのお礼

丁寧な説明ありがとうございます。初心者には助かります。
重ね重ね恐縮ですが疑問点2つあります。

前半部分については、今プロトコルを勉強をしてまして、恐らくHDLC手順や無手順プロトコルと言った話なのではないかと思いますが、それをどのようにプログラムに書き込んだらよいのかがわかりません。
ただ単に制御コードを送りたい情報の前後等に、文字列として送ってやればよいのでしょうか?

後半部の話は、sleep等で待ち時間を調節してやれば良い。という理解でよろしいでしょうか?

あまりお手を煩わせるのもなんですので、参考サイトなどで十分ですのでよろしくお願いします。

お礼日時:2009/05/21 11:23

>>ひとつ質問なのですがバッファを一度0x00で埋める理由とはなんなのでしょうか?


memset( rData, 0x00, sizeof(rData) ); ←これは、
単に初期化しているだけです。これをしないとバッファの中身が不定値になりますので、変な文字が受信データとして表示される場合があるからです。

rData[0] = 0x00; ←ここの事でしょうか。
受信したデータを表示させるのですが、printf( "%s", rData ); にて%sを使用した文字列表示をさせています。文字列の終端は0x00というお約束ですので、表示をかけたらループでまた表示となりますので再表示させない為に、rData[0]を0x00にする事で、無表示になります。read関数の戻り値で1以上なら表示という条件文を付けても良いのですが、簡潔にする為、単にrData[0]=0x00として無表示にさせているだけです。
    • good
    • 0
この回答へのお礼

質問が明確ではなく失礼しました(^^;
無事に理解できました!ありがとうございます!

お礼日時:2009/05/21 12:09

USB接続のRS232C(/dev/ttyUSB0)、Vine Linuxで以前作成し上手く送受信しているサンプルです。


9600Bps、8bit、ノンパリ、STOP BIT 1です。
--------------------
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

int main( void )
{
int fd;
struct termios tio;
int err;
char sData[1];
char rData[255];

if ((fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK))<0) {
return -1;
}
memset(&tio, 0x00, sizeof(tio));
tio.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
tio.c_iflag = IGNPAR | ICRNL;
tio.c_oflag = 0;
tio.c_lflag = 0;
tio.c_cc[VTIME] = 0;
tio.c_cc[VMIN] = 1;

tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &tio);
fcntl(fd, F_SETFL, FNDELAY);

sData[0] = ' ';
memset( rData, 0x00, sizeof(rData) );
while(1){
// 1キャラクタ送信
err = write( fd, sData, 1);
sData[0]++;
if( sData[0]>='z' ){
sData[0] = ' ';
}

// 受信
err = read( fd, rData, sizeof(rData) );
printf( "%s", rData ); // 受信データ表示
rData[0] = 0x00;

// 500mSecのWAIT
usleep( 500000 );
}

close( fd );
}
--------------------
ご参考まで。
    • good
    • 0
この回答へのお礼

ありがとうございます!!参考にさせてもらいます!
ひとつ質問なのですがバッファを一度0x00で埋める理由とはなんなのでしょうか?重ね重ねすみません。

お礼日時:2009/05/21 10:56

以前の経験です。

それもLinuxではなく(昔懐かし)MS-DOSの時代の話ですから、そのぶんさっぴいでください。
あの時は読み取りだったのですが、一気にread文では読み取れず、ポートから1文字ずつ拾いました。計測器側のデータを準備するスピードとPCの読み取り速度に差異が生じ、一文字拾ったきりポート待ちになってしまいました。同様のことが発生していませんか?PC側で一気に吐き出してしまうと、計測器側で処理しきれずエラーになってしまうというものです。ほかの方も書いていますが、1文字ずつ贈ってみるのも悪くないような気がします。
    • good
    • 0
この回答へのお礼

御解答ありがとうございます!
関数を変えて1キャラクタづつ送信してみましたがうまくいきませんでした。また、PC-PC間での送信では同じPCを用いたのでそこまでの差が出るようにも思われません。当面はore100さんの指摘された点を考えていきたいと思います。ありがとうございます!!

お礼日時:2009/05/20 15:03

どのような、プロトコルで232cの通信を行うのかが不明です。


プロトコルの説明をお願い申し上げます。
ack、nacのコードが返って来ると思いますが、その処理は、ないようです。
    • good
    • 0
この回答へのお礼

さっそくの御返答ありがとうございます!
正直を言うとプロトコルの知識が全くなく今初めて調べて、それが必要であることを知りました。
つまり、制御キャラクタを処理するプログラム、及び通信プロトコルと呼ばれる通信の型?(これが前者を包括しているのかもしれませんが)をプログラムに組み込まなければならないということでよいでしょうか?
今からプロトコルの勉強をし直してきたいと思います。ありがとうございます!

お礼日時:2009/05/20 14:54

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qシリアル通信プログラム(受信)について

現在、シリアル通信をする(受信のみ)プログラムを作成しています。
接続先は1秒ごとに10バイトのデータを自動で送信してきます。
現段階でPC側でデータを受信できることは確認できました。
しかし、受信データが文字化け(出力結果が{や■などがでています)しており、その原因がわかりません。
どこが問題なのか教えていただけないでしょうか?

また、接続先からは10バイトのうち最初の2バイトは固定の値(0x2b,0x22)がでてくるはずなのですが、それもでてきていません。これも文字化けで見えていないだけでしょうか?
文字化けしても周期的に固定の値に対応した文字がでてくるものだと思ったのですが、でてきていません。
(ソースで50バイトまでみているのはこの周期性を確認するためです)

シリアル通信を初めてさわるので、考え方自体間違っているかもしれませんが
配列pszBufに1つずつ、受信された1バイトのデータが格納されていると思っています。
個人的にはprintfでの表記(%cがいけない?)に間違いがあるかと疑っています。

ご回答よろしくお願いいたします。

(環境)
Visual C++ 2008 (C/C++)

(シリアルポート設定)
ボーレート 9600bps
パリティ   なし
ストップビット 1
データビット 8

(ソース) ※ポートの設定は省略。受信部のみ記述
HANDLE hComm;
DWORD dwErrors;
COMSTAT ComStat;
char pszBuf[1024];
DWORD dwRead;

ClearCommError(hComm, &dwErrors, &ComStat);
ReadFile(hComm, pszBuf, 50, &dwRead, NULL);  //50バイトまでデータを取得

for(int i=0;i<50;i++){
printf("%c\n",pszBuf[i]);
}

(参考URL)
http://www.geocities.jp/terukat/_geo_contents_/win/comm.html

現在、シリアル通信をする(受信のみ)プログラムを作成しています。
接続先は1秒ごとに10バイトのデータを自動で送信してきます。
現段階でPC側でデータを受信できることは確認できました。
しかし、受信データが文字化け(出力結果が{や■などがでています)しており、その原因がわかりません。
どこが問題なのか教えていただけないでしょうか?

また、接続先からは10バイトのうち最初の2バイトは固定の値(0x2b,0x22)がでてくるはずなのですが、それもでてきていません。これも文字化けで見えていない...続きを読む

Aベストアンサー

>一応、ReadFileをおわったあとにdwReadを確認したのですが、50になっていました。

であれば、ReadFile()が失敗したとかはなさそうですね。
# ReadFile()の戻り値を確認していないのであればdwReadはReadFile()コール前にクリアしておいた方がいいかと思いますが。

>なんらかの失敗といわれるとどういった失敗がありえるのでしょうか?

タイムアウトがないのであれば…基本的には失敗はない…でしょうね。
コネクタ類が接触不良でデータが化けるとか、XON/XOFFフロー制御している…とかでなければ。

>(ボーレートの設定がおかしければデータがかわることはあるでしょうが・・・)

ボーレート以外の設定が異なっていた場合も化けると思われます。

>接続先がデータを送らなくとも、ReadFileがデータを格納することがあるのでしょうか?

受信バッファに残っていた場合は読み出す…でしょうね。

CreateFile()でシリアルポートを開く処理、シリアルポートの設定を行っている部分も掲示された方がいいかも知れません。
# が、私自身はAPI叩いてシリアルポート操作したことは無かったりします。

WindowsAPIのパターンとして…構造体は0x00でクリアして必要な部分だけ設定する。
という方法を採らないと妙な挙動することもありますので、その辺りは確認された方がいいでしょう。
APIに構造体のアドレスを渡して、情報を取得(上書きされる)から…ということで、未初期化の構造体渡したらエラーで何も設定してくれなかった。
なんて場合もあります。
# 構造体のメンバに「構造体のサイズ」を格納する場合、その構造体のサイズで対応バージョンを判別する。
# なんて挙動をしている場合もありますので。

>一応、ReadFileをおわったあとにdwReadを確認したのですが、50になっていました。

であれば、ReadFile()が失敗したとかはなさそうですね。
# ReadFile()の戻り値を確認していないのであればdwReadはReadFile()コール前にクリアしておいた方がいいかと思いますが。

>なんらかの失敗といわれるとどういった失敗がありえるのでしょうか?

タイムアウトがないのであれば…基本的には失敗はない…でしょうね。
コネクタ類が接触不良でデータが化けるとか、XON/XOFFフロー制御している…とかでなければ。

>(ボーレ...続きを読む

Qシリアル通信でのデータ受信

シリアル通信にてデータを連続的に受信するプログラムを
つくりたいと思っています.

以下のプログラムを作成して,
main関数のcountを増やして,繰り返しreadを行おうとすると,

出力結果として,
時,分,秒,ID,値B,値C,値Dというフォーマットで

0, 9,30, 1,514,708,542,290

0, 9,30, 2,515,707,542,288

0, 9,30, 3,514,709,542,287

0, 9,30, 4,514,707,543,289

0, 9,30, 5,514,708,542,289

0, 9,30, 6,514,708,542,292

0, 9,30, 7,514,708,542,291

0, 9,30, 8,514,708,542,289

0, 9,30, 9,514,708,543, 0, 9,39,35,514,708,542,289

(この後フが連続)
フフフフフフフフフフフフフフフ ク 0, 9,39,36,514,708,542,290

0, 9,39,37,515,709,541,291

0, 9,39,38,514,707,542,286

0, 9,39,39,514,708,542,281

0, 9,39,40,514,708,542,284

0, 9,39,41,514,707,542,286

0, 9,39,42,514,707,542,290

0, 9,39,43,514,709,542,290

0, 9,30, 9,514,708,543, 0, 9,39,35,514,708,542,289

フフフフフフフフフ・・・再びフ

となってしまいます.
問題としては

・フがたくさんでてきてしまう.
・1サイクルの最後で改行ができていない
・1サイクルが終わって次のサイクルに入る時までの
間にデータが失われている.
・2サイクル目になぜか1サイクル目の値が残っている?

などがあります.

どなたか解決方法を教えていただけると大変助かります.
よろしくお願いします.
-------------------------------
#include "stdafx.h"
#include <stdlib.h>
#include <windows.h>
#include <string.h>
#include <stdio.h>

#define COM_PORT_NAME"COM2"
#define BAUD_RATE57600
#define BYTE_SIZE5000 //250
#define PARITYNOPARITY //EVENPARITY
#define STOP_BITTRUE
#define F_PARITYONESTOPBIT

HANDLE hComm;// シリアルポートとの通信ハンドル

bool ComInit()
{
// シリアルポートを開ける
hComm = CreateFile(
COM_PORT_NAME,/* シリアルポートの文字列 */
GENERIC_READ | GENERIC_WRITE,
/* アクセスモード:読み書き */
0,/* 共有モード:他からはアクセス不可 */
NULL,/* セキュリティ属性:ハンドル継承せず */
OPEN_EXISTING,/* 作成フラグ: */
FILE_ATTRIBUTE_NORMAL,/* 属性: */
NULL/* テンプレートのハンドル: */
);

if (hComm == INVALID_HANDLE_VALUE) {
printf("シリアルポートを開くことが出来ませんでした。\n");
return false;
}

// 通信属性を設定する
DCB dcb;
GetCommState(hComm, &dcb); /* DCB を取得 */
dcb.BaudRate = BAUD_RATE;
dcb.ByteSize = BYTE_SIZE;
dcb.Parity = PARITY;
dcb.fParity = STOP_BIT;
dcb.StopBits = F_PARITY;
SetCommState(hComm, &dcb); /* DCB を設定 */

return true;
}

void ComEnd()
{
// ハンドルを閉じる
CloseHandle(hComm);
}


bool ReadData(char *buff, unsigned int max_size)
{
DWORD dwErrors; /* エラー情報 */
COMSTAT ComStat; /* デバイスの状態 */
DWORD dwCount; /* 受信データのバイト数 */
DWORD dwRead; /* ポートから読み出したバイト数 */

ClearCommError(hComm, &dwErrors, &ComStat);
dwCount = ComStat.cbInQue;

FILE *fid;
fid=fopen("test.txt", "w");

printf("%d %d\n", dwCount, max_size);
fprintf(fid,"%d %d\n", dwCount, max_size);

fclose(fid);
if (dwCount > max_size) {
printf("バッファサイズが足りません。\n");
return false;
}

if(hComm != NULL){
ReadFile(hComm, buff, dwCount, &dwRead, NULL);

if (dwCount != dwRead) {
printf("データの受け取りに失敗しました。\n");
return false;
}
}

return dwRead;
}

int main(int argc, char* argv[])
{

char buff[BYTE_SIZE];
int count = 0;
int data_length;
FILE *fid2;
fid2=fopen("test2.txt","w");

ComInit();

while(1){
if(count == 2) break;
count++;

data_length=ReadData(buff, strlen(buff));
printf("%s ",buff);
fprintf(fid2, "%s ",buff);


}
fclose(fid2);
ComEnd();

return 0;
}

シリアル通信にてデータを連続的に受信するプログラムを
つくりたいと思っています.

以下のプログラムを作成して,
main関数のcountを増やして,繰り返しreadを行おうとすると,

出力結果として,
時,分,秒,ID,値B,値C,値Dというフォーマットで

0, 9,30, 1,514,708,542,290

0, 9,30, 2,515,707,542,288

0, 9,30, 3,514,709,542,287

0, 9,30, 4,514,707,543,289

0, 9,30, 5,514,708,542,289

0, 9,30, 6,514,708,542,292

0, 9,30, 7,514,708,542,291

0, 9,30, 8,51...続きを読む

Aベストアンサー

先ほどの訂正と追加です。
3.dcb.Bytesizeを8にして、while文を無限ループにし
(countのif~break文を削除し), strlen(buff)のところを
BYTE_SIZEにしてみてください。データが取りこぼしなく
表示されませんか。
#通信が終わらないという問題は、受信ができない問題
とは別問題なので、今は考えていません
4.3.でデータの取りこぼしがあれば、送信側・受信側とも、
BaudRateを低く(9600bpsとか)してみて改善されるかどうか、
確認してください。

データの取りこぼしが通信速度によるものなら、フロー制御など
も考えないといけませんね。ところで、今頃聞くのもなんなんですが、
送信側・受信側は、どのような環境をお使いなんでしょう?

QLINUX上でシリアル通信(C++)

PCとマイコンをシリアル通信を介して送受信したいのですが
どのサイトを見てもVC++やWindows上のAPIを使ったものばかりです。

開発環境はLINUXのgcc4.5を想定していますが、使える関数が異なりますよね?
どのような流れで作成すればいいのでしょうか。
単にシリアル変換のUSBで文字列を送受信するだけでいいです。

Aベストアンサー

これが参考になるかもしれない。
http://linuxjf.sourceforge.jp/JFdocs/Serial-Programming-HOWTO.html
デバイスは /dev/ttyUSB0 などになると思う。

参考URL:http://linuxjf.sourceforge.jp/JFdocs/Serial-Programming-HOWTO.html

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

QRS232cと通信が可能な、CまたはC++のプログラム

初めて投稿します。

現在卒業研究で、RS232cで接続された2次元センサ(カメラで対象物をトラッキングし、2次元座標データをPCに送る計測器)のデータをPC(OSはXP)で読み込もうとしています。
以下のサイトを見つけ、
http://7ujm.net/C++/Rs232c.h.html
ソースファイルとヘッダーファイルからなるプログラムをつくり(プログラムの変更点は最後に明記しました)
、VC++とBORLANDC++で試してみたのですが
VC++ではプロジェクトのビルド時に
「fatal error C1010: プリコンパイル済みのヘッダーの検索中に予期しないEOFを検出しました。」
とエラーが出てしまいます。
_tmain()関数の引数を無記入にしてみてもエラーの内容は変わりません
でした。

また、BORLANDC++ではコンパイル時に
「エラー E2268 RS232.cpp 11: 未定義の関数'printf'を呼び出した(関数 tmai())」
「エラー E2268 RS232.cpp 13: 未定義の関数'gethar'を呼び出した(関数 tmai())」
となってしまい、ヘッダーファイルのみをコンパイルしても
「エラー E2141 RS232c.h 10:宣言の構文エラー」
というエラーが生じてしまいます。

念のためこちらも
http://okwave.jp/qa733184.html
参考に、BORLANDの設定(bcc32.cfg ファイルの確認など、最初の設定)も確認しましたが、独習Cなどの教本に載っているプログラムでは問題なく動作します。

なお計測機器のボーレートは115200bps、ターミネータはcr(キャリッジリターン)のみで(lf(ラインフィード)が入ってもかまわない)、送信コマンドはASCII文字となっています。

ハイパーターミナル、MATLABのM-fileでの通信は確認済みです。

もしこのような環境でRS232c通信が利用可能なC(またはC++)プログラムをご存知の方がいらっしゃれば、教えていただけないでしょうか?
よろしくお願いします。


「ソースファイル」
#include "RS232c.h" //このヘッダーを取り込みます。

int _tmain()
{
RS232c rs;
rs.Connect();
rs.Send("POS#?,,1 CR/LF");//文字列を送信 Send(送信文字列)
char w[100];
rs.Read(w,100); //文字列の受信 Read(char配列,読み込む文字数)
printf(w);
getchar();
return 0;
}

「ヘッダーファイル」
#ifndef _RS_232C_H_
#define _RS_232C_H_

#if _MSC_VER > 1000
#pragma once
#endif

#include <windows.h>
<中略>
bool RS232c::Connect(char* PortNmae="COM1",
int BaudRate = 115200,
int ByteSize = 8,
int Parity = NOPARITY,
int StopBits = ONESTOPBIT,
int RTS = RTS_CONTROL_DISABLE,
int DTR = DTR_CONTROL_DISABLE,
int ReadTimeOut =700,
int WriteTimeOut = 700
)
<中略>
{
RS232c::~RS232c(){
//ポートを閉じます
CloseHandle(m_hComm);
}
#endif // _RS_232C_H_

初めて投稿します。

現在卒業研究で、RS232cで接続された2次元センサ(カメラで対象物をトラッキングし、2次元座標データをPCに送る計測器)のデータをPC(OSはXP)で読み込もうとしています。
以下のサイトを見つけ、
http://7ujm.net/C++/Rs232c.h.html
ソースファイルとヘッダーファイルからなるプログラムをつくり(プログラムの変更点は最後に明記しました)
、VC++とBORLANDC++で試してみたのですが
VC++ではプロジェクトのビルド時に
「fatal error C1010: プリコンパイル済みのヘッダーの検索中に予期...続きを読む

Aベストアンサー

> の値を変更すると変わってくるので、ターミネータはうまく機能していないのかと思うのですが、

そのようですね。

また、WinRS のほうの 「Abnormal program termination」は、おそらくタイムアウトだと思います。

これから推定すると、計測器からは(crlf ではなく)cr しか帰ってきてないのではと思います。
WinRS *port = new WinRS(1, 115200, ifLine::cr, "8N1", false);
(3つめのパラメータが、ifLine::crlf → ifLine::cr に変更。これで、cr を受け取った時点で帰ってきます)

あるいは、port->talk("POS#?,,1 \0"); のレスポンスはすぐに帰ってくるのでしょうか?
port->listen() は、これを呼び出したときに受信データがないと、約6秒でタイムアウトします。
もしもレスポンスに時間がかかるのであれば、

port->talk("POS#?,,1");
while(! port->loc()); // レスポンス受信まで待つ
port->listen(buff, len);
としてみて下さい。

また、port->listen() の len は、呼び出し時には、受信できる最大バイト数を、返り時には、実際に受信したデータ数を持っています。
このため、talk() を複数行う場合は、
len = 1024;
port->talk("POS#?,,1");
のように毎回 len を設定して下さい。
これがないと、前回の受信バイト数をもって listen() を呼び出すので、前回のレスポンスより長いレスポンスが受け取れなくなります。

最後に、"POS#?,,1 \0" のような、最後の "\0" は不要です。
(あっても無害ですが)
"~" で囲まれた文字列の終端には、暗黙のうちに、"\0" が付加されますので。

> の値を変更すると変わってくるので、ターミネータはうまく機能していないのかと思うのですが、

そのようですね。

また、WinRS のほうの 「Abnormal program termination」は、おそらくタイムアウトだと思います。

これから推定すると、計測器からは(crlf ではなく)cr しか帰ってきてないのではと思います。
WinRS *port = new WinRS(1, 115200, ifLine::cr, "8N1", false);
(3つめのパラメータが、ifLine::crlf → ifLine::cr に変更。これで、cr を受け取った時点で帰ってきます)

あるいは、...続きを読む

QLinuxでシリアル通信(RS232C)プログラム

Linuxでパソコンから他の機器へ文字列を送るプログラムを書きたいと思っています。
termios.h というヘッダーがあると言うことは検索して分かったのですが、それ以上に詳しいことがよく分かりません。
Linuxでシリアル通信をするC言語のプログラミングを扱っている書籍や詳しいサイトがあれば教えて頂きたく思います。

また、C言語のヘッダーは自分が勉強した本に載っているものは分かるのですが、それ以外のものはどうやって調べられているのでしょうか?
自分が求めている機能のライブラリがあるかどうかは、Googleとかで調べておられるのでしょうか?
termios.hというようなヘッダーについては、どうやって情報を集められているのでしょう?

よろしくお願い致します。

Aベストアンサー

これとか参考になるかと。
古くからあるドキュメントですが、基本的に変わってないので。
もしかすると、もっとお手軽に使えるフレームワークがQtやJavaあたりにありそうですが。

参考URL:http://www.linux.or.jp/JF/JFdocs/Serial-Programming-HOWTO.html

QC言語とシリアル通信の送受信データの概念

C言語とシリアル通信の送受信データの概念

今シリアル通信で基盤上のデータを読み書きするツールを作っています。
基盤はまだ手元にないので、先にプログラムと、基盤の動作を模したプログラムを作るつもりです。
基盤の説明にはデータはバイナリで送るようにと書かれていたので、
文字列で1バイトずつ割り当てようと考えました。
しかし、どうやって1234などの数値を1バイトずつ割り振るのか、
バイナリって何だっけと調べているうちにわけが分からなくなってきました。

たとえば1234という10進数の数値を送りたいとき、
現状ではchar型の文字列"1234"を渡しています。
もしかしてこれは間違っていて、本当は

char s[] = { 1, 2, 3, 4 };
16進数の場合はabcdなら
char s[] = { 0xa, 0xb, 0xc, 0xd };
として渡すのが正しいのでしょうか。
これでprintfを使うと文字化けして何だかバイナリっぽいぞと感じましたが。

また、バイナリ以外ならどんな送り方があるのでしょう?

Aベストアンサー

まあ、それは、データ形式の名前を気にするより、単に BCD でと言うことですね。

こんな感じで変換できますね。
(データを変換するだけなので、最初に送る 0xa1 はつけていません)

あと、BCD だと、(単純なバイナリ送信と違って) 'A' ~ 'F' に相当するコードは出てきません。
なので、0xa1 のように、「BCD としては存在しない」データがコマンドなどに割り当たっているわけです。

#include <stdio.h>

unsigned char toBCD2(int v)
{
return ( (v / 10) * 0x10 + v % 10);
}

void longToBCD(long src, char bcd[], int keta)
{
int i;
for(i = 0; i < keta; i++) // 桁は、BCD の配列の個数(安直ですが)
{
int work = src % 100;
bcd[i] = toBCD2(work);
src /= 100;
}
}

int main()
{
int i;

char result[5];
longToBCD(0x00201e90, result, 5);
for (i = 0; i < 5; i++)
{
printf("%02X ", result[i]);
}

return 0;
}

まあ、それは、データ形式の名前を気にするより、単に BCD でと言うことですね。

こんな感じで変換できますね。
(データを変換するだけなので、最初に送る 0xa1 はつけていません)

あと、BCD だと、(単純なバイナリ送信と違って) 'A' ~ 'F' に相当するコードは出てきません。
なので、0xa1 のように、「BCD としては存在しない」データがコマンドなどに割り当たっているわけです。

#include <stdio.h>

unsigned char toBCD2(int v)
{
return ( (v / 10) * 0x10 + v % 10);
}

void longToBCD(long src,...続きを読む

Qシリアル通信でのread関数の戻り値

オムロン製PLCと上位コンピュータをRS232Cで接続し、FINSコマンドを用いてシリアル通信をしようとしています。
現在作っているプログラムの流れは、

・シリアルポート"/dev/ttyS2"のオープン
  comm_fd = open("/dev/ttyS2", O_RDWR | O_NOCTTY);
・通信設定
  termios構造体を設定
・コマンドフレーム(COMMAND)を作成し、ポートに書き込む
  write(comm_fd, &COMMAND, strlen(COMMAND));
・PLCからのレスポンスを読み出す
  read(comm_fd, &RESPONSE, 256);

のようにしているのですが、read関数が実行されたままになってしまいます。(エラーコードも返ってこない状態です)
readの戻り値が-1ならポートにアクセスできていないとわかるのですが…

ためしにcomm_fdと違う値をread関数に入れてみたところ(read(6, &RESPONSE, 256)、戻り値は-1となりました。

これはどういう状態になってしまっているのでしょうか?
わかりにくい質問で申し訳ありません。

オムロン製PLCと上位コンピュータをRS232Cで接続し、FINSコマンドを用いてシリアル通信をしようとしています。
現在作っているプログラムの流れは、

・シリアルポート"/dev/ttyS2"のオープン
  comm_fd = open("/dev/ttyS2", O_RDWR | O_NOCTTY);
・通信設定
  termios構造体を設定
・コマンドフレーム(COMMAND)を作成し、ポートに書き込む
  write(comm_fd, &COMMAND, strlen(COMMAND));
・PLCからのレスポンスを読み出す
  read(comm_fd, &RESPONSE, 256);

のようにしているのです...続きを読む

Aベストアンサー

PLCはttyS2に接続されていますか?
接続が正しいのであれば、termiosの設定が気になります。
newtio.c_iflag = (IGNPAR | ICRNL); みたいになってないと
readが改行受信で戻ってこずに、256バイト読むまで待っているかもしれません。

QC# シリアル通信でデータ受信時の欠損について

Visualstudio 2013 を使用して C# で開発を行っています。

SerialPort Classを使用してデータの送受信をするプログラムを作成しているのですが、
非同期でデータを受信する際にどうしてもうまくデータを取得出来ません。

5Byteのデータは正常に取得できるのですが、
その直後にくる40Byteのデータは、真ん中あたりの10数Byteや最後の10数Byteしか取れません。


serialPort.DataReceived に登録したイベント関数の中身です。

--------------------------------------------------------------------------------------
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
bytesRead = 0;
// Initialize a buffer to hold the received data
byte[] buffer = new byte[this.serialPort.ReadBufferSize];

try
{
bytesRead = this.serialPort.Read(buffer, 0, buffer.Length);
if (true == serialPort.IsOpen)
{
serialPort.DiscardInBuffer();//受信バッファをクリアする
}

}
catch (Exception ex)
{
DataLog.Exception(ex);
}

//派生クラス用の処理
DeviceClassEventArgs _DeviceClassEventArgs = new DeviceClassEventArgs(buffer, bytesRead);
DeviceClassEvent(this, _DeviceClassEventArgs);
}
--------------------------------------------------------------------------------------

ネットの情報を参考に、
ReceivedBytesThreshold の値を期待するデータ量に逐一変えることで
とりあえず正常に取ることが出来たのですが、これでいいのでしょうか?
期待するデータ量がわからなかった場合は使えないのかなとも思います。

データが欠損してしまう理由、
上記の対処法以外の一般的な対処法など有りましたら教えて下さい。

その他参考になるページ等ありましたら教えていただけると大変助かります。

Visualstudio 2013 を使用して C# で開発を行っています。

SerialPort Classを使用してデータの送受信をするプログラムを作成しているのですが、
非同期でデータを受信する際にどうしてもうまくデータを取得出来ません。

5Byteのデータは正常に取得できるのですが、
その直後にくる40Byteのデータは、真ん中あたりの10数Byteや最後の10数Byteしか取れません。


serialPort.DataReceived に登録したイベント関数の中身です。

-------------------------------------------------------------------------------...続きを読む

Aベストアンサー

DataReceivedイベントが発生したときでも、
シリアルポートへの受信はまだ継続している可能性があるので
不用意にバッファクリアしてはいけない。
非同期の受信処理は、何かと難しいのです。

private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
  bytesRead = 0;
  // Initialize a buffer to hold the received data
  byte[] buffer = new byte[this.serialPort.ReadBufferSize];

  try
  {
    //bytesRead = this.serialPort.Read(buffer, 0, buffer.Length);
    //if (true == serialPort.IsOpen)
    //{
    // serialPort.DiscardInBuffer();//受信バッファをクリアする
    //}

    // 受信バッファにデータがなくなるまで繰り返し読込む
    while (true)
    {
      if (0 == serialPort.BytesToRead)
      {
        break;
      }
      buffer[bytesRead] = (byte)serialPort.ReadByte();
      bytesRead++;
      System.Threading.Thread.Sleep(0);

      // シリアルポートの受信バッファには、
      // ・必要なブロックの途中から受信している。
      // ・次のブロックの先頭部分も受信されている。
      // 可能性があるので、ここで必要なブロックだけRead()できたことを確認する。
      if (必要なブロックが正常に読めたか確認する関数())
      {
        break;
      }
    }
  }
  catch (Exception ex)
  {
    DataLog.Exception(ex);
  }

  //派生クラス用の処理
  DeviceClassEventArgs _DeviceClassEventArgs = new DeviceClassEventArgs(buffer, bytesRead);
  DeviceClassEvent(this, _DeviceClassEventArgs);
}

DataReceivedイベントが発生したときでも、
シリアルポートへの受信はまだ継続している可能性があるので
不用意にバッファクリアしてはいけない。
非同期の受信処理は、何かと難しいのです。

private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
  bytesRead = 0;
  // Initialize a buffer to hold the received data
  byte[] buffer = new byte[this.serialPort.ReadBufferSize];

  try
  {
    //bytesRead = this.serialPort.Read(buffer, 0, buffer.Le...続きを読む

Qシリアル通信の出力バッファと送信完了イベントについて

こんにちわ。よろしくお願いします。

どの言語として扱うか迷ったのですが、恐らくはC/C++が一番だろうと思ってここで質問させていただきます。

質問の内容ですが、現在、シリアル通信のアプリケーションを作っていまして、CreateFileの引数にFILE_FLAG_OVERLAPPEDを与えて非同期で読み書きを行うようにしています。
非同期ですので、OVERLAPPED構造体をstaticで宣言し、
WriteFile時に引数で与えています。
---
m_hComm = CreateFile( (const char*)pCom, GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ) ;
WriteFile(m_hComm, pwData,dwLen, &dwWrite, &osWriter);
---

問題はここからで、OVERLAPPED構造体のイベントが、シグナル状態になり、GetOverlappedResult(m_hComm, &osWriter, &dwWrite, TRUE)を抜けるのはいいのですが、実際には送信は完了しておらず、GetCommStateで通信速度を変更すると送信途中のデータが化けて通信エラーになってしまいます。

どうやら、今使用しているPCのUARTの出力バッファが大きいのか、Windows側のバッファからUARTバッファに書き込みが完了した時点でWindowsはOVERLAPPED構造体のイベントをシグナルにしているようです。
(もちろんFIFOは切ってあります)

他のPCで確認したところ、問題ありませんでした。
もしどなたか、シリアルの出力バッファを監視するいい方法があったら教えていただけないでしょうか。

こんにちわ。よろしくお願いします。

どの言語として扱うか迷ったのですが、恐らくはC/C++が一番だろうと思ってここで質問させていただきます。

質問の内容ですが、現在、シリアル通信のアプリケーションを作っていまして、CreateFileの引数にFILE_FLAG_OVERLAPPEDを与えて非同期で読み書きを行うようにしています。
非同期ですので、OVERLAPPED構造体をstaticで宣言し、
WriteFile時に引数で与えています。
---
m_hComm = CreateFile( (const char*)pCom, GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXI...続きを読む

Aベストアンサー

2400bpsで9文字の文字列を送出してからビットレートを57600bpsに変更する、という処理を5回繰り返すテストプログラムです。

ちょっと乱雑なソースですがご勘弁を。(インデントは全角スペースです。ご注意ください。)

int main(int argc, char** argv)
{
  for (int i = 0; i < 5; ++i) {
    HANDLE hFile;
    DWORD dw;

    hFile = CreateFile(
      "com1",
      GENERIC_WRITE,
      0,
      NULL,
      OPEN_EXISTING,
      0,
      NULL
    );

    DCB dcb = { sizeof(DCB) };
    GetCommState(hFile, &dcb);
    dcb.BaudRate = CBR_2400;
    SetCommState(hFile, &dcb);

    char buf[100];
    sprintf(buf, "%d ABCDE\r\n", i);
    WriteFile(hFile, buf, lstrlen(buf), &dw, NULL);
    // "# ABCDE\r\n" totals 9 bytes, or 90 bits.
    // At 2400bps, 90 bits need 37.5ms to be transmitted.

#if 0
    CloseHandle(hFile);
    hFile = CreateFile(
      "com1",
      GENERIC_WRITE,
      0,
      NULL,
      OPEN_EXISTING,
      0,
      NULL
    );
#endif

    Sleep(15); // 37 makes mess, 38 ok.
    dcb.BaudRate = CBR_57600;
    SetCommState(hFile, &dcb);

    Sleep(100);
    CloseHandle(hFile);
  }

  return 0;
}

同期処理にしていますが、同じ現象が発生しています。

9文字(90ビット)を2400bpsで送出すると37.5msかかる計算になるのですが、このプログラム中にあるSleep(15)の15を37にすると文字化けが発生し、38にすると文字化けが発生しないので、おおよそ計算どおりと言えるかと思います。

ここで#if 0の行を#if 1に変更すると、Sleep(15)がSleep(0)でも文字化けは発生しなくなります。つまり、デバイスのハンドルをcloseするときにはバッファがflushされるということです。

close時は必ずflushする、という記述に行き当たったわけではないので、closeさえすれば万事OKという保証はできませんが、ドライバの動作としては妥当だと思います。

#実は、「試したいこと」とはこれではなくてDevice Power Stateの変更だったのですが、そのテストをする前になんだかいい感じの結果になってしまったので(^^;

2400bpsで9文字の文字列を送出してからビットレートを57600bpsに変更する、という処理を5回繰り返すテストプログラムです。

ちょっと乱雑なソースですがご勘弁を。(インデントは全角スペースです。ご注意ください。)

int main(int argc, char** argv)
{
  for (int i = 0; i < 5; ++i) {
    HANDLE hFile;
    DWORD dw;

    hFile = CreateFile(
      "com1",
      GENERIC_WRITE,
      0,
      NULL,
      OPEN_EXISTING,
      ...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報