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

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

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

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

シリアルポート

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

Xcode

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

C++

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

Arduino

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

Q&A

解決済

2回答

5447閲覧

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

Yusuke_nomecchi

総合スコア17

C

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

シリアルポート

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

Xcode

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

C++

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

Arduino

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

0グッド

0クリップ

投稿2017/11/07 08:36

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

arduino

1#define FPS 20 2unsigned long pulseWidth; 3unsigned long time0; 4int T = 1000 / FPS; 5int i = 0; 6void setup() 7{ 8 Serial.begin(9600); // Start serial communications 9 10 pinMode(2, OUTPUT); // Set pin 2 as trigger pin 11 digitalWrite(2, LOW); // Set trigger LOW for continuous read 12 13 pinMode(3, INPUT); // Set pin 3 as monitor pin 14} 15 16void loop(){ 17 time0 = millis(); 18 19 pulseWidth = pulseIn(3, HIGH); // Count how long the pulse is high in microseconds 20 // If we get a reading that isn't zero, let's print it 21 if(pulseWidth != 0){ 22 pulseWidth = pulseWidth / 10; // 10usec = 1 cm of distance 23 Serial.print(pulseWidth); // Print the distance 24 } 25 26 while((millis() - time0) < T){ 27 } 28}

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

c

1#include <stdio.h> 2#include <sys/types.h> 3#include <sys/stat.h> 4#include <sys/ioctl.h> 5#include <fcntl.h> 6#include <termios.h> 7#include <unistd.h> 8 9#define SERIAL_PORT "/dev/cu.usbmodem1411" 10 11int main(int argc, char *argv[]) 12{ 13 unsigned char msg[] = "serial port open...\n"; 14 unsigned char buf[255]; // バッファ 15 int fd; // ファイルディスクリプタ 16 struct termios tio; // シリアル通信設定 17 int baudRate = B9600; 18 int i; 19 int len; 20 int ret; 21 int size; 22 23 fd = open(SERIAL_PORT, O_RDWR); // デバイスをオープンする 24 if (fd < 0) { 25 printf("open error\n"); 26 return -1; 27 } 28 29 tio.c_cflag += CREAD; // 受信有効 30 tio.c_cflag += CLOCAL; // ローカルライン(モデム制御なし) 31 tio.c_cflag += CS8; // データビット:8bit 32 tio.c_cflag += 0; // ストップビット:1bit 33 tio.c_cflag += 0; // パリティ:None 34 35 cfsetispeed( &tio, baudRate ); 36 cfsetospeed( &tio, baudRate ); 37 38 cfmakeraw(&tio); // RAWモード 39 40 tcsetattr( fd, TCSANOW, &tio ); // デバイスに設定を行う 41 42 ioctl(fd, TCSETS, &tio); // ポートの設定を有効にする 43 44 // 送受信処理ループ 45 while(1) { 46 len = read(fd, buf, sizeof(buf)); 47 if (0 < len) { 48 for(i = 0; i < len; i++) { 49 printf("%02X", buf[i]); 50 } 51 printf("\n"); 52 } 53 54 // エコーバック 55 write(fd, buf, len); 56 } 57 58 close(fd); // デバイスのクローズ 59 return 0; 60}

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

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

環境
xcode 9.1
Arduino uno

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

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

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

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

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

guest

回答2

0

ベストアンサー

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

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

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

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

C++

1// 送信側 2// Serial.print(142); Serial.print("\n"); 3// Serial.print(146); Serial.print("\n"); 4// Serial.print(139); Serial.print("\n"); 5const char *aSend[] = {"142\n","1","46","\n1","39\n"}; // 間欠的に受信をシミュレート 6int readPos = 0; 7int SEND_CNT = sizeof(aSend)/sizeof(aSend[0]); 8int dummy_read( char buf[]) 9{ 10 if( readPos >= SEND_CNT) return -1; 11 strcpy( buf, aSend[readPos]); 12 readPos++; 13 return strlen(buf); 14} 15void ser_test( void) 16{ 17 char line_buf[256] = ""; // 行バッファ 18 while( 1){ 19 char ser_buf[256] = ""; 20 int len = dummy_read( ser_buf); 21 if( len < 0) break; // 終了 22 23 for( int i = 0; i < len; i++){ 24 char c(ser_buf[i]); 25 if( c == '\n'){ // 区切り 26 int num = atoi(line_buf); 27 printf( "%d\n", num); 28 strcpy(line_buf, ""); // 行バッファクリア 29 } 30 else{ // 行バッファに1文字追加 31 int len = strlen(line_buf); 32 line_buf[len] = c; 33 line_buf[len+1] = '\0'; 34 } 35 } 36 } 37}

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

投稿2017/11/08 02:26

can110

総合スコア38233

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

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

Yusuke_nomecchi

2017/11/08 05: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[] で受け取ることは可能ですか? すみませんが、よろしくお願いいたします。
can110

2017/11/08 06:18

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

0

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

投稿2017/11/07 09:04

fuzzball

総合スコア16731

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

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

Yusuke_nomecchi

2017/11/15 04:07

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問