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

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

ただいまの
回答率

91.02%

  • Xcode

    3509questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • C

    3075questions

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

  • C++

    2932questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Arduino

    438questions

    Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

  • シリアルポート

    32questions

    シリアルポートは一度に一ビットごと移行される物理的なインターフェイスです。一般的には、9ピンのd-subコネクタであるRS-232を指します。

センサーを繋いだarduinoとのシリアル通信をCかC++で行いたいです。

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 796

題名に書いた通りですが、シリアル通信でC言語でセンサーからの出力値を得たいです。
まずarduino側のコードを載せます。

#define FPS 20
unsigned long pulseWidth;
unsigned long time0;
int T = 1000 / FPS;
int i = 0;
void setup()
{
  Serial.begin(9600); // Start serial communications

  pinMode(2, OUTPUT); // Set pin 2 as trigger pin
  digitalWrite(2, LOW); // Set trigger LOW for continuous read

  pinMode(3, INPUT); // Set pin 3 as monitor pin
}

void loop(){
  time0 = millis();

  pulseWidth = pulseIn(3, HIGH); // Count how long the pulse is high in microseconds
    // If we get a reading that isn't zero, let's print it
    if(pulseWidth != 0){
      pulseWidth = pulseWidth / 10; // 10usec = 1 cm of distance
      Serial.print(pulseWidth); // Print the distance
    }

  while((millis() - time0) < T){
  }
}


この出力値をC/C++言語で読み取りたいのですが、下記のコードでは問題がありました。

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

#define SERIAL_PORT "/dev/cu.usbmodem1411"

int main(int argc, char *argv[])
{
    unsigned char msg[] = "serial port open...\n";
    unsigned char buf[255];             // バッファ
    int fd;                             // ファイルディスクリプタ
    struct termios tio;                 // シリアル通信設定
    int baudRate = B9600;
    int i;
    int len;
    int ret;
    int size;

    fd = open(SERIAL_PORT, O_RDWR);     // デバイスをオープンする
    if (fd < 0) {
        printf("open error\n");
        return -1;
    }

    tio.c_cflag += CREAD;               // 受信有効
    tio.c_cflag += CLOCAL;              // ローカルライン(モデム制御なし)
    tio.c_cflag += CS8;                 // データビット:8bit
    tio.c_cflag += 0;                   // ストップビット:1bit
    tio.c_cflag += 0;                   // パリティ:None

    cfsetispeed( &tio, baudRate );
    cfsetospeed( &tio, baudRate );

    cfmakeraw(&tio);                    // RAWモード

    tcsetattr( fd, TCSANOW, &tio );     // デバイスに設定を行う

    ioctl(fd, TCSETS, &tio);            // ポートの設定を有効にする

    // 送受信処理ループ
    while(1) {
        len = read(fd, buf, sizeof(buf));
        if (0 < len) {
            for(i = 0; i < len; i++) {
                printf("%02X", buf[i]);
            }
            printf("\n");
        }

        // エコーバック
        write(fd, buf, len);
    }

    close(fd);                              // デバイスのクローズ
    return 0;
}

このURLから引っ張ってきたコードですが、これではlenの値が正しく反映されません(正しい行数が出てこない)。また出力を10進数で出したいです。
かなり丸投げな質問ですが、よろしくお願いいたします。

ちなみに出力したらこんな感じに出てきます。
・出力例
313432
31
3436
31
3439
3134
・本来出て欲しい出力
143
143
142
141
143
142

環境
xcode 9.1
Arduino uno

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

送信側からは142146139…という文字の並びが順次送られてきています。
一方受信側は、この通信がいつ終わるか分からないので、実はread関数は適当(勝手)なタイミングで受信データを区切って呼出元に返します。
すなわちread関数の結果(バッファの中身)は、142 1 46 1 39 …となっています。

これでは送信した数値の区切りが分かりません。
そこで、送信側で、受信側がデータの区切りが分かるような文字を付加して送るようにします。

ここでデータ(文字列)+区切り文字と表現します。
受信側は区切り文字が来るまで(数値)文字を行バッファに溜めておき、区切り文字が来たら行バッファに溜まった数値文字列を数値に変換すればよいです。
ちなみに、区切り文字は改行文字\r,\nなどを用いるのが一般的です。

以下は疑似的な検証コードです。

