質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

COM

COM(Component Object Model)はMicrosoftによるコンポーネントテクノロジーであり、 ソフトウェアの再利用を目的とした技術を指します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Debian

Debianは、Debian GNU/Linux などのOS(オペレーティングシステム)です。

Q&A

解決済

1回答

4001閲覧

Linuxでシリアル送信ができない

cafe_takai

総合スコア27

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

COM

COM(Component Object Model)はMicrosoftによるコンポーネントテクノロジーであり、 ソフトウェアの再利用を目的とした技術を指します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Debian

Debianは、Debian GNU/Linux などのOS(オペレーティングシステム)です。

0グッド

1クリップ

投稿2018/06/07 01:22

編集2018/06/07 23:43

行いたいこと

Linux(Debian)から外部デバイスに対してシリアル通信を行いたくプログラムを記載しています。
言語はCで、Linux側のシリアルは/dev/ttyS0として認識しています。

症状

外部デバイスに対して"TC\r\n"を送信すると、時刻情報が戻ってくるはずなのですが、どうもシリアル送信できていないようなのです。
なお外部デバイスからデータを手動で送ってもらうと、なぜか受信はできており、送信だけができない状態のようなのです。なお受信確認は別なプログラムで、無限ループの中、readを行っているだけのものです。

確認済み事項

  • /dev/ttyS0アクセスに対する権限付与
  • ユーザのdialoutグループへの追加
  • minicomからの送受信(成功)

ソース(異常処理等割愛)

C

1#include <sys/types.h> 2#include <sys/stat.h> 3#include <sys/ioctl.h> 4#include <fcntl.h> 5#include <termios.h> 6#include <unistd.h> 7#include <string.h> 8#include <stdio.h> 9 10#define SERIAL_PORT "/dev/ttyS0" // シリアルインターフェースに対応するデバイスファイル 11#define BAUD_RATE B9600 // RS232C通信ボーレート 12 13int main(int argc, char *argv[]) 14{ 15 char rBuf[255] = {'\0'}, sBuf[255] = {'\0'}; // バッファ 16 int fd, i, len; 17 struct termios tio; // シリアル通信設定 18 19 fd = open(SERIAL_PORT, O_RDWR); // デバイスをオープンする 20 tio.c_cflag += CREAD; // 受信有効 21 tio.c_cflag += CLOCAL; // ローカルライン(モデム制御なし) 22 tio.c_cflag += CS8; // データビット:8bit 23 tio.c_cflag += 0; // ストップビット:1bit 24 tio.c_cflag += 0; // パリティ:None 25 tio.c_cc[VMIN] = 0; 26 tio.c_cc[VTIME] = 30; 27 // ボーレートの設定 28 cfsetispeed(&tio,BAUD_RATE); 29 cfsetospeed(&tio,BAUD_RATE); 30 ioctl(fd, TCSETS, &tio); // ポートの設定を有効にする 31 strcpy(sBuf,"TC\r\n"); 32 write(fd, sBuf, 4); // デバイスへ書き込み 33 printf("%s\n", sBuf); 34 len = read(fd, rBuf, sizeof(rBuf)); // デバイスから255バイト読み込み 35 if (0 < len) { 36 for(i = 0; i < len; i++) { 37 printf("%s", rBuf[i]); 38 } 39 printf("\n"); 40 } 41 close(fd); // デバイスのクローズ 42 return 0; 43} 44

ご教授、賜れましたら幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

少なくとも明らかにひとつコードに問題があって、

struct termios tio; // シリアル通信設定 fd = open(SERIAL_PORT, O_RDWR); // デバイスをオープンする tio.c_cflag += CREAD; // 受信有効 tio.c_cflag += CLOCAL; // ローカルライン(モデム制御なし) ...

とある部分で、struct termios tio;と宣言されただけで、中はゴミのまま、メンバー変数に CREAD等をセットしています。これだとゴミのビットパターンがセットされたままになり、不適切な設定がされてしまう可能性が高いです。memsetなり宣言時の初期化なりで、あらかじめ0クリアしてください。

また、write()などのシステムコール実行時は返り値のチェックと、エラーであればerrnoをチェックしてください。
もし書き込みでBUSY状態のようなことになっていれば、selectで書き込み可となるまで待機した方が良いかと思われます。

