• ベストアンサー

VISCAプロトコル(RS232C通信)のプログラム

VISCAプロトコル(RS232C通信)のプログラムがうまく動きません。 大学の研究にてSONYのEVI-D100というカメラをパソコンから制御する必要が出てきました。 このカメラはVISCAプロトコル(RS232C通信)で制御するらしく、シリアル通信でコマンドを送る以下のようなプログラムをウェブで見つけて参考にしています。 http://onishi-lab.jp/programming/rs232c_win.html しかし、短いコマンド(例:カメラを右にパンする、81 01 06 01 10 10 02 03 FF)は動くのですが、長いコマンド(例:カメラのパンチルト上限を設定、81 01 06 07 00 01 0F 0A 05 00 0F 0E 09 08 FF)になるとコマンド中に0が入ると動いてくれません。また、コマンド中に0がなくても思うような動きをしてくれません。 一応自分で通信タイムアウトは書き加えたのですが、それでもうまく動きません GetCommTimeouts( hCom, &cto ); // タイムアウトの設定状態を取得 cto.ReadIntervalTimeout = 0; cto.ReadTotalTimeoutMultiplier = 0; cto.ReadTotalTimeoutConstant = 1000; cto.WriteTotalTimeoutMultiplier = 0; cto.WriteTotalTimeoutConstant =1000; SetCommTimeouts( hCom, &cto ); // タイムアウトの状態を設定 RS232Cについては初心者なのでよくわからないことも多いのですが、どこをどう書き換えれば動くかなどを教えていただけると幸いです。よろしくお願いします。 EVI-D100のマニュアルページへのリンクを貼っておきます。 http://www.totsu.co.jp/isp/ispproducts/pdf/D100_tec.pdf

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

  • ベストアンサー
回答No.2

sprintf(send,"\x88\x01\x00\x01\xff"); send_length=5; などと記載されている一連のコマンド設定コードを memcpy(send,"\x88\x01\x00\x01\xff", 5); send_length=5; で解決だと思いますけど。

ario316
質問者

お礼

ありがとうございます。無事正常に動かすことができました。 RS232Cの問題というよりC言語の関数の問題だったんですね。失礼しました。

その他の回答 (2)

noname#144013
noname#144013
回答No.3

ario316さん、はじめまして。 後述した内容をカキコミしようと思っていたところ、既に解決されたようで良かったですね。(^_^) 以下は投稿しようと用意していたものですが、参考までにカキコミしてみます。 ※ario316さんが返答される前のものなので、KY(^^;)な部分は予めご了承ください。 ======================================= まず、【回答:ANo.1】のJaritenCatさんも言われているように、EVI-D100のテクニカルマニュアル をよく読んで、送信するコマンド、データ等の形式(コマンド値、データ範囲、データ長など)が合っ ているかどうかの確認、およびラインモニタなどを使用し、送信したデータ、EVI-D100からの応答 メッセージ等の確認をされた方が良いと思います。 あと、デバッグ用にバイナリデータが送信できる市販またはフリーの「RS-232C通信ソフト」を使用 して、手入力またはマクロ機能(簡易プログラム機能)などを使い、EVI-D100へテストコマンド及び データを送信して正常に送受信できるか確認されるのも良いかと思います。 それと、【回答:ANo.2】のpenguin999さんも指摘されているように、そもそも参考にされている サンプルプログラム自体が間違っています。 (このサンプルを作成&公開された方は、ちゃんとテストされたのでしょうか?) sprintfに限らず、C言語の文字列を扱う標準関数では、文字列の途中にNULLコード ('\x00'、16進値=0x00)を含んだものは扱うことはできません。 なぜなら、NULLコードは文字列の終端コードとして扱われているからです。 関数が文字列を処理している時にNULLコードに達するとそこで処理を終了します。 参考にされているサンプルの例で言うと、   sprintf(send,"\x88\x01\x00\x01\xff"); の部分の実際の処理は、   バッファ"send"には、'\xff'までコピーされずに、"\x88\x01"までしかコピーされない。   ※'\x00'は文字列の終端コードなため。 だと思います。 この関数を実行した後のバッファ"send"の中身は、   0x88、0x01、0x00、・・・・・・・・・  (・・・の部分はsprintfを実行する前の値) となってしまうと思います。(0x00は終端コードとしてsprintfが付加します) 解決策として、ここはpenguin999さんが書かれているとおり、文字列用の関数を使うのではなく、 バッファ転送用の関数(memcpyなど)を使ってデータコピーするのが得策だと思います。 ※memcpy関数は単純に指定したバイト数分のバッファコピーを行います。 C/C++言語の標準関数(ランタイムライブラリ等)の詳細仕様については、お使いの開発環境 付属のマニュアルおよび、C/C++言語関連の書籍等をご覧になってください。 =======================================

ario316
質問者

お礼

詳しい説明どうもありがとうございます。 C言語の方もまだまだ勉強が必要なようです・・・。 精進したいと思います

