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

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

ただいまの
回答率

90.86%

  • Linux

    3364questions

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

  • C

    3319questions

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

  • Debian

    105questions

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

  • COM

    33questions

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

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 131

cafe_takai

score 17

 行いたいこと

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

 症状

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

 確認済み事項

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

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

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#define SERIAL_PORT "/dev/ttyS0"  // シリアルインターフェースに対応するデバイスファイル
#define BAUD_RATE   B9600                // RS232C通信ボーレート

int main(int argc, char *argv[])
{
    char rBuf[255] = {'\0'}, sBuf[255] = {'\0'};        // バッファ
    int fd, i, len;
    struct termios tio;               // シリアル通信設定

    fd = open(SERIAL_PORT, O_RDWR);   // デバイスをオープンする
    tio.c_cflag += CREAD;             // 受信有効
    tio.c_cflag += CLOCAL;            // ローカルライン(モデム制御なし)
    tio.c_cflag += CS8;               // データビット:8bit
    tio.c_cflag += 0;                 // ストップビット:1bit
    tio.c_cflag += 0;                 // パリティ:None
    tio.c_cc[VMIN] = 0;
    tio.c_cc[VTIME] = 30;
    // ボーレートの設定
    cfsetispeed(&tio,BAUD_RATE);
    cfsetospeed(&tio,BAUD_RATE);
    ioctl(fd, TCSETS, &tio);           // ポートの設定を有効にする
    strcpy(sBuf,"TC\r\n");
    write(fd, sBuf, 4);                // デバイスへ書き込み
    printf("%s\n", sBuf);
    len = read(fd, rBuf, sizeof(rBuf));   // デバイスから255バイト読み込み
    if (0 < len) {
        for(i = 0; i < len; i++) {
          printf("%s", rBuf[i]);
        }
        printf("\n");
    }
    close(fd);                        // デバイスのクローズ
    return 0;
}


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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

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

    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 13: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の状態でシリアルから電文は送られていないようです。

    キャンセル

  • 2018/06/07 13:28 編集

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

    キャンセル

  • 2018/06/07 13:33

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

    キャンセル

  • 2018/06/07 13:48 編集

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

    キャンセル

  • 2018/06/07 13:56

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

    キャンセル

  • 2018/06/07 14:00

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

    キャンセル

  • 2018/06/07 14:02

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

    キャンセル

  • 2018/06/07 14:05

    > 実機が遠隔にあり、直ぐにご返答できない

    いえいえ、今分かる限り、と言うのは仕方無いです。連投したのはこちらの勝手ですのでお気になさらないでください。

    > printf("%2X", rBuf[i]); に変更したうえでチャレンジしてみます。

    おそらく当初の意図としてはprintf("%c", rBuf[i])かな、と思いましたが、"%2X"でも良いと思います。(こちらの方が確実)

    キャンセル

  • 2018/06/08 08:41

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

    キャンセル

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

  • ただいまの回答率 90.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Linux

    3364questions

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

  • C

    3319questions

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

  • Debian

    105questions

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

  • COM

    33questions

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