あと気になったこととしては、+=でビットパターンをセットしている部分で、ビットパターンを扱う上では良い書き方ではありません。セット(ON)するときは|= 値 、OFFにするときは&= ~値としましょう。(今回の問題のケースに直接関係は無いと思いますが)

投稿2018/06/07 03:09

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cafe_takai

2018/06/07 04:10

dodox86様 ご回答、ありがとうございます。ご指摘に従い、次の通り追記してみました。 memset(&tio,0,sizeof(tio)); // 初期化 j = write(fd, sBuf, 4); // デバイスへ書き込み printf("%d, errno=%d: %s\n", j, errno, strerror(errno)); 結果としてですが症状としては変わらず、jには4が入り、errno=0: Successの状態でシリアルから電文は送られていないようです。
dodox86

2018/06/07 04:28 編集

minicomでは送受信成功とのことですが、minicomで送信した内容が、デバイス側で正しく受信できている、との意味ですよね。デバイスではなく、対抗のPCの端末にして受信させてみたり、シリアルのクロスケーブルで自PCに折り返して確認したりはできないでしょうか。
dodox86

2018/06/07 04:33

デバイス側が結果としてどう動くか、と言うより、デバイス側(受信側)でどのようなデータを受信できているか(できていないか)を確認するのが先決だと思います。
dodox86

2018/06/07 04:50 編集

連投すみません。もしかしたらデバイスへのwriteでの送信はちゃんと成功していて、デバイス側は受信できているものの、readが早すぎてデバイス側からのレスポンスを受信する前に終わっちゃっているということはありませんでしょうか。9,600bpsは結構遅いです。readの前に少しwaitを入れてみてください。まぁ、readでブロックしているのであればwaitで待機の必要は無いですが。
dodox86

2018/06/07 04:56

readで返り値が0なら恐らくブロックしてないでシステムコールからすぐ戻っているので、readの呼び出しが早すぎといえます。 もうひとつコードの問題を指摘させていただきますと、printf("%s", rBuf[i]); の部分がバグです。SIGSEGVで落ちると思います。
cafe_takai

2018/06/07 05:00

dodox86様 早速のご回答、ありがとうございます。minicomについては改行コード(\r\n)の都合、本来の電文ではなく、何かしらの送受信はできているとの確認までで、電文内容まで確認できておりません。 ご教授いただいた通り、相手側デバイスをPCに変え、minicomやWindowsのTeraTermなどを使用して、電文がきちんと送受信できてるか、まず確認してみます。 最後に言い訳がましくて恐縮ですが、実機が遠隔にあり、直ぐにご返答できないのですが、色々とご指導賜り、感謝申し上げます。ありがとうございます。
cafe_takai

2018/06/07 05:02

再度のアドバイス、ありがとうございます。 waitを入れ、printf("%s", rBuf[i]); → printf("%2X", rBuf[i]); に変更したうえでチャレンジしてみます。
dodox86

2018/06/07 05:05

> 実機が遠隔にあり、直ぐにご返答できない いえいえ、今分かる限り、と言うのは仕方無いです。連投したのはこちらの勝手ですのでお気になさらないでください。 > printf("%2X", rBuf[i]); に変更したうえでチャレンジしてみます。 おそらく当初の意図としてはprintf("%c", rBuf[i])かな、と思いましたが、"%2X"でも良いと思います。(こちらの方が確実)
cafe_takai

2018/06/07 23:41

昨晩、確認させていただきました(私自身ではないのですが…)。結果、次の通りです。 ① 送信側はWin10(ホストOS)+VirtualBox(Vagrant)でのLinux(Debian)。 ② 相手デバイスから送信するとminicom/自作PGとも受信できるが、共に送信できていない。  → minicomから送信可と申しましたが不可のようでした。失礼いたしました。 ③ ホスト側をRaspberryPIに変更したところ送受信できるようになった。  → プログラムの変更はありません。 アドバイスいただきました通り、プログラムを疑う前に実機にて動作確認が先でした。真の原因究明までには至っておりませんが、プログラムとしてはご指導いただいた内容で問題ありませんでした。 お騒がせし申し訳ありませんことと、適切なアドバイス頂戴しましたこと感謝申し上げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問