シリアル通信でのバイナリデータの送受信方法

このQ&Aのポイント
  • シリアル通信でバイナリデータを送受信するための方法を紹介します。
  • バイナリデータを扱うための関数や使用例について教えてください。
  • プログラム初心者のため、必要なコードや情報が不足している場合には指摘してください。
回答を見る
  • ベストアンサー

シリアル通信でのバイナリデータの送受信方法

visual studio 2008 c++ を用いて 0x00~0xFFの任意のバイトをシリアル通信で送受信するプログラムを書いています。 0x00(NUL)を含んだ文字列は、文字列処理関数では処理出来ないので、以下のようにプラグラムを書くと文字列の最後を示すのに NULL を使っている処理系なので、文字列として読み込みをしているため,NULLで止まってしまいます。 -------------------------------------------------------- 略 DWORD dwWritten; char sendBuf[32]={0}; sendBuf[0] = 0x02; //02 STX sendBuf[1] = 0x00; //00 長 sendBuf[2] = 0xC0; //C0 取得コマンド sendBuf[3] = 0x10; //10 取得コマンド sendBuf[4] = 0x03; //03 ETX sendBuf[5] = 0xD0; //D0 Sum WriteFile(hComm, sendBuf, 6, &dwWritten, NULL); //hComm 指定ポート, 略 -------------------------------------------------------- そこで,送信データをバイナリデータとして扱う関数を使う必要があると思います。 ただ,いろいろ調べたのですが,バイナリデータとして読み書きする関数が分からず困っています。 そのため,バイナリデータとして扱う関数とその使用例を教えていただきたいです。 プログラム初心者のため,問題解決のために必要なコードや情報が不足していることがあるかと思います。 その際にはご指摘いただきたいと思います。

質問者が選んだベストアンサー

  • ベストアンサー
  • yama1718
  • ベストアンサー率41% (670/1618)
回答No.3

その送信のプログラムは問題無いです。 WriteFileの戻り値は、成功すれば「1」で失敗すれば「0」ですが、これはどうなっていますか? あと、dwWrittenには実際に送信できたバイト数が入ります、それは6が入っていませんか? 戻り値が失敗だったり、送信データ数が少なかったら、通信相手や他の問題だと思います。

参考URL:
http://infoseek_rip.g.ribbon.to/spectrum123.at.infoseek.co.jp/vb/vb_2/vb_2.htm
checkshirtbot
質問者

お礼

回答ありがとうございます。 dwWrittenにはちゃんと6が入っていました。 WriteFileの戻り値が0で失敗していたので,質問者様の言うように通信相手や他の問題だと思いますので,そこをあたってみます。 このような初歩的な問題に丁寧に答えてくださりありがとうございました。

その他の回答 (3)

  • wormhole
  • ベストアンサー率28% (1619/5654)
回答No.4

>0x00の時点で文字列の最後と判断されてしまい,それ以降を送受信することができていないと考えているのですが,それは間違いなのでしょうか。 https://msdn.microsoft.com/ja-jp/library/cc429856.aspx を読んで、どこかにそのような動作をするようなこと書かれていますか?

checkshirtbot
質問者

お礼

たびたび回答ありがとうございます。 readfileでの受信の失敗がバイナリデータとして送信できていないためだと勘違いしていました。 大変お騒がせいたしました。

  • notnot
  • ベストアンサー率47% (4847/10260)
回答No.2

WriteFileはバイナリデータを扱える関数のはずですが、何故違うと思ったのでしょうか? 0x00 を終端として扱うのは、文字列処理関数だけです。

checkshirtbot
質問者

お礼

回答ありがとうございます。 readfileでの受信の失敗がバイナリデータとして送信できていないためだと勘違いしていました。

  • wormhole
  • ベストアンサー率28% (1619/5654)
回答No.1

ReadFile,WriteFileでバイナリデータの読み書きできますけど?

checkshirtbot
質問者

補足

そうなのですか? 0x00の時点で文字列の最後と判断されてしまい,それ以降を送受信することができていないと考えているのですが,それは間違いなのでしょうか。 上記のコードで下記の送信コマンドを送ることができているということでしょうか。 02 00 C0 10 03 D0 おそらく非常に初歩的なことを聞いてしまっているかとは思いますが,よろしくお願いします。

