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

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

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

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

Arduino

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

解決済

Arduinoで複数センサの値をSPI通信で受信したい。(大気圧・温度センサ)

kt.tk.co
kt.tk.co

総合スコア27

C

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

Arduino

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

2回答

0リアクション

0クリップ

16147閲覧

投稿2015/11/26 01:37

編集2015/11/27 14:14

Arduinoで複数センサの値をSPI通信で受信したい。大気圧・温度センサ(LPS331AP)

●目的・理想
SPI通信で8つの大気圧・温度センサ(LPS331AP)から値を取得したいです。

●現状
センサが2つまでであれば正常な値を取得できますが、3つ以上になるとセンサの値がおかしいです。

気圧:1668[mbar]/[hPa] , 温度:110[`C] など

●疑った部分
おそらくセンサの個数が問題ではなく、Arduinoのデジタルピンの制御の問題なのではないかと考えています。
SPI通信を行うためにセンサのCS(SS)ポートの配線先が、ArduinoのD10,D9であれば問題なく、D8,D7,D6であれば問題有るようです。
→再度試した所、ピンソケットの番号ではなく、2つ以上設置すると発生する模様!?(下記に記載)

●試行錯誤

  • センサや配線 : センサや配線,配線の取り回しなどを変更しても、決まってD8,D7,D6の値がおかしいです。
  • プルアップ抵抗 : 抵抗を付けてみましたが、改善なし。(正しく付けられていない可能性が高いです)
  • ソースコードのCS(SS)ポートの設定 : 初期設定が必要かもしれませんが、調べてみてもよくわからず。
  • SPIのクロックやモードなどの設定 : 調べてみてもよくわからず。適当に値を変更してみましたが変化なし。

(下2つの可能性が有力でしょうか?)

●現状
1週間近く試してみましたが、改善策が思い浮かばなくなりお手上げ状態です。
お力添え頂けますと幸いです。

■シリアルポートの出力値 (写真撮影後に、センサを5つに変更して試した結果)
Port = D10 1006[mbar]/[hPa] ,27[C] Port = D9 1002[mbar]/[hPa] ,26[C]
Port = D8 1668[mbar]/[hPa] ,110[C] Port = D7 1278[mbar]/[hPa] ,110[C]
Port = D6 423[mbar]/[hPa] ,37[`C]
…(以下、同様の値でループ)

■配線 (動作テストのため今はセンサが5つだけ)
(fritzingで配線図を書こうとしましたが、LPS331APのセンサが見つからず断念)

[ケーブル色:役割 = ピンソケット番号]
黄色:SCK = D13
白色:MISO = D12
灰色:MOSI = D11
オレンジ色:CS = D9~D6

イメージ説明

イメージ説明

イメージ説明

■コード

C

