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

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

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

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

Arduino

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

Q&A

解決済

3回答

8152閲覧

ArduinoでI2C通信とBluetoothシリアル通信を両立させる方法について

zum1309

総合スコア17

C++

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

Arduino

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

0グッド

0クリップ

投稿2018/03/01 04:00

数か月前から電子工作を始めました。
ArduinoとPCのBluetooth通信について行き詰ってしまったため教えていただけると幸いです。

###最終目標
ArduinoにI2C通信のセンサを取り付け、センサの値をBluetoothチップのシリアル通信でPCで受信する

###構成
・Arduino側
Arduino UNO
Bluetoothチップ RN-42使用 Bluetooth評価キット
6軸センサ MPU6050使用

・Arduino配線
MPU6050とArduinoの配線
VCCと5V
GNDとGND
SCLとSCL
SDAとSDA
で配線

Bluetoothチップの配線はこちらを参考にさせていただきました。

・PC側
ubuntu16.04でbluemanを使用して接続
BluetoothドングルはLBT-UAN05C2/Nを使用

###問題点
Bluetooth通信の参考にさせていただいたこちらのサイト通りに試したところ正常にハードウェアシリアルで通信が可能でした。
ArduinoIDEのシリアルモニタで仮想シリアルポートrfcommを指定してArduinoからのシリアル送信を受信することが出来ます。

ですが、MPU6050からI2C通信でデータを取得しようとするとシリアルモニタで何も受信できなくなってしまいます。
MPU6050とのI2C通信はArduinoUNO付属のUSBケーブルを用いてのシリアル通信では成功しています。

以下、問題のスケッチです。

lang