関連するQ&A

  • シリアル通信でのNULL送受信方法について

    プログラム初心者です。 現在,visual Studio 2008 c++でRS-485 シリアル通信プログラムを書いています。 使用しているのは変位計なのですが,その仕様書には送信コマンドが 02 00 20 1b 03 3B と表記されています。 00は0x00でNULLとなってしまうと思うのですが、NULLの送信は可能なのでしょうか。 現在書いているプログラムのコマンド送信について書いた部分を以下に示します。 -------------------------------------------------------- 略 DWORD dwWritten; char sendBuf[32]={0}; sendBuf[0] = 0x02; //02 STX sendBuf[1] = 0x00; //00 長 sendBuf[2] = 0xC0; //C0 取得コマンド sendBuf[3] = 0x10; //10 取得コマンド sendBuf[4] = 0x03; //03 ETX sendBuf[5] = 0xD0; //D0 Sum WriteFile(hComm, sendBuf, 6, &dwWritten, NULL); //hComm 指定ポート, 略 -------------------------------------------------------- エラーコード等は省略しています。 指定のポートは開くことができたのは確認したのですが、NULL文字以降がコマンドとして送信できているのか分かりません。 また,その後に ReadFile(hComm, yomiBuf, dwCount, &dwRead, NULL); で受信コマンドを読み込んでいるのですが、NULL以降が読み込めません。 このようなNULL(0x00)のシリアル通信での送受信は可能なのでしょうか。 ご意見よろしくお願いいたします。 また,なにぶん初心者であるため,問題解決のために必要なコードや情報が不足していることがあるかと思います。 その際にはご指摘いただきたいと思います。

  • シリアル通信プログラミングでのバイナリデータ送信

    UNIX系環境(IRIX)でのシリアル通信プログラムを作成していて、 バイナリデータの送信方法がわからず困っています。 write関数を使い、テキストデータの送信は出来ます。 write(fd,"テキスト",byte)のように。 ただ、今回はバイナリデータ送信を考えており、 例えば1byteのデータ00000001(01H)を送りたいと思っています。 このデータを送る場合、write関数で実現出来るのでしょうか? write(fd,0x01,1)←イメージです。 色々ネットで調べても出てきません。 開発がWindows環境ではないので、API関数が使えない状況で困っています(MsComm等が使えない)。また、fwrite関数は使用してはいけないみたいです。教えてください。宜しくお願いします。

  • バイナリデータの取り方

    VB6を使用して、バイナリファイルをバイナリデータとして文字列にとりたいのですが、全角文字が絡んだ時の処理がうまくいきません。 バイナリファイルをString型の変数に丸ごと読み込んで、後は何バイトから何バイト目を抜き取り数値に変換…という処理をしようとしています。 本来は、バイナリでファイルをオープンして、Getコマンドで取得するのが手っ取り早いのですが、ファイルアクセス回数を減らすため、このような面倒な方法をとっております。 そこで仮に、 dim test as string dim i as integer test = "aあ" & chr(1) & "0 " For i = 1 to 6 Debug.Print Asc(Strconv( _ MidB(Strconv(test,vbFromUnicode),i,1), _ vbUnicode)) Next のようなソースを作ってみました。(本来は文字列は数100KByte…) しかしながら、この方法ですと上の例では2Byte目、つまり「あ」の文字の1Byte目が「&H00」になってしまいます。その次は「&HA0」、他の箇所も問題ないのですが… おそらくは根本的に違う方法で解決すべきではないかと思うのですがその方法がわかりません。 なお、この格納データはバイナリデータなので、意図的に全角文字にしていくてもその値によって(偶然)全角文字になったり制御文字になったりしますので前もって全角文字に対する処理は難しいと考えてます。 質問の仕方が良くなく、質問の内容がなかなかご理解いただけないとは思いますが、ご存知の方、ご経験者の方、ご教授お願いいたします。

  • テキストデータをそのままバイナリへ

    初心者です。 テキストデータ(ASCII)として取り込んだ 「05 50 0E」 といった文字列を そのままバイナリデータ(16進)としての 「05 50 0E」 に変換したいのですが、こういった処理をする関数ってあるでしょうか? もしなければ作ってみたいのですが、その際の考え方や有用な関数などありましたら教えていただけると嬉しいです。

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

    C言語とシリアル通信の送受信データの概念 今シリアル通信で基盤上のデータを読み書きするツールを作っています。 基盤はまだ手元にないので、先にプログラムと、基盤の動作を模したプログラムを作るつもりです。 基盤の説明にはデータはバイナリで送るようにと書かれていたので、 文字列で1バイトずつ割り当てようと考えました。 しかし、どうやって1234などの数値を1バイトずつ割り振るのか、 バイナリって何だっけと調べているうちにわけが分からなくなってきました。 たとえば1234という10進数の数値を送りたいとき、 現状ではchar型の文字列"1234"を渡しています。 もしかしてこれは間違っていて、本当は char s[] = { 1, 2, 3, 4 }; 16進数の場合はabcdなら char s[] = { 0xa, 0xb, 0xc, 0xd }; として渡すのが正しいのでしょうか。 これでprintfを使うと文字化けして何だかバイナリっぽいぞと感じましたが。 また、バイナリ以外ならどんな送り方があるのでしょう?

  • バイナリデータからの値の取得について教えてください

    今、バイナリデータから値を取りだそうとがんばっています。 しかし、うまくいかずに困っています。 困っていることは2点あります。 (1)バイナリデータにはリトルエンディアンで格納していると書いています。 まず、リトルエンディアンで書かれている場合、どのような処理を考えることが必要なのでしょうか? (2)バイナリデータには、 はじめに文字列(char)型4バイトで「RIFF]という値 次に32ビット符号なし整数で4バイトの数字、 次に4052バイトの構造体 などと収納されているようです。 このように入っているデータから値を取得するにはどのようにしたらよいのでしょうか? 全然できなくて困っています。 教えていただけないでしょうか? よろしくお願いいたします。

  • シリアル通信で0x00を送信したいのですが。

    こんにちは、VC++初心者です。 現在、下記サイトのプログラムをもとにシリアル通信用プログラムを作成しています。 http://www.takebay.net/~daigo-ao/paddlewiki.pl/title_A5B7A5EAA5A2A5EBC4CCBFAE2852532D3233324329A4C7C1F7BFAEA1A6BCF5BFAEA4F2B9D4A4A6A5D7A5EDA5B0A5E9A5E0.html 例えば、editboxに02 31 32 33 03と入力したら、0x02 0x31 0x32 0x33 0x03として送信するところまではできました。 ただし、00と入力したとき、0x00として送信することができません。 どうすれば0x00を送信できるか、ご教授お願いいたします。 m_editSend.GetWindowText()にて入手したstrSendのデータから、SPACEを除いて、 0xをつけてhexにしてから、Send()にて送信しています。 void CSerial2Dlg::OnBnClickedButtonSend() { CString strSend; CString strSendCMD; CString bw; int i, n, i2; unsigned int hex; m_editSend.GetWindowText(strSend); // ポート名を取得 char *buff = new char[strSend.GetLength()+1]; if(strSend.GetLength() == 0 || strSend == " "){ //送るものが無ければ終了 AfxMessageBox("送信するコマンドがありません。"); } else{ strcpy(buff, strSend); //editboxのデータをbuff[]へコピー i = 0; n = 0; bw = "\0"; while (buff[i] != '\n'){ if( buff[i] == ' ' || buff[i] == ':' || buff[i] == ',')//SPEACEorコロンorカンマをSKIPして送信する。 else{ bw += buff[i];//2文字ためる n++; } if(n == 2){ sscanf(bw, "%x", &hex); //bwに2文字溜まったら、hexに変換 strSendCMD += hex; bw = "\0"; //変換が終わったらClear n = 0; //カウントもリセット } i++; } m_serial->Send(strSendCMD, strlen(strSendCMD)); } delete [] buff ; //bufferの開放 } 下記のプログラムで、 WriteFileにて送信しています。 void CSerialCommunication::Send(LPCSTR str, DWORD strLength) { if (m_hComm == NULL) { AfxMessageBox("COMポートが開かれていません"); return; } // ** 送信! ** DWORD dwWrite; // COMポートに送ったバイト数 WriteFile(m_hComm, str, strLength, &dwWrite, NULL); }

  • 通信(送信)のプログラム

    bool WriteData(char *buff, unsigned int data_size) {     DWORD dwWritten; /* ポートへ書き込んだバイト数 */ WriteFile(hComm, buff, data_size, &dwWritten, NULL); if (dwWritten!=data_size) { printf("データの送信に失敗しました。\n"); return false; } return true; } 上の関数はシリアル通信の送信する関数なんですが、これに数値などを入れたいんですが、char型のため、一文字しか入れれません。たとえば、01ならchar型の0とchar型の1を別々に送らないとだめなんですが、このようにするしか無理なんでしょうか?int型の数値を好きなように入れて送りたいんですが。あと、OxFFのように16進数も入れれると便利なんですが。駄文ですいません。プログラムの知識が浅はかですいません。

  • RS232Cでバイナリーデータを送信する方法を教えてください。

    VBの初心者です。 RS232Cでバイナリーデータを送信したくVBでAPIを使いプログラムを組みたいと思っております。 色々な本を探してASCIIデータを送信するプログラムは発見し、改造を試みているのですが、WriteFile()ではどうしても&H81や&HF0と言ったデータが&H00に化けてしまいうまく送れません。 どなたか参考になる情報があれば教えて下さい。 よろしくお願い致します。

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

    シリアル通信にてデータを連続的に受信するプログラムを つくりたいと思っています. 以下のプログラムを作成して, 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_RATE 57600 #define BYTE_SIZE 5000 //250 #define PARITY NOPARITY //EVENPARITY #define STOP_BIT TRUE #define F_PARITY ONESTOPBIT 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; }

専門家に質問してみよう