#include <SPI.h> //センサの個数を指定 int HowMenySensor = 5; //センサのCS(SS)はArduinoのD10ピンから配置すること。(D10→D9→D8→D7→D6→D5→D4→D3) //デバイスのレジスタアドレス(センサで取得できる値の格納場所など) const byte LPS331AP_WHOAMI = 0x0f;// デバイスの識別ID格納レジスタアドレス const byte LPS331AP_CTRL_PRESS = 0x10; // 圧力分解能のモード設定アドレス const byte LPS331AP_CTRL1 = 0x20;// 制御レジスタ1の設定レジスタアドレス const byte LPS331AP_CTRL2 = 0x21;// 制御レジスタ2の設定レジスタアドレス const byte LPS331AP_CTRL3 = 0x22;// 制御レジスタ3の設定レジスタアドレス const byte LPS331AP_CTRL_STATUS = 0x27; // ステータス・レジスタアドレス const byte LPS331AP_P_LL = 0x28;// 読み出すデータの先頭レジスタアドレス const byte LPS331AP_P_L = 0x29; const byte LPS331AP_CTRL_AMP = 0x30; // アナログ・フロント・エンド制御レジスタアドレス const byte LPS331AP_P_H = 0x2A; const byte LPS331AP_T_L = 0x2B; const byte LPS331AP_T_H = 0x2C; const byte LPS331AP_RW = 0x80; const byte LPS331AP_MS = 0x40; //使っていない!? //////////////////////////////// //センサへデータを書き込む関数//(センサ設定の変更用) //////////////////////////////// void LPS331AP_write(int CS, byte reg, byte val) { digitalWrite(CS, LOW); //LOWにすることで通信開始 SPI.transfer(reg); SPI.transfer(val); digitalWrite(CS, HIGH); //HIGHにすることで通信終了 } ////////////////////////////// //センサから値を受信する関数// (CSで受信先のセンサを区別。regで取得するデータ(温度or気圧)を指定) ////////////////////////////// byte LPS331AP_read(int CS, byte reg) { byte ret = 0; digitalWrite(CS, LOW); //LOWにすることで通信開始 SPI.transfer(reg | LPS331AP_RW); //読み込むデータを指示 ret = SPI.transfer(0); //データを取得 digitalWrite(CS, HIGH); //HIGHにすることで通信終了 return ret; } //////////// //初期設定// //////////// void setup() { // シリアルモニターの設定 Serial.begin(9600); Serial.println("\r\nStart"); //SPIの初期化 SPI.begin() ; // SPIを行う為の初期化 SPI.setBitOrder(MSBFIRST) ; // ビットオーダー SPI.setClockDivider(SPI_CLOCK_DIV4); // クロック(CLK)をシステムクロックの1/8で使用(16MHz/8) = 2MHz; (max 10MHz) //SPI.setDataMode(SPI_MODE3) ; // クロック極性0(LOW) クロック位相1(HIGH) // シリアルストリームが開いていないときには、何もしない: // →シリアルモニタを開いたら、セットアップをやり直す!? while (!Serial) {} //センサの個数だけ回す for (int CS_i = 10; CS_i > 10 - HowMenySensor ; CS_i--) { pinMode(CS_i, OUTPUT); // 出力に設定 delay(1000); //センサが認識していることを確かめる。 Serial.println(LPS331AP_read(CS_i, LPS331AP_WHOAMI), HEX); //BBと表示されれば、LPS331APを認識している。0なら認識していない。 //センサの設定を書き換える。 LPS331AP_write(CS_i, LPS331AP_CTRL1, B10010000); digitalWrite(CS_i, HIGH); //通信終了状態に(CSをOFFに設定) } //必要ないかも delay(1000); //確実に設定を完了させるため1秒待つ? } ////////////// //ループ処理// ////////////// void loop() { //////////////////////////////////////////////////////////////////// //多めに指定しているので、今後修正 unsigned long Pressure_val[14];// 気圧を格納する変数(unsigned long は「符号なしlong整数型」である。つまり、負の値を取らない) short Temperature_val[14]; //センサの個数だけ回す for (int CS_i = 10; CS_i > 10 - HowMenySensor ; CS_i--) { //////////////浮動小数点型で引き受ける必要があるはず////////////////////////////////////////////////// // 気圧を取得する(関数を使う) Pressure_val[CS_i] = GetPressure(CS_i); // 温度を取得する(関数を使う) Temperature_val[CS_i] = GetTemperature(CS_i); } //センサの個数だけ回す for (int CS_i = 10; CS_i > 10 - HowMenySensor ; CS_i--) { Serial.print("Port = D"); Serial.print(CS_i); Serial.print(" "); Serial.print(Pressure_val[CS_i]); // pressure in [mbar]/[hPa] Serial.print("[mbar]/[hPa] "); Serial.print(','); Serial.print(Temperature_val[CS_i]); // temprerature in [`C] Serial.println("[`C]"); } delay(1000); } ////////////////////////////////////// //センサの値に応じて、気圧を返す関数// ////////////////////////////////////// unsigned long GetPressure(int CS) { // センサから気圧を読み込む long press_xl = LPS331AP_read(CS, LPS331AP_P_LL); // 気圧の下位バイト long press_l = LPS331AP_read(CS, LPS331AP_P_L); // 気圧の中位バイト long press_h = LPS331AP_read(CS, LPS331AP_P_H); // 気圧の上位バイト //センサの値から気圧を計算する unsigned long press_val = (press_h << 16) + (press_l << 8) + (press_xl); /* 下記のif分は最上位のビットが"1"の時の処理で、ビットが"0"の時はif分をとばす (最上位のビットが"1"か"0"かによって計算が違う)*/ if (press_val >= 8388608) { press_val = ~ press_val; press_val += 1; } press_val = press_val / 4096.0; //(hPa単位に直すには4096で割る必要がある。) return press_val;//返り値に気圧を入れて返す。 } ////////////////////////////////////// //センサの値に応じて、温度を返す関数// ////////////////////////////////////// short GetTemperature(int CS) { short Temperature_val; // センサから温度を読み込みながら計算する Temperature_val = LPS331AP_read(CS, LPS331AP_T_H); Temperature_val = (Temperature_val << 8) | LPS331AP_read(CS, LPS331AP_T_L); Temperature_val = 42.5 + Temperature_val / 480.0; ////////////////////////////////////Androidに引き渡すときにはコメントアウト return Temperature_val;//返り値に温度を入れて返す。 }

