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
1#include <SPI.h> 2 3//センサの個数を指定 4int HowMenySensor = 5; 5//センサのCS(SS)はArduinoのD10ピンから配置すること。(D10→D9→D8→D7→D6→D5→D4→D3) 6 7//デバイスのレジスタアドレス(センサで取得できる値の格納場所など) 8const byte LPS331AP_WHOAMI = 0x0f;// デバイスの識別ID格納レジスタアドレス 9const byte LPS331AP_CTRL_PRESS = 0x10; // 圧力分解能のモード設定アドレス 10const byte LPS331AP_CTRL1 = 0x20;// 制御レジスタ1の設定レジスタアドレス 11const byte LPS331AP_CTRL2 = 0x21;// 制御レジスタ2の設定レジスタアドレス 12const byte LPS331AP_CTRL3 = 0x22;// 制御レジスタ3の設定レジスタアドレス 13const byte LPS331AP_CTRL_STATUS = 0x27; // ステータス・レジスタアドレス 14const byte LPS331AP_P_LL = 0x28;// 読み出すデータの先頭レジスタアドレス 15const byte LPS331AP_P_L = 0x29; 16const byte LPS331AP_CTRL_AMP = 0x30; // アナログ・フロント・エンド制御レジスタアドレス 17const byte LPS331AP_P_H = 0x2A; 18const byte LPS331AP_T_L = 0x2B; 19const byte LPS331AP_T_H = 0x2C; 20 21const byte LPS331AP_RW = 0x80; 22const byte LPS331AP_MS = 0x40; //使っていない!? 23 24 25//////////////////////////////// 26//センサへデータを書き込む関数//(センサ設定の変更用) 27//////////////////////////////// 28 29void LPS331AP_write(int CS, byte reg, byte val) 30{ 31 digitalWrite(CS, LOW); //LOWにすることで通信開始 32 SPI.transfer(reg); 33 SPI.transfer(val); 34 digitalWrite(CS, HIGH); //HIGHにすることで通信終了 35} 36 37 38////////////////////////////// 39//センサから値を受信する関数// (CSで受信先のセンサを区別。regで取得するデータ(温度or気圧)を指定) 40////////////////////////////// 41 42byte LPS331AP_read(int CS, byte reg) 43{ 44 byte ret = 0; 45 46 digitalWrite(CS, LOW); //LOWにすることで通信開始 47 SPI.transfer(reg | LPS331AP_RW); //読み込むデータを指示 48 ret = SPI.transfer(0); //データを取得 49 digitalWrite(CS, HIGH); //HIGHにすることで通信終了 50 51 return ret; 52} 53 54 55 56//////////// 57//初期設定// 58//////////// 59 60void setup() 61{ 62 // シリアルモニターの設定 63 Serial.begin(9600); 64 Serial.println("\r\nStart"); 65 66 //SPIの初期化 67 SPI.begin() ; // SPIを行う為の初期化 68 SPI.setBitOrder(MSBFIRST) ; // ビットオーダー 69 SPI.setClockDivider(SPI_CLOCK_DIV4); // クロック(CLK)をシステムクロックの1/8で使用(16MHz/8) = 2MHz; (max 10MHz) 70 //SPI.setDataMode(SPI_MODE3) ; // クロック極性0(LOW) クロック位相1(HIGH) 71 72 73 // シリアルストリームが開いていないときには、何もしない: 74 // →シリアルモニタを開いたら、セットアップをやり直す!? 75 while (!Serial) {} 76 77 //センサの個数だけ回す 78 for (int CS_i = 10; CS_i > 10 - HowMenySensor ; CS_i--) { 79 80 pinMode(CS_i, OUTPUT); // 出力に設定 81 82 delay(1000); 83 //センサが認識していることを確かめる。 84 Serial.println(LPS331AP_read(CS_i, LPS331AP_WHOAMI), HEX); //BBと表示されれば、LPS331APを認識している。0なら認識していない。 85 86 //センサの設定を書き換える。 87 LPS331AP_write(CS_i, LPS331AP_CTRL1, B10010000); 88 89 digitalWrite(CS_i, HIGH); //通信終了状態に(CSをOFFに設定) 90 } 91 92 //必要ないかも 93 delay(1000); //確実に設定を完了させるため1秒待つ? 94 95} 96 97 98 99////////////// 100//ループ処理// 101////////////// 102 103void loop() 104{ 105 106 //////////////////////////////////////////////////////////////////// 107 //多めに指定しているので、今後修正 108 unsigned long Pressure_val[14];// 気圧を格納する変数(unsigned long は「符号なしlong整数型」である。つまり、負の値を取らない) 109 short Temperature_val[14]; 110 111 112 //センサの個数だけ回す 113 for (int CS_i = 10; CS_i > 10 - HowMenySensor ; CS_i--) { 114 //////////////浮動小数点型で引き受ける必要があるはず////////////////////////////////////////////////// 115 116 // 気圧を取得する(関数を使う) 117 Pressure_val[CS_i] = GetPressure(CS_i); 118 119 // 温度を取得する(関数を使う) 120 Temperature_val[CS_i] = GetTemperature(CS_i); 121 122 } 123 124 125 //センサの個数だけ回す 126 for (int CS_i = 10; CS_i > 10 - HowMenySensor ; CS_i--) { 127 128 Serial.print("Port = D"); 129 Serial.print(CS_i); 130 Serial.print(" "); 131 132 Serial.print(Pressure_val[CS_i]); // pressure in [mbar]/[hPa] 133 Serial.print("[mbar]/[hPa] "); 134 Serial.print(','); 135 Serial.print(Temperature_val[CS_i]); // temprerature in [`C] 136 Serial.println("[`C]"); 137 138 } 139 140 delay(1000); 141} 142 143 144 145////////////////////////////////////// 146//センサの値に応じて、気圧を返す関数// 147////////////////////////////////////// 148unsigned long GetPressure(int CS) { 149 150 // センサから気圧を読み込む 151 long press_xl = LPS331AP_read(CS, LPS331AP_P_LL); // 気圧の下位バイト 152 long press_l = LPS331AP_read(CS, LPS331AP_P_L); // 気圧の中位バイト 153 long press_h = LPS331AP_read(CS, LPS331AP_P_H); // 気圧の上位バイト 154 155 //センサの値から気圧を計算する 156 unsigned long press_val = (press_h << 16) + (press_l << 8) + (press_xl); 157 158 /* 下記のif分は最上位のビットが"1"の時の処理で、ビットが"0"の時はif分をとばす 159 (最上位のビットが"1"か"0"かによって計算が違う)*/ 160 if (press_val >= 8388608) { 161 press_val = ~ press_val; 162 press_val += 1; 163 } 164 press_val = press_val / 4096.0; //(hPa単位に直すには4096で割る必要がある。) 165 166 return press_val;//返り値に気圧を入れて返す。 167 168} 169 170 171////////////////////////////////////// 172//センサの値に応じて、温度を返す関数// 173////////////////////////////////////// 174 175short GetTemperature(int CS) { 176 177 short Temperature_val; 178 179 // センサから温度を読み込みながら計算する 180 Temperature_val = LPS331AP_read(CS, LPS331AP_T_H); 181 Temperature_val = (Temperature_val << 8) | LPS331AP_read(CS, LPS331AP_T_L); 182 Temperature_val = 42.5 + Temperature_val / 480.0; ////////////////////////////////////Androidに引き渡すときにはコメントアウト 183 184 return Temperature_val;//返り値に温度を入れて返す。 185}
■■■■■■■■■■■■■■■■■■■■■■■■
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つは異常 という状況です。
もうすこしチェックをしてみる予定ですが、本件は「センサの故障」が原因であると考えられます。
みなさま長らくお付き合いいただき有り難うございました。
予めチェックの工程なども細かく掲載しておけば、早くご指摘頂けたのではないかと反省しております。
また何かありましたら追ってご報告いたします。
みなさまのお力添えに感謝しております。
ありがとうございました。

回答2件
あなたの回答
tips
プレビュー
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。
2015/11/26 02:57
2015/11/26 03:01
2015/11/26 03:03
2015/11/26 03:09
2015/11/26 03:26
2015/11/26 03:42
2015/11/26 04:01 編集
2015/11/26 04:22
2015/11/26 04:44 編集
2015/11/26 04:59
2015/11/26 05:07 編集
2015/11/26 05:14
2015/11/27 14:15