1// MPU-6050 Accelerometer + Gyro 2 3// I2CにアクセスするためにWireライブラリを使用 4#include <Wire.h> 5 6// レジスタアドレス 7#define MPU6050_ACCEL_XOUT_H 0x3B // R 8#define MPU6050_WHO_AM_I 0x75 // R 9#define MPU6050_PWR_MGMT_1 0x6B // R/W 10#define MPU6050_I2C_ADDRESS 0x68 11#define MPU6050_GYRO 131.0 12#define MPU6050_G 16384.0 13 14double acc_x = 0; 15double acc_y = 0; 16double acc_z = 0; 17 18double gyro_x = 0; 19double gyro_y = 0; 20double gyro_z = 0; 21 22 23// 構造体定義 24typedef union accel_t_gyro_union { 25 struct { 26 uint8_t x_accel_h; 27 uint8_t x_accel_l; 28 uint8_t y_accel_h; 29 uint8_t y_accel_l; 30 uint8_t z_accel_h; 31 uint8_t z_accel_l; 32 uint8_t t_h; 33 uint8_t t_l; 34 uint8_t x_gyro_h; 35 uint8_t x_gyro_l; 36 uint8_t y_gyro_h; 37 uint8_t y_gyro_l; 38 uint8_t z_gyro_h; 39 uint8_t z_gyro_l; 40 } 41 reg; 42 struct { 43 int16_t x_accel; 44 int16_t y_accel; 45 int16_t z_accel; 46 int16_t temperature; 47 int16_t x_gyro; 48 int16_t y_gyro; 49 int16_t z_gyro; 50 } 51 value; 52}; 53 54// デバイス初期化時に実行される 55void setup() { 56 int error; 57 uint8_t c; 58 59 Wire.begin(); 60 61 // ボーレートを115200bpsにセット 62 Serial.begin(115200); 63 //Serial.print("MPU-6050 "); 64 65 // 初回の読み出し 66 error = MPU6050_read(MPU6050_WHO_AM_I, &c, 1); 67 Serial.print("WHO_AM_I : "); 68 Serial.print(c, HEX); 69 Serial.print(", error = "); 70 Serial.println(error, DEC); 71 72 // 動作モードの読み出し 73 error = MPU6050_read(MPU6050_PWR_MGMT_1, &c, 1); 74 Serial.print("PWR_MGMT_1 : "); 75 Serial.print(c, HEX); 76 Serial.print(", error = "); 77 Serial.println(error, DEC); 78 79 // MPU6050動作開始 80 MPU6050_write_reg(MPU6050_PWR_MGMT_1, 0); 81} 82 83void loop() { 84 int error; 85 float dT; 86 accel_t_gyro_union accel_t_gyro; 87 88 // 加速度、角速度の読み出し 89 // accel_t_gyroは読み出した値を保存する構造体、その後ろの引数は取り出すバイト数 90 error = MPU6050_read(MPU6050_ACCEL_XOUT_H, (uint8_t *)&accel_t_gyro, sizeof(accel_t_gyro)); 91 92 // I2C通信正常終了 93 if(error == 0){ 94 // 取得できるデータはビッグエンディアンなので上位バイトと下位バイトの入れ替え(AVRはリトルエンディアン) 95 uint8_t swap; 96 #define SWAP(x,y) swap = x; x = y; y = swap 97 SWAP (accel_t_gyro.reg.x_accel_h, accel_t_gyro.reg.x_accel_l); 98 SWAP (accel_t_gyro.reg.y_accel_h, accel_t_gyro.reg.y_accel_l); 99 SWAP (accel_t_gyro.reg.z_accel_h, accel_t_gyro.reg.z_accel_l); 100 SWAP (accel_t_gyro.reg.t_h, accel_t_gyro.reg.t_l); 101 SWAP (accel_t_gyro.reg.x_gyro_h, accel_t_gyro.reg.x_gyro_l); 102 SWAP (accel_t_gyro.reg.y_gyro_h, accel_t_gyro.reg.y_gyro_l); 103 SWAP (accel_t_gyro.reg.z_gyro_h, accel_t_gyro.reg.z_gyro_l); 104 105 // 取得した加速度値 106 acc_x += accel_t_gyro.value.x_accel ; 107 acc_y += accel_t_gyro.value.y_accel ; 108 acc_z += accel_t_gyro.value.z_accel ; 109 110 // 取得した角速度値 111 gyro_x += accel_t_gyro.value.x_gyro ; 112 gyro_y += accel_t_gyro.value.y_gyro ; 113 gyro_z += accel_t_gyro.value.z_gyro ; 114 115 Serial.print("\t"); 116 Serial.print(error, DEC); 117 Serial.print(","); 118 Serial.print(acc_x); 119 Serial.print(","); 120 Serial.print(acc_y); 121 Serial.print(","); 122 Serial.print(acc_z); 123 Serial.print(","); 124 Serial.print(gyro_x); 125 Serial.print(","); 126 Serial.print(gyro_y); 127 Serial.print(","); 128 Serial.print(gyro_z); 129 Serial.println(""); 130 131 delay(100); 132 133 } 134} 135 136// MPU6050_read 137int MPU6050_read(int start, uint8_t *buffer, int size) { 138 int i, n, error; 139 Wire.beginTransmission(MPU6050_I2C_ADDRESS); 140 n = Wire.write(start); 141 if (n != 1) { 142 return (-10); 143 } 144 n = Wire.endTransmission(false);// hold the I2C-bus 145 if (n != 0) { 146 return (n); 147 } 148 // Third parameter is true: relase I2C-bus after data is read. 149 Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true); 150 i = 0; 151 while (Wire.available() && i < size) { 152 buffer[i++] = Wire.read(); 153 } 154 if ( i != size) { 155 return (-11); 156 } 157 return (0); // return : no error 158} 159 160// MPU6050_write 161int MPU6050_write(int start, const uint8_t *pData, int size) { 162 int n, error; 163 Wire.beginTransmission(MPU6050_I2C_ADDRESS); 164 n = Wire.write(start);// write the start address 165 if (n != 1) { 166 return (-20); 167 } 168 n = Wire.write(pData, size);// write data bytes 169 if (n != size) { 170 return (-21); 171 } 172 error = Wire.endTransmission(true); // release the I2C-bus 173 if (error != 0) { 174 return (error); 175 } 176 177 return (0);// return : no error 178} 179 180// MPU6050_write_reg 181int MPU6050_write_reg(int reg, uint8_t data) { 182 int error; 183 error = MPU6050_write(reg, &data, 1); 184 //Serial.print("error = "); 185 //Serial.println(error); 186 return (error); 187}; 188

ソースを部分的に変えておかしくなる箇所を特定していったところ
Wire.beginTransmission(MPU6050_I2C_ADDRESS);
の命令があるとBluetoothを経由してシリアル通信ができなくなっているようです。
MPU6050がつながっているSDAとSCLについて調べたところ、それぞれシリアルデータピンとシリアルクロックピンとの事でしたので、もしかしてこのピンで通信しているとTX、RXピンを用いたシリアル通信はできないのでしょうか?
何かわかることがあればよろしくお願いします。

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

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

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

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

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

guest

回答3

0

ざっと見ただけで詳細までは目を通していませんが、、
シリアル通信、IIC通信はビジーループで実装してますよね?

#プログラムで受信/送信ステータスをチェックし、データ可の状態に
#なればデータの読み出し/書き込みを行う

こういう組み方をすると、たとえばシリアル通信をしている間はIICの通信は出来ません。
また、IIC通信をしている間はシリアル通信はできなくなります
これをどうにかするには、シリアル通信、IIC通信のどちらか、あるいは両方を、割り込みで駆動する方式に変える必要があります

投稿2018/03/01 04:38

y_waiwai

総合スコア87747

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

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

zum1309

2018/03/01 05:12

回答ありがとうございます。 やはりI2C通信している間はRX、TXピンでの通信はできないということですね。 ビジーループというものは実装していないので調べてみたいと思います。 他にも具体的にこうすればいいなどありましたらよろしくお願いします。
y_waiwai

2018/03/01 05:20