// 送信側
// Serial.print(142); Serial.print("\n");
// Serial.print(146); Serial.print("\n");
// Serial.print(139); Serial.print("\n");
const char  *aSend[] = {"142\n","1","46","\n1","39\n"};    // 間欠的に受信をシミュレート
int readPos = 0;
int SEND_CNT = sizeof(aSend)/sizeof(aSend[0]);
int dummy_read( char buf[])
{
    if( readPos >= SEND_CNT) return -1;
    strcpy( buf, aSend[readPos]);
    readPos++;
    return strlen(buf);
}
void ser_test( void)
{
    char line_buf[256] = "";    // 行バッファ
    while( 1){
        char ser_buf[256] = "";
        int len = dummy_read( ser_buf);
        if( len < 0) break; // 終了

        for( int i = 0; i < len; i++){
            char c(ser_buf[i]);
            if( c == '\n'){    // 区切り
                int num = atoi(line_buf);
                printf( "%d\n", num);
                strcpy(line_buf, "");    // 行バッファクリア
            }
            else{            // 行バッファに1文字追加
                int len = strlen(line_buf);
                line_buf[len] = c;
                line_buf[len+1] = '\0';
            }
        }
    }
}

参考:ArduinoとMacでシリアル通信(C言語)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/08 14:58

    ```C++
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <unistd.h>
    #include <iostream>
    using namespace std;
    #define SERIAL_PORT "/dev/cu.usbmodem1411"


    int dummy_read( char buf[], char *aSend[]) {
    int readPos = 0;
    int SEND_CNT = sizeof(aSend)/sizeof(aSend[0]);
    if( readPos >= SEND_CNT) return -1;
    strcpy( buf, aSend[readPos]);
    readPos++;
    return strlen(buf);
    }int main(int argc, char *argv[])
    {
    unsigned char msg[] = "serial port open...\n";
    char *aSend[255]; // バッファ
    char line_buf[256] = "";
    int fd; // ファイルディスクリプタ
    struct termios tio; // シリアル通信設定
    int baudRate = B9600;

    fd = open(SERIAL_PORT, O_RDWR); // デバイスをオープンする
    if (fd < 0) {
    printf("open error\n");
    return -1;
    }

    tio.c_cflag += CREAD; // 受信有効
    tio.c_cflag += CLOCAL; // ローカルライン(モデム制御なし)
    tio.c_cflag += CS8; // データビット:8bit
    tio.c_cflag += 0; // ストップビット:1bit
    tio.c_cflag += 0; // パリティ:None

    cfsetispeed( &tio, baudRate );
    cfsetospeed( &tio, baudRate );

    cfmakeraw(&tio); // RAWモード

    tcsetattr( fd, TCSANOW, &tio ); // デバイスに設定を行う

    ioctl(fd, TCSANOW, &tio); // ポートの設定を有効にする

    // 送受信処理ループ
    while(1) {
    char ser_buf[256] = "";
    int len = dummy_read( ser_buf, aSend);
    if( len < 0) break; // 終了

    for( int i = 0; i < len; i++){
    char c(ser_buf[i]);
    if( c == '\n'){ // 区切り
    int num = atoi(line_buf);
    printf( "%d\n", num);
    strcpy(line_buf, ""); // 行バッファクリア
    }
    else{ // 行バッファに1文字追加
    int len = strlen(line_buf);
    line_buf[len] = c;
    line_buf[len+1] = '\0';
    }

    }
    }
    close(fd); // デバイスのクローズ
    return 0;
    }
    ```
    こう書きましたがうまくいきませんでした。
    そもそもどこの行で受信した値を*aSend[255]に入れているのでしょうか‥。
    また受信した値をchar *aSend[] で受け取ることは可能ですか?
    すみませんが、よろしくお願いいたします。

    キャンセル

  • 2017/11/08 15:18

    回答のコードはあくまで検証用なのでそのまま組み込んでも動作しません。
    内容を確認、理解したうえで適切に組み込む必要があります。
    具体的にはdummy_read関数はご自身のread関数のままでよいです。
    その後に行バッファ処理を加える形になるかと思います。
    参考URLも記載していますので確認ください。

    キャンセル

0

「出力例」はアスキーコードのように見えるので、受信した値は「142 146 139 ...」ではないかと思います。「本来出て欲しい出力」と値自体は違いますが、フォーマットとしては正しそうです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/15 13:07

    いつも回答本当にありがとうございます。
    フォーマットを合わせたら解決しました!

    キャンセル

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

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

関連した質問

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

  • Xcode

    3509questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • C

    3075questions

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

  • C++

    2932questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Arduino

    438questions

    Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

  • シリアルポート

    32questions

    シリアルポートは一度に一ビットごと移行される物理的なインターフェイスです。一般的には、9ピンのd-subコネクタであるRS-232を指します。