■■■■■■■■■■■■■■■■■■■■■■■■
20151126追加
センサの資料
■■■■■■■■■■■■■■■■■■■■■■■■

たしかネットにPDFがあったと思いますが、すぐに見つからないのでスキャンしました。
イメージ説明
イメージ説明

「センサのピンごとの配線先」 と 「プルアップ抵抗の設置場所の確認」
イメージ説明

|
|
|
|
|
|
|
|
|
|
|
|
|
|

■■■■■■■■■■■■■■■■■■■■■■■■
20151127変更
プルアップ抵抗の追加
バイパスコンデンサの追加
GNDの配線追加
■■■■■■■■■■■■■■■■■■■■■■■■

イメージ説明
イメージ説明

結果:センサ値に変化なし

Port = D10 432[mbar]/[hPa] ,36[C] Port = D9 1010[mbar]/[hPa] ,24[C]
Port = D8 1012[mbar]/[hPa] ,24[C] Port = D7 1293[mbar]/[hPa] ,110[C]
Port = D6 1677[mbar]/[hPa] ,110[`C]

|
|
|
|
|
|
|
|
|
|
|
|
|
|

■■■■■■■■■■■■■■■■■■■■■■■■
20151127チェック
センサチェック
■■■■■■■■■■■■■■■■■■■■■■■■

センサをチェックしたところ、センサの故障の可能性が高まりました。
今までのチェックでは、シリアルポートからデータを取得している状態でセンサを外し、他のセンサへと付け替えていました。
そうすると、外したソケットの値が
760[mbar]/[hPa] ,42[`C]
に固定されてしまっていたようでした。
(考えてみるとセンサの初期設定を行えていないので当たり前ですが、頭が回っておりませんでした。)


Port = D10 760[mbar]/[hPa] ,42[C] ←ここ Port = D9 1012[mbar]/[hPa] ,26[C]
Port = D8 1013[mbar]/[hPa] ,26[C] Port = D7 940[mbar]/[hPa] ,110[C]
Port = D6 1011[mbar]/[hPa] ,27[`C]

しかし、センサを付け替えた後にシリアルポートを再度出すことで、異なるセンサの値が出ていることが確認できました。

Port = D10 1010[mbar]/[hPa] ,24[C] ←ここ Port = D9 1011[mbar]/[hPa] ,25[C]
Port = D8 1013[mbar]/[hPa] ,25[C] Port = D7 940[mbar]/[hPa] ,110[C]
Port = D6 1010[mbar]/[hPa] ,25[`C]

いままでは手元にある8つのセンサの内、2つまでしか正常な値を確認できておりませんでした。
しかし、4つまで正常な値を出すことができました!!!

すべて(8つ)をチェックした所、4つは正常、4つは異常 という状況です。
もうすこしチェックをしてみる予定ですが、本件は「センサの故障」が原因であると考えられます。

みなさま長らくお付き合いいただき有り難うございました。
予めチェックの工程なども細かく掲載しておけば、早くご指摘頂けたのではないかと反省しております。

また何かありましたら追ってご報告いたします。
みなさまのお力添えに感謝しております。
ありがとうございました。

以下のような質問にはリアクションをつけましょう

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

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

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

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

適切な質問に修正を依頼しましょう。

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

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

C

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

Arduino

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