大気圧センサ
UNO

概要

MPL115A2という大気圧センサを使った実験です。大気圧センサですが、大気圧以外に気温も測定できます。ただし、測定する気温は大気圧補正のための計算データとして利用するためのようで、データシートには精度については触れられていませんでした。

実際には、秋月電子通商で販売している、丸ピン実装済みの製品を利用しました。

目的

MPL115A2というセンサを使って、大気圧と気温を測定します。このセンサは、I2Cを使って通信を行うため、Wireライブラリの使い方の実験も兼ねています。

データシート

MPL115A2のデータシートを参照して、どのようなものかを調べました。

概要

MPL115A2の仕様の概要は以下の通りです。

項目 内容
電源電圧(Vdd) 2.375V~5.5V(標準3.3V)
測定範囲(大気圧) 50~115kPa(500~1150hPa)
分解能(大気圧) 0.15kPa(1.5hPa)
精度(大気圧) ±1kPa(±10hPa)
測定範囲(温度) -40℃~105℃
変換時間(開始コマンド実行後、レジスタに値が入るまでの時間)・(大気圧のみ) 標準0.6ms(最大0.7ms) ドキュメントによってはは3ms
変換時間(温度のみ) 標準0.6ms(最大0.7ms) ドキュメントによっては3ms
変換時間(大気圧・温度両方) 標準0.8ms(最大1ms) ドキュメントによっては3ms
I2Cアドレス 0x60(7ビットアドレッシング)

MPL115A2は、8ピンのデバイスで各ピンの意味は以下の通りです。

ピン番号 内容
1 VDD
2 外部キャパシタ
3 GND
4 シャットダウン(GNDに接続するとシャットダウンする)
5 RST(GNDに接続するとI2C通信抑止)
6 NC
7 データ
8 クロック入力

7番と8番は、4.7kΩの抵抗でプルアップ(VDDに接続)するよう指示があります。

また、あらかじめ、大気圧を計算するためのデータがデバイスに書き込まれていて、このデータを利用して大気圧を計算します。

インタフェース

MPL115A2は、I2Cインタフェースを利用しています。I2Cインタフェースはデータとクロックの2線で接続する単純なインタフェースです。接続するデバイスは、一つのマスターと一つ以上のスレーブです。マスターデバイスからスレーブデバイスに対して指示を出し、命令を実行します。スレーブデバイスの選択はアドレスを指定することで行います。

MPL115A2はI2Cのスレーブとして動作します。つまり、Arduinoはマスターとして動作します。このため、ArduinoがMPL115A2に対してコマンドを発行することで、大気圧を測定したり、測定したデータを取得したりすることになります。また、バス速度は400kbit/secまで動作可能なFast Modeです。

メモリ

大気圧や気温を読み取ったデータや、補正用のデータはMPL115A2のメモリ上に書き込まれます。大気圧・気温とも10ビットの数値で表されます。補正用データは96ビットです(実際に使うのは84ビットです)。以下に、メモリマップを示します。10ビットとなっているものは、16ビットのうち上位10ビットが有効で下位6ビットが0が設定されています。

アドレス 説明 サイズ(ビット)
0x00-0x01 大気圧データ 10
0x02-0x03 気温データ 10
0x04-0x0f 補正用データ 96

コマンド

MPL115A2で利用可能なコマンドを以下に示します。Xは0でも1でも構わないそうです。変換を開始するには、コマンドコードに続けて、0x01を送信する必要があるようです。また、読み取りについては、そのアドレスのデータだけしか読み取れないというわけではなく、そのアドレスからデータを読み取りを開始するというコマンドのようで、例えば、大気圧データのMSB読み取りコマンドを発行した後に続けて4バイトのデータを読み取ることができ、大気圧データ・気温データのすべてをまとめて取得できます。

コマンド コマンドコード
大気圧変換開始 X0010000
気温変換開始 X0010001
大気圧・気温変換開始 X0010010
大気圧データのMSB読み取り X0000000
大気圧データのLSB読み取り X0000001
気温データのMSB読み取り X0000010
気温データのLSB読み取り X0000011
補正用データ読み取り X0000100

データ変換

読み取ったデータを実際の大気圧に変換するには、大気圧データと気温データ、補正用データを使って変換(計算)する必要があります。

96ビット(のうちの84ビット)ある補正用データは、以下の構成となっています。

アドレス 記号 データ長(ビット) 符号ビット 整数ビット長 小数ビット長 小数点以下の0の数
0x04 a0 16 1 12 3 -
0x06 b1 16 1 2 13 -
0x08 b2 16 1 1 14 -
0x0a c12 14 1 0 13 9
0x0c c11 11 1 0 10 11
0x0e c22 11 1 0 10 15

補正用データの各ビットは以下のような構成になっています。

読み取ったデータから実際の大気圧に変換するための式は以下のようになります。

Pcomp = a0 + (b1 + c11Padc + c12Tadc) * Padc + (b2 + c22*Tadc) * Tadc

ここで、Padc・Tadcは、それぞれ、センサから読み取った大気圧データ・気温データです。この結果計算された、Pcompは、0のとき50kPa、1023のときに115kPaです。よって、Pcompを大気圧P(hPa)に変換するには、さらに、以下の計算を行います。

P = (1150 - 500) / 1023 * Pcomp + 500

実験

MPL115A2とArduinoとの接続

MPL115A2とArduinoとを以下のように接続します。

MPL115A2のピン番号 Arduinoのピン番号
1 5V
2 コンデンサ(1.0μF)→GND
3 GND
4 5V
5 5V
6 接続しない
7 A4、4.7kΩの抵抗でプルアップ
8 A5、4.7kΩの抵抗でプルアップ