というか、IIC通信している間は、CPUはIICの通信待ちをしてしまうため、シリアルの通信処理に移れない、ということです。 同様にシリアル通信している間はCPUIはシリアルの通信待ちをしてしまう(以下略 決してIICとシリアルの通信が同時に行えないというわけではありません
nullbot

2018/03/01 05:20

``` while (Wire.available() && i < size) { buffer[i++] = Wire.read(); } ``` これがビジーループです。
zum1309

2018/03/01 05:42

error = MPU6050_read(MPU6050_ACCEL_XOUT_H, (uint8_t *)&accel_t_gyro, sizeof(accel_t_gyro)); の関数でI2C通信で読取しています。 この関数ではaccel_t_gyro構造体のサイズ分だけ読み込んだらI2C通信を終了していると思っていたのですが違うのでしょうか?
y_waiwai

2018/03/01 06:05

それはそのとおりです。 問題なのは、その関数を呼び出したら、そのサイズ分の通信が終わるまで戻ってこない、ということです。 当然その間は他の処理はできません(もちろんシリアル通信の処理も)
zum1309

2018/03/01 06:09

回答ありがとうございます。 >問題なのは、その関数を呼び出したら、そのサイズ分の通信が終わるまで戻ってこない、ということです。 >当然その間は他の処理はできません(もちろんシリアル通信の処理も) そちらは理解しています。 なので while (Wire.available() && i < size) { buffer[i++] = Wire.read(); } の部分でI2C通信が終わるまでループで待ち、I2C通信が終わってから Serial.print(""); でシリアル送信を行っており、I2C通信とシリアル通信を同時に行っていないというのが私の認識です。 私の認識に間違いがあったら教えていただけると助かります。
y_waiwai

2018/03/01 06:23

ああ、IIC通信を行ったらそれ以降シリアル通信が出来ないってことですか。 本来、シリアルとIICは同時に使えるはずのものですんで、プログラムに何かバグがあることになりますね 提示されたコードだけではどこにバグがあるかというのは判別できないので、 IIC通信を行う前と後で、CPUのシリアルユニットのレジスタの設定を比較して設定が変わっていないかチェックすること、シリアル通信の関数のどの箇所でおかしくなるか、などを追いかけていってバグの箇所を特定していく必要があります
zum1309

2018/03/01 06:54

回答頂いた内容で調べてみたいと思います。 全く同じスケッチでタイプB→タイプAのUSBケーブルの有線接続では問題なく通信ができたのでプログラムに異常はないと思い込んでいました。 回答ありがとうございます。
guest

0

結論から書きますと、Wire.writeをした際にエラーが発生し、そのエラーコードが4(その他のエラー)の場合にそれ以降プログラムが動かなくなるようでした。

その他のエラーが発生した理由としましては、センサのチップの配線の長さが1.5mほどあったため、電流が放電されて足りなくなったのではないかと思われます。
Bluetoothの通信を試していた時はモバイルバッテリーからの給電のため、PCからの給電と比べると電力不足なのかもしれません。
ひとまずセンサチップへの配線を10cmほどの短いものに変えたところ、Wire.writeでエラーコード4のエラーが発生しなくなりました。

エラーが発生した際の処理なども考えなくてはなりませんが、ひとまず当初の目的であったI2Cでセンサの値を取り、Bluetoothでシリアル送信することは達成できましたので解決とさせていただきます。

知識の浅い私に丁寧に回答して頂いたお二人に、改めて感謝申し上げます。
ありがとうございました。

投稿2018/03/01 08:00

zum1309

総合スコア17

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

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

0

ベストアンサー

"PCで"シリアル受信できないのですね。読み間違えていました。

直感的にはエラー時にendTransmissionを呼び出していないので、2回連続でbeginTransmissionを呼び出すケースがあるので、ここで刺さりそうです。(エラー時に呼び出す必要があるかは確認していません)

投稿2018/03/01 06:21

編集2018/03/01 06:22
nullbot

総合スコア910

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

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

zum1309

2018/03/01 06:52

ArduinoUNO付属のタイプB→タイプAケーブルで接続した場合は問題なくセンサの値をシリアル通信で取得できます。 なのでプログラムのバグではないと思っていましたが、これは有線の場合はRX、TXピンを使用しないで通信を行う為でしょうか? プログラム自体にバグがないか、いらないコードを少しずつ削ったりして試してみます。 回答ありがとうございます。
nullbot

2018/03/01 07:16

> これは有線の場合はRX、TXピンを使用しないで通信を行う為でしょうか? 理由はわかりませんが、有線の場合(USBシリアル)をつかう場合RX, TXピンを使用しないと言うのは間違いです。USBシリアルの素子にRX, TXが接続されています。なので参考にされているページでも > ハードウェアシリアルを使用する場合には、プログラム書き込み時には、Rx、Txの結線を取り除き、実行時に再度結線します。 > ソフトウェアシリアルを使用する場合には、実行時の結線のままプログラム書き込みができます。 という注意書きがされています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問