M5Stackで始めるセンサ・インターフェーシング(8) 気圧センサLPS25HBを利用
気圧センサは従来補正パラメータが多く、それらを読み出し計算をして気圧を求めていました。ここで利用するSTMicroelectronicsのLPS25HBは、補正がICの内部で行われます。ボードは、秋月電子通商から入手しました。電源がつながるとLEDが点灯しますから、消費電力を抑えたいときはLEDの配線を切って利用します。
●LPS25HBボードのおもなスペック
- 動作電圧 3.3V(デバイスは1.7~3.6 V)
- 消費電流 約2mA(LED分を含む。ハイレゾ、1Hz測定間隔時25uA)
- 測定範囲 260~1260hPa
- 確度 ±0.1hPa(25℃)、±1hPa(0~80℃)
- インターフェース SPI、I2C。I2C用プルアップ抵抗は実装、デフォルトは切り離し
データシートはこちらからダウンロードできます。
●接続
I2Cで接続します。取扱説明書に従うと、次のようになります。ボードのピン番号は、OPアンプなどの8ピンDIPと同じように振られています。I2Cのプルアップ抵抗はM5Stack本体でつながっているので、このボードのジャンパを触りません。
ボードのピン番号 | M5Stack (GROVEコネクタ) |
---|---|
1 Vdd | 3.3 |
2 SCL | SCL |
3 SDA | SDA |
4 SA0 Vddにつないでスレーブ・アドレスは0x5d | - |
5 CS Vddに接続してI2Cモードに | |
6 NC | - |
7 INT | - |
8 GND | GND |
●気圧の読み出しと表示
気圧のデータは、3バイト24ビットです。PRESS_OUT_H (2Ah)、 PRESS_OUT_L (29h)、PRESS_OUT_XL (28h)を読み出し、4096で割るとhPaの値になります。
1Hzの繰り返しで気圧データを読み出します。電源が入ったのち、パワーダウン・モードになっているので、測定できるモードに変更します。この二つの設定は、「CTRL_REG1」(0x20)に0x90を書き込むことで実現します。
気圧データの低いアドレス28hから3バイトを読み出しますが、0x28 | 0x80の形で読まないと、正しいデータが読めません。
#include <Wire.h> #include <M5Stack.h> #define LPS25HB_address 0x5d byte readbuffer[3]; float press; void setup() { Wire.begin(); Serial.begin(9600); M5.begin(); M5.Lcd.setCursor(10, 10); M5.Lcd.print("LPS25HB start"); // Serial.println("start"); Wire.beginTransmission(LPS25HB_address); Wire.write(0x20);Wire.write(0x90); Wire.endTransmission(); } void loop() { for(int i=0; i<180; i++) { Wire.beginTransmission(LPS25HB_address); Wire.write(0x28 | 0x80); Wire.endTransmission(); Wire.requestFrom(LPS25HB_address, 3); readbuffer[0] = Wire.read(); readbuffer[1] = Wire.read(); readbuffer[2] = Wire.read(); press = (readbuffer[2] << 16 | readbuffer[1] << 8 | readbuffer[0]) / 4096.0; M5.Lcd.setTextColor(WHITE); M5.Lcd.print(" "); M5.Lcd.print(press); M5.Lcd.setTextColor(YELLOW); M5.Lcd.drawString(String(press,1),40,169,7);M5.Lcd.drawString("hPa",224,192,4); delay(1000); } M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(0, 0); }
実行結果です。print()関数では、デフォルトの小さい文字を表示します。
drawString()の最後の引数7は大きめ文字で7セグLEDの数字を表示します。引数4は、中ぐらいの大きさのASCII文字を表示します。
●気圧と温度の読み出しと関数化
確度が±2℃の温度計が内蔵されているので、そのデータを読み出し、480で割り、42.5を加算すると摂氏の温度が得られます。内蔵の温度計なので、周辺温度より高めになるようです。
読み出して16ビットにした値を(int16_t)でキャストしないと、正しいデータになりませんでした。気圧の24ビット・データも(int32_t)でキャストしていますが、こちらはキャストしなくても正しい値になりました。
#include #include #define LPS25HB_address 0x5d byte readbuffer[3]; float press; float temp; void setup() { Wire.begin(); M5.begin(); M5.Lcd.setCursor(10, 10); M5.Lcd.print("LPS25HB Press data hPa/Temp data"); Wire.beginTransmission(LPS25HB_address); Wire.write(0x20);Wire.write(0x90); // wakeup Wire.endTransmission(); } void loop() { M5.Lcd.drawString(String(readTemp(),1),50,136,6);M5.Lcd.drawString("`C",164,153,4); M5.Lcd.drawString(String(readPress(),1),40,185,6);M5.Lcd.drawString("hPa",214,200,4); delay(2000); } float readPress(){ Wire.beginTransmission(LPS25HB_address); Wire.write(0x28 | 0x80); Wire.endTransmission(); Wire.requestFrom(LPS25HB_address, 3); readbuffer[0] = Wire.read(); readbuffer[1] = Wire.read(); readbuffer[2] = Wire.read(); press = (int32_t)(readbuffer[2] << 16 | readbuffer[1] << 8 | readbuffer[0]) / 4096.0; return press; } float readTemp(){ Wire.beginTransmission(LPS25HB_address); Wire.write(0x2b | 0x80); Wire.endTransmission(); Wire.requestFrom(LPS25HB_address, 2); readbuffer[0] = Wire.read(); readbuffer[1] = Wire.read(); M5.Lcd.print(readbuffer[1]);M5.Lcd.print(" ");M5.Lcd.print(readbuffer[0]);M5.Lcd.print(" "); temp = 42.5 + (int16_t)(readbuffer[1] << 8 | readbuffer[0])/480.0; return temp; }
実行結果です。
●グラフを描く
スプライトの機能を使って、折れ線グラフを描きます。
M5.Lcd.から始まる関数は、オレンジ色の座標です。graph1.から始まる関数の座標は、グレーのスプライト領域の座標です。ただし、graph1.pushSprite(5, 20);の座標は、オレンジ色の座標です。
グラフは、スプライト領域の左から右へ '.' どっとを打っていきます。右端にくると、x座標は同じ場所にドットを打ちます。そしてスプライト領域を左にシフトします。常に新しい値がグラフになります(右端で数ドットずれているかもしれない)。
#include <Wire.h> #include <M5Stack.h> #define LPS25HB_address 0x5d byte readbuffer[3]; float press; float temp; TFT_eSprite graph1 = TFT_eSprite(&M5.Lcd); void setup() { Wire.begin(); M5.begin(); M5.Lcd.setCursor(50, 10); M5.Lcd.print("LPS25HB Press & Temp data"); Wire.beginTransmission(LPS25HB_address); Wire.write(0x20);Wire.write(0x90); // wakeup Wire.endTransmission(); graph1.setColorDepth(8); graph1.createSprite(314, 160); // 320, 240 graph1.fillSprite(BLACK); //graph1.drawString("ABCDEFGABCDEFGABCDEFG",0, 0, 4); // スプライト領域内の相対座標 }
int x=3; void loop() { graph1.pushSprite(5, 20); // x,y 左上の座標。スプライト領域内 if (x<317) { x = x+2; graph1.setTextColor(RED); graph1.drawString(".",x, 1050-int(readPress()), 4); graph1.setTextColor(CYAN); graph1.drawString(".",x, 40-int(readTemp()), 4); } else { graph1.setTextColor(GREENYELLOW); graph1.drawString(".", 310, 1050-int(readPress()), 4); graph1.setTextColor(YELLOW); graph1.drawString(".", 310, 40-int(readTemp()), 4); graph1.scroll(-1, 0); } delay(1000); M5.Lcd.drawRoundRect(0, 0, 320, 182, 2, WHITE); M5.Lcd.drawLine(1, 80, 5, 80, WHITE); M5.Lcd.setTextColor(YELLOW); M5.Lcd.fillRect(0, 186, 320, 44, TFT_BLACK); M5.Lcd.drawString(String(round(readTemp()),0),8,192,6);M5.Lcd.drawString("'C",64,208,4); M5.Lcd.setTextColor(GREENYELLOW); M5.Lcd.drawString(String(readPress(),1),102,192,6);M5.Lcd.drawString("hPa",256,208,4); } float readPress(){ Wire.beginTransmission(LPS25HB_address); Wire.write(0x28 | 0x80); Wire.endTransmission(); Wire.requestFrom(LPS25HB_address, 3); readbuffer[0] = Wire.read(); readbuffer[1] = Wire.read(); readbuffer[2] = Wire.read(); press = (int32_t)(readbuffer[2] << 16 | readbuffer[1] << 8 | readbuffer[0]) / 4096.0; return press; } float readTemp(){ Wire.beginTransmission(LPS25HB_address); Wire.write(0x2b | 0x80); Wire.endTransmission(); Wire.requestFrom(LPS25HB_address, 2); readbuffer[0] = Wire.read(); readbuffer[1] = Wire.read(); //M5.Lcd.print(readbuffer[1]);M5.Lcd.print(" ");M5.Lcd.print(readbuffer[0]);M5.Lcd.print(" "); temp = 42.5 + (int16_t)(readbuffer[1] << 8 | readbuffer[0])/480.0; return temp; }
実行結果です。途中で、センサを加熱しました。