簡単な回路図を以下に示します。A4・A5はArduinoのアナログの4番・5番です。

Arduinoプログラミング

MPL115A2はI2Cプロトコルを利用するため、上記を実現するためにはArduinoで標準提供されているWireライブラリを利用します。具体的には、以下のような手順でプログラムを動作させることになります。

  • Wireライブラリの初期化
  • 補正データの取得
  • 大気圧データと気温データの取得
  • 上記で取得したデータを利用して大気圧の計算

連続して動作させる場合は、補正データは最初の1回だけ取得、その後、大気圧データ・気温データの取得と大気圧の計算の繰り返しとすることになります。

初期化

Wireライブラリを利用するために、setup()の中で、以下のWire.begin()を実行します。

補正データ・大気圧データ・気温データの取得

補正データを取得するには、データ取得用のコマンドを送信したあと、データを取得します。

コマンドを送信するには、Wire.beginTransmission()を発行したあと、コマンド列を、Wire.write()でキューイングし、最後にWire.endTransmission()を実行してキューイングしたデータを送信します。Wire.endTransmission()は戻り値を返す関数で0が正常終了、それ以外は異常終了です。とはいえ、ここでエラーが出ても救済策がないのでこのプログラムでは戻り値は無視しています。例えば、MPL115A2とArduinoとを接続する回路がおかしいときなどはエラーが返ってきました。なお、ここでエラーが出るとその後の処理も失敗するので、結果としては何も表示されません。

次いで、Wire.requestFrom()を実行し、Wire.available()でデータを確認し、必要なバイト数をWire.read()で取得します。

Wire.beginTransmission()には、引数としてI2Cアドレスを指定します。今回は0x60です。補正データの取得のためのコマンドは0x04(=b00000100)で、補正データは12バイトなので、以下のようにします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Wire.beginTransmmision(0x60); //データ送信開始
Wire.write(0x04); //データ(コマンド)のキューイング
Wire.endTransmission(); //キューイングしたデータの送信

Wire.requestFrom(0x60, 12); //I2Cアドレス0x60から、12バイトの読み出しを要求
if(Wire.available()) {
  val1 = Wire.read();  //12バイト読み取る
  val2 = Wire.read();
  
 val12 = Wire.read();
}

大気圧データと気温データを取得するには、まず、大気圧・気温変換開始コマンドを送信し、その後、大気圧データの先頭アドレスを指定して4バイト読み出すと、最初の2バイトが大気圧データ、残りの2バイトが気温データが読み出されます。以下は、大気圧・気温変換開始コマンドを送信するためのプログラムです。

1
2
3
4
Wire.beginTransmission(0x60);
Wire.write(0x12); //大気圧・気温変換開始コマンド
Wire.write(0x01);
Wire.endTransmission();

大気圧の計算

大気圧を計算するには、前述したとおり、補正データと大気圧データ、気温データを用います。

補正データを実際の値に変換するためには以下のようにします。

  • 1バイト読み取り: msb = Wire.read()
  • 1バイト読み取り: lsb = Wire.read()
  • msbとlsbを16ビットの値に変換: (msb « 8) + lsb
  • 変換した値を、 1 « (16 - データ長 + 小数ビット長 + 小数点以下の0の数) で割る

上記で1を左シフトしていますが、最大で30ビットシフトするので、long型の1をシフトする必要があることに注意してください。

上記のlsbは、データによっては無効なデータを含んでいますが、0が代入されているため無視して構いません。

以下に、a0とc12についての概念図を示します。

スケッチ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <Wire.h>
 
const int address = 0x60;
 
float read_coefficients(int total_bits, int fractional_bits, int zero_pad) {
  unsigned char msb, lsb;
   
  msb = Wire.read();
  lsb = Wire.read();
   
  return ((float) ((msb << 8) + lsb) / ((long)1 << 16 - total_bits + fractional_bits + zero_pad));
}
 
unsigned int read_adc() {
  unsigned char msb, lsb;
  msb = Wire.read();
  lsb = Wire.read();
   
  return (((unsigned int)msb << 8) + lsb) >> 6;
}  
 
float a0, b1, b2, c12, c11, c22;
 
void setup () {
  Wire.begin();
  Serial.begin(9600);
   
  Wire.beginTransmission(address);
  Wire.write(0x04);        // Read coefficient data
  Wire.endTransmission();
   
  Wire.requestFrom(address, 12);  // Request 12 bytes
  if (Wire.available()) {
    a0 = read_coefficients(16, 3, 0);
    b1 = read_coefficients(16, 13, 0);
    b2 = read_coefficients(16, 14, 0);
    c12 = read_coefficients(14, 13, 9);
    c11 = read_coefficients(11, 10, 11);
    c22 = read_coefficients(11, 10, 15);
  }
}
 
void loop () {
  Wire.beginTransmission(address);
  Wire.write(0x12);      // Start both conversions(Pressure and Temperature)
  Wire.write(0x01);
  Wire.endTransmission();
 
  delay(5);
 
  Wire.beginTransmission(address);
  Wire.write((uint8_t)0x00);  // Read pressure and temperature
  Wire.endTransmission();
 
  Wire.requestFrom(address, 4); // Request 4 bytes
 
  if(Wire.available()) {
    unsigned int Padc = read_adc();
    unsigned int Tadc = read_adc();
   
    float Pcomp = a0 + (b1 + c11 * Padc + c12 * Tadc) * Padc + (b2 + c22 * Tadc) * Tadc;
    float hpa = Pcomp * 650 / 1023 + 500;
    Serial.println(hpa);
  }
   
  delay(1000);
}

バージョン

Hardware:Arduino Uno
Software:Arduino 1.0.5

最終更新日

November 1, 2022

inserted by FC2 system