回答No.1

コマンドを送ったら機器からレスポンスが送信されてくると思うのですが正常が返ってくるのでしょうか? ちらっとマニュアルを見る限りでは、 81 01 06 07 00 01 0F 0A 05 00 0F 0E 09 08 FF は、YYYY=FA50を設定していますが範囲外だと思います。 FA60(-1440)~05A0(1440)に指定しないとだめではないでしょうか。 このコマンドを送ったときエラーは返ってきますか? 通信プログラムが期待通りのデータを送信しているかどうかは、RS-232Cラインモニタなどを使うと分かります。 もし変なデータを送っているのであれば、ソフトの問題でしょう。

ario316
質問者

お礼

ご指摘のとおり、設定パラメータがおかしかったことも一要因だったようです。ご指摘ありがとうございます。符号付16進数のことがよくわかっていませんでした。 コマンドを送ったときにエラーすら帰ってこない状態だったのですが、そちらについてはpenguin999さんからの回答で解決しました。ありがとうございました。

関連するQ&A

  • VISCAプロトコル(RS232C通信)で、やはり長いコマンドを正しく

    VISCAプロトコル(RS232C通信)で、やはり長いコマンドを正しく送れない 次のサイトのソースをもとに、SONY EVI-HD1カメラをPCからVC++プログラムで制御しようとしています: http://onishi-lab.jp/programming/rs232c_win.html ただし、以前あった以下の質問を参考に、ソースをいくつか修正しています: http://okwave.jp/qa/q4296092.html 具体的には、下記の変更を加えました: (1)"sprintf"ではなく"memcpy"関数を使うようにする (2)"dcb.fOutxDsrFlow = bSet;"の部分は"bSet = dcb.fOutxDsrFlow;" の誤りと思われるので修正 以前の質問では(1)の修正により解決されたようでしたが、実際に試してみると問題がありました。 これは、前の方が質問の中で報告されている通り、 「短いコマンド(例:カメラを右にパンする、81 01 06 01 10 10 02 03 FF)は動くが、長いコマンド(例:カメラのパンチルト上限を設定、81 01 06 07 00 01 0F 0A 05 00 0F 0E 09 08 FF)になるとコマンド中に00が入ると動かない。また、コマンド中に0がなくても思うような動きをしない」 というものです。 私が試したところ(1)の修正に関係なく、上の問題が発生するようです。 ・なぜ長いコマンドになると問題があるのか? ・なぜ00が入るとコマンド書き込みが上手くいかないのか? など見当がつかず、混乱しております。 もし何か心当たりがありましたら教えていただければ大変助かります。

  • RS232CとPCの通信

    RS232Cを使って、PCとシリアル通信をしたいのですが、 RS232Cの通信について、制御線や手順について詳しく書いてあるサイトを知りたいです。 もしご存知でしたら、教えていただきたいです。 よろしくお願いします。

  • Visual C++はSCPIプロトコルに準拠していますか?

    研究で直流電源を使おうと考えているのですが これはVisual C++で制御できますか? Visual C++はVisual C++.net version2003です 電源のカタログには 「パソコンなどによる制御、監視に対応するRS-232C、RS-485の2系統のシリアル通信ポートを標準で装備しています。 オプションのマルチ接続ケーブルを使えば1個のシリアルポートで31台までのZXシリーズが制御できます。 通信コマンドはSCPIプロトコルに準拠した形式と当社EXシリーズ互換のコマンドから選択できるので、システム側ソフトウェアの小規模な変更でEXシリーズから置き換えが可能です。」 とありました

  • プロトコルの決め方(RS232C)

    VB6.0を使用して、画像処理プログラムの開発を行っているのですが、処理結果を別機器(PLC)へ送信しなければならなくなりました。漠然とRS232Cでデータ通信を行おうと考えてたのですが、上司から「まずプロトコルを決めないと、232Cもクソもないやろ」と怒鳴られました。232Cの使用を前提として、プロトコルを決めたいと思うのですが、上司に説明する文書としてどのような書式を用いればよいのか見当がつきません。(トホホ明日中に説明しろと言われております) VBと別機器の動作としては、別機器からスタート信号をもらい、PCで画像撮像・処理を行い、処理データ(小数点以下3位程度×2個)を別機器へ送信するといったものです。 上記動作そのものが「プロトコルを決める」ということではありませんよね?スタート信号や処理完了信号の文字を決定するところまでを含めて「プロトコルを決める」ということなのでしょうか? アプリケーションとしては複雑なものではないのですが、いかんせん基本が分かっていないので、私の説明も理解していただき難いものがあるかと思います。上記動作のアプリケーションに似たプロトコルのサンプル文書があれば非常に助かるのですが。。。 よろしくお願い致します。

  • RS422通信について

    訳あってRS422A通信ポートのついた温調器を、RS232C、またはRS422Aでパソコン制御することになりました。が、私はほとんど初心者で途方にくれています。近辺の書店、ヤ○ダ電気などを周りましたが参考になる書籍が見つかりませんでした。 通信制御のイロハについて教えてくださるようなサイトはないでしょうか?どうかご教示お願いいたします。

  • RS-232-C で通信する方法について

    UNIX 環境を使っています。 RS-232-C を使って通信をしたいのですが、UNIX のCで何かよい命令は無いでしょうか?またはどのように実現できるでしょうか?(プロトコルは分かりません。確かIEEE 482勧告か何かが事実上標準になっている、と書いてあったのですが、その辺も教えていただけると洗いがたいです。) もし分かれば、教えていただきたいです。

  • RS232C通信のタイムアウトが働きません

    http://okwave.jp/qa3351570.htmlの続きです。 お陰様でDLしたクラスの意味もほぼ理解でき、昔作成したPICボードにコマンドを送信し、返信を受け取る事ができました。試行錯誤の過程で、PCから送るコマンドの末尾に\rを付けないと、書き放しになってしまい、タスクマネージャから該当するプロセスを終了させないと終わらなくなる事が判明しました(自分で設定したプロトコルですが...)。上記クラスには、タイムアウト設定の関数(単純にSetCommTimeoutsを実行しているだけ)もあったため、試しに読み書きのタイムアウト値をを設定してみましたが、改善されません。タイムアウト値が意図した通り設定されている事は、読み出して確認しました。今は、\rをつけてやって動いてはいるのですが、 ・このケースで、タイムアウトが機能しないのは何故か ・タイムアウトが働くと、APIはどのような挙動をしめすのか 教えていただきたく、お願いします。

  • RS232cと通信が可能な、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→RS485変換

    専門カメラとPLCを無手順の通信でつなぐようにしていますがうまくいきません。 カメラはRS232C通信仕様。 PLCは、RS485通信ポート。 そこであるメーカーのIC-485Sという変換器を使っていますが、接続及び設定がわかりません。 カメラ出力D-Sub9Pin Pin2:SD、3:RD、4:DR、5:SG、6:ER、7:CS、8:RS →ストレート9cケーブル→D-Sub9pinオス・メス変換コネクタ→D-Sub9Pin/25Pin変換→IC485S変換器→4cケーブル→PLC485ポート(SDA,SDB,RDA,RDB) IC-485Sには切替スイッチあり。 SW1:DCE-DTE-Monitor(の3段階) SW2:TxO、RxON-TxRTS、RxRTS(RTSには上部に棒線あり、排他?)TxRTS、RxON(の3段階) この変換器なのですが、メーカーからは232Cの通信経路を延長する為の変換器なので2台セットで使用するのが標準。と言う回答。 ですが、232Cを485で通信するので1つでも通信可能の補足回答も有り。 現場の立ち上げで困っています。予算が無く、変換器等を再購入する時間及び予算なし。(すでにIC-485Sを10台購入) 通信関係で詳しい方、ご教授願えないですか。

  • RS232C通信のC言語プログラム:入力モード?

    ある計測機器(以後(A)と略記)と"一般的な"Linux PC(Kernel 2.4xx)とをRS232Cシリアルポートで接続し、コマンドの送信とデータの受信を一定時間間隔(1秒)で行うためのC言語プログラムを作成しようとしています。第一段階として、Windows XPのソフトウェア:ハイバーターミナルで(A)にコマンドパケット(10バイト程度)を送信し、それに対応するデータ(20バイト程度)を(A)の取り扱い説明書どおり、正しく受け取ることができました。(A)の受け付ける通信データフォーマットは”8 data bits, 1 stop bit, no parity bit"で、通信ケーブルはいわゆる3線式で、フロー制御は用いません。通信レートは9600baudです。  (A)から返される20バイト程度(長さはまちまちです)のデータパケットは全て、最後が[;FF]の"アルファベット3文字"で終わっていて、いわゆる”行末コード”は付加されていません(取扱説明書でも確認ずみ)。このような場合に、linux上でのC言語プログラムで(A)が接続された/dev/ttyS* (*は一桁の数字)から、どのような入力モードでread()すればよいか、アドバイスをお願いいたします。事前調査の段階ですが、今考えている方法は (1)ループの中で、ノンブロッキングモードでひと文字ずつ読んで、自分で用意したバッファに納めつつ、その最後が";FF"になったらループを脱出する というものですが、制御用のLinux PCは他にも”作業をしていて”、(A)とのデータの授受の負荷は軽いほどよいので、より賢明な方法がないか探しています。 たとえば、 (2)カノニカルモードで、一時的に、”行末コード”にセミコロン";"を指定して、read()する などということは可能でしょうか。これが可能なら、次の"FF"は、2文字を指定して”読み捨てる”ことも可能になります。 わかりにくい説明で恐縮ですが、他のアイデアなどを含めて、アドバイスをお願いいたします。

専門家に質問してみよう