概要
Raspberry pi 2 Model B (Raspbian)での aitendo M180-4P(BMP180使用 気圧センサモジュール) 設定覚書き
参考
参考にしました、ありがとうございます。
センサーモジュール接続
ここのピンアウト表を参照しました。今回は、1,3,5,9ピンを使用し設定します。
5Vトレラントなので、5Vで接続したほうが安定するかもしれません。
3.3Vで使ってみて様子をみます。
センサーモジュール設定情報
説明書を読んでみます。
このセンサーは、以下のようなレジスタ構成になっています。
-
MSB(out_msb), LSB(out_lsb), XLSB(out_xlsb)
測定データが入ります。
温度(UT)は、16ビットになります。MSBとLSBを使います。
気圧(UP)は、モードにより16ビット〜19ビットになります。MSB, LSB, XLSBを使います。
【oss(oversampling_setting)】:
2ビットで、温度測定時は、00。気圧測定時は、ここの設定でモードを決めます。
4種類のモードとソフトウェア的に精度を上げた(複数回計測しているだけですが)1計測毎内部サンプリング回数が32回のモードの5種類があります。
【sco】:
1ビットで、1の間は、計測中です。計測が完了すると0になります。
【measurement】:
5ビットで、温度測定は、"01110"。気圧測定は、"10100"です。
測定したいモードの設定値を0xF4のコントロールレジスタに(例えば、温度なら0x2E)書き込み、変換時間待ったのち、out_msb, out_lsb, out_xlsbから計測値を取得すればよいようです。
-
soft(Soft reset)
0xB6を書き込むと電源リセットと同様のシーケンスでソフトリセットされます。 -
id
0x55(固定値)です。接続確認などに使います。 -
calib21-calib0(補正値)
各16ビットの11補正パラメータです。AC4, AC5, AC6がunsignedで、それ以外のパラメータは、signedです。
補正値は、気温、気圧を計算する際、以下の計算式で使用します。
結構、めんどくさい計算です。その分、正確な値が計測できるのかな。
【補正値 AC1, AC2, AC3, AC4, AC5, AC6, B1. B2, MB, MC, MD】
各補正値 = ((各補正値のMSB << 8) | 各補正値のLSB);
【気温 t】
UT = ((MSB << 8) | LSB);
X1 = ((UT - AC6) * AC5 >> 15);
X2 = ((MC << 11) / (X1 + MD));
B5 = (X1 + X2);
t = ((B5 + 8) >> 4);
t / 10.0 ℃
【気圧 p】
UP = ((MSB << 16) | (LSB << 8) | XLSB) >> (8 - oss)
B3の計算
B6 = (B5 - 4000);
X1 = ((B6 * B6) >> 12);
X1 = (X1 * B2);
X1 = (X1 >> 11);
X2 = (AC2 * B6);
X2 = (X2 >> 11);
X3 = (X1 + X2);
B3 = (AC1 * 4 + X3);
B3 = ((B3 << oss) + 2);
B3 = (B3 >> 2);
B4の計算
X1 = ((AC3 * B6) >> 13);
X2 = ((B6 * B6) >> 12);
X2 = ((B1 * X2) >> 16);
X3 = ((X1 + X2) + 2) >> 2;
B4 = (AC4 * (X3 + 32768)) >> 15;
pの計算
B7 = ((UP - B3) * (50000 >> oss));
if (B7 < 0x80000000) {
p = (B7 << 1) / B4;
} else {
p = (B7 / B4) << 1;
}
X1 = p >> 8;
X1 *= X1;
X1 = (X1 * 3038) >> 16;
X2 = (p * -7357) >> 16;
p += (X1 + X2 + 3791) >> 4;
p / 100.0 hPa
センサーモジュール設定手順
I2C有効
$ sudo raspi-config
「8 Advanced Options」 → 「A7 SPI」 → 「I2C enable」
I2Cモジュール設定
$ sudo nano /etc/modules
snd-bcm2835
i2c-dev
I2Cライブラリインストール
$ sudo sudo apt-get install libi2c-dev
gitインストール
$ sudo apt-get install git-core
アップデート
$ sudo apt-get update
$ sudo apt-get upgrade
センサーモジュールアドレス確認
たぶん、0x77だと思います。
$ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77
センサーモジュール接続確認
データを取得できるか試すため、idを取得してみます。
0x55が返ってくれば正しく接続できています。
$ sudo i2cget -y 1 0x77 0xD0 b
0x55
サンプルコード
このサンプルコードは、温度と気圧のソフトウェア精度モードを取得します。
BMP180は、扱いやすいセンサーのようです。
Pythonでadafruitのドライバを利用している方が多いようでした。
センサーの使い方を勉強するため、説明書を読んで、メーカーのドライバとadafruitのドライバのソースコードを読んでみました。
BMP085と下位互換があるようですので、Raspbianに入っているbmp085のカーネルモジュールで簡単に動作するのかもしれません。試してないです。
まずは、シェルスクリプトで気温の値が取得できるか挑戦してみました。
実は、16bitのsignedの扱いでそうとう苦労しました。
あまり綺麗な方法でないと思っています。
何か良い計算方法があったら教えて下さい。
#!/bin/bash
AC5_MSB=$(sudo i2cget -y 1 0x77 0xB2 b)
AC5_LSB=$(sudo i2cget -y 1 0x77 0xB3 b)
AC5=$((AC5_MSB<<8|AC5_LSB))
AC6_MSB=$(sudo i2cget -y 1 0x77 0xB4 b)
AC6_LSB=$(sudo i2cget -y 1 0x77 0xB5 b)
AC6=$((AC6_MSB<<8|AC6_LSB))
MC_MSB=$(sudo i2cget -y 1 0x77 0xBC b)
MC_LSB=(sudo i2cget -y 1 0x77 0xBD b)
MC=$(printf "0x%x" $((MC_MSB<<8|MC_LSB)))
if [ $(printf "%d" $MC) -gt 32767 ];then
MC=$((((MC^0xffff)+1)*-1))
else
MC=$(printf "%d" $MC)
fi
MD_MSB=$(sudo i2cget -y 1 0x77 0xBE b)
MD_LSB=$(sudo i2cget -y 1 0x77 0xBF b)
MD=$((MD_MSB<<8|MD_LSB))
sudo i2cset -y 1 0x77 0xF4 0x2E b
sleep 1
UT_MSB=$(sudo i2cget -y 1 0x77 0xF6 b)
UT_LSB=$(sudo i2cget -y 1 0x77 0xF7 b)
UT=$((UT_MSB<<8|UT_LSB))
X1=$((((UT-AC6)*AC5)>>15))
X2=$(((MC<<11)/(X1+MD)))
B5=$((X1+X2))
TEMPERATURE=$(((B5+8)>>4))
printf "Temprature: %.2f C\n" $(echo "scale=2;$TEMPERATURE / 10.0" | bc)
exit 0
サンプルコードは、WiringPiとBoschのドライバを利用しています。
気になるところや間違いなどあればコメントいただけると助かります。
$ cd
$ git clone git://git.drogon.net/wiringPi
$ cd wiringPi
$ ./build
$ cd ..
$ git clone https://github.com/BoschSensortec/BMP180_driver.git
$ cd BMP180_driver
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include "bmp180.h"
s8 BMP180_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt);
s8 BMP180_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt);
void BMP180_delay_msek(u32 msek);
int main(void)
{
struct bmp180_t bmp180;
s32 com_rslt = E_BMP_COMM_RES;
u16 v_uncomp_temp_u16 = BMP180_INIT_VALUE;
u32 v_uncomp_press_u32 = BMP180_INIT_VALUE;
bmp180.bus_write = BMP180_I2C_bus_write;
bmp180.bus_read = BMP180_I2C_bus_read;
bmp180.dev_addr = BMP180_I2C_ADDR;
bmp180.delay_msec = BMP180_delay_msek;
com_rslt = bmp180_init(&bmp180);
if(com_rslt < 0) {
printf("error: Initialization failed\n");
}
bmp180.sw_oversamp = BMP180_SW_OVERSAMP_U8X;
bmp180.oversamp_setting = BMP180_OVERSAMP_SETTING_U8X;
v_uncomp_temp_u16 = bmp180_get_uncomp_temperature();
v_uncomp_press_u32 = bmp180_get_uncomp_pressure();
printf("temp: %.2f C\n", bmp180_get_temperature(v_uncomp_temp_u16) / 10.0);
printf("press: %.2f hPa\n", bmp180_get_pressure(v_uncomp_press_u32) / 100.0);
return 0;
}
s8 BMP180_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
int fd;
s32 iError = BMP180_INIT_VALUE;
u8 stringpos = BMP180_INIT_VALUE;
fd = wiringPiI2CSetup(dev_addr);
for (stringpos = BMP180_INIT_VALUE; stringpos < cnt; stringpos++) {
*(reg_data + stringpos) = wiringPiI2CReadReg8(fd, reg_addr + stringpos);
}
return (s8)iError;
}
s8 BMP180_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
int fd;
s32 iError = BMP180_INIT_VALUE;
u8 stringpos = BMP180_INIT_VALUE;
fd = wiringPiI2CSetup(dev_addr);
for (stringpos = BMP180_INIT_VALUE; stringpos < cnt; stringpos++) {
iError = wiringPiI2CWriteReg8(fd, reg_addr + stringpos, *(reg_data + stringpos));
}
return (s8)iError;
}
void BMP180_delay_msek(u32 msek)
{
usleep(msek * 1000);
}
$ gcc -Wall -lwiringPi bmp180.c bmp180_sample.c -o bmp180_sample
$ sudo ./bmp180_sample
temp: 15.10 C
press: 1004.03 hPa
以上