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;
}
実行結果です。途中で、センサを加熱しました。