はじめに
秋月電子通商で購入したBME280使用 温湿度・気圧センサーモジュールキットをPicoMite(MMBasic)で使えるようにChatGPTに問い合わせて生成させたコードを修正して動作するコードを作成しました。その内容などを以下に示します。
使用部品
使用した部品は秋月電子通商のBME280使用 温湿度・気圧センサーモジュールキットAE-BME280です。
BME280はI2CまたはSPIで接続できます。今回はI2CでRaspberry Pi PicoおよびPicoCalcと接続しました。
配線
BME280をRaspberry Pi PicoとPicoCalcの両方で使用できるようにRaspberry Pi Picoとの接続を次のように決めた。PicoCalcで外部から接続できるI/OピンはGP2〜GP5とGP21とGP28の6ピンだけです。
BME280のピン | Picoのピン(物理ピン) |
---|---|
VDD | 3V3 |
GND | GND(3) |
CSB | 未接続 |
SDI | GP4(6) |
SDO | GND |
SCK | GP5(7) |
Raspberry Pi Picoでの実体配線図を以下に示します。
プログラム
PicoMiteはBME280をサポートしていないため、自分で用意する必要があります。今回もChatGPTのo4-mini-high
にコードを生成させました。それらしいコードを生成してくれましたがそのままでは動作しないものだったので手作業などで動作するように修正しました。
BME280を使った温度、湿度、気圧測定は次の手順で実行しています。
- キャリブレーション(補正係数読み出し)
- 測定モード設定
- センサーから温度、湿度、気圧の生データ読み出し(全8バイト)
- 生データから温度計算
- 生データから気圧計算
- 生データから湿度計算
- 計算結果をOLEDディスプレイに表示
キャリブレーション(補正係数読み出し)
補正係数は16ビットおよび8ビットで符号なし、符号付きのデータです。それぞれのデータ形式に合わせてデータを組み上げている。
補正係数のデータは下表に示すレジスタから読み取り、データ形式に応じたデータを変数に保存している。
項目 | レジスタ範囲 | キャリブレーション定数 |
---|---|---|
温度 | &H88〜&H8D | dig_T1〜dig_T3 |
気圧 | &H8E〜&H9F | dig_P1〜dig_P9 |
湿度 | &HA1、&HE1〜&HE7 | dig_H1〜dig_H6 |
-
I2C Write
コマンドで読み取るレジスタを指定 -
I2C Rread
コマンドで2バイト、または1バイトのデータを読み取る - 係数ごとのデータ形式に応じて係数値を算出
コード量が多いので下記の全コードの51〜125行を参照
測定モード設定
センサ内部のADCの1測定サイクル中に温度、湿度、気圧測定を何回測定するか(オーバーサンプリング)とデバイスの動作速度、フィルタ、インターフェイスの設定をしている。
ここでは温度、湿度、気圧測定は測定サイクル中に1回測定、ノーマルモード動作、フィルタとSPIは使用しない設定にしています。
レジスタ | 名称 | 設定項目 |
---|---|---|
&HF2 | ctrl_hum | 湿度データのオーバーサンプリング |
&HF4 | ctrl_meas | 温度、気圧のオーバサンプリング、センサーモード |
&HF5 | config | ノーマルモードスタンバイ時間、フィルタ、SPI使用 |
127 '---- オーバサンプリング、測定モード設定
128 Sub Setup
129 I2C Write BME280_ADDR, 0, 2, &HF2, &H01 ' ctrl_hum: x1
130 I2C Write BME280_ADDR, 0, 2, &HF4, &H27 ' ctrl_meas: temp x1, press x1, mode normal(3)
131 I2C Write BME280_ADDR, 0, 2, &HF5, &H20 ' config:
132 End Sub
センサーから温度、湿度、気圧の生データ読み出し
キャリブレーション、測定モードの設定が終わればセンサーから温度、湿度、気圧の生データを読み出せます。
センサーからの生データは8つのレジスタ(0xF7〜0xFE)に格納されているので先頭のレジスタを指定してバルク読み出しし、バッファの配列data%()に格納しています。
30 ' 生データのバルク読み出し (レジスタ0xF7~0xFE: 8バイト)
31 I2C Write BME280_ADDR, 0, 1, &HF7
32 I2C READ BME280_ADDR, 0, 8, data%()
バッファの8バイトのデータは気圧で3バイト(press_msb、press_lsb、press_xlsb)、温度で3バイト(temp_msb、temp_lsb、temp_xlsb)、湿度で2バイト(hum_msb、hum_lsb)の順で格納されており、次の表に示す順でデータが並んでいます。
レジスタ | アドレス | データ | ファッバ |
---|---|---|---|
press_msb | 0xF7 | press_msb<7:0> | data%(0) |
press_lsb | 0xF8 | press_lsb<7:0> | data%(1) |
press_xlsb | 0xF9 | press_xlsb<7:4>0000 | data%(2) |
temp_msb | 0xFA | temp_msb<7:0> | data%(3) |
temp_lsb | 0xFB | temp_lsb<7:0> | data%(4) |
temo_xlsb | 0xFC | temp_xlsb<7:4>0000 | data%(5) |
hum_msb | 0xFD | press_msb<7:0> | data%(6) |
hum_lsb | 0xFE | press_lxb<7:0> | data%(7) |
生データから温度計算
温度の生データは上の表に示したとおり、data%(3)からdata%(5)に上位ビットから順に格納されていてdata%(5)の下位4ビットを除いた20ビット分です。
プログラムの137行目のようにtemp_msbのdata%(3)の8ビットを左へ12ビットシフトして19〜12ビットに、temp_lsbのdata%(4)の8ビットを左へ4ビットして11〜4ビットに、temp_xlsbのdata%(5)を右へ4ビットシフトして3〜0にし、それらの値の論理和を求めると20ビットの生データになります。生データと補正データ使って温度データを計算します。
133 '---- 温度計算
134 Function get_temperature()
135 Local var1, var2, raw_t%
136 ' 生データ
137 raw_t% = data%(3) << 12 Or data%(4) << 4 Or data%(5) >> 4
138 ' 補正データから温度計算
139 var1 = (raw_t% / 16384.0 - dig_T1 / 1024.0) * dig_T2
140 var2 = ((raw_t% / 131072.0 - dig_T1 / 8192.0) ^ 2) * dig_T3
141 t_fine = var1 + var2
142 get_temperature = t_fine / 5120.0
143 End Function
生データから気圧計算
気圧の生データはdata%(0)からdata%(3)に温度データと同様に20ビット分のデータが格納されていて温度データとと同様に20ビットのデータへ変換し、補正データから気圧の値を計算している。
144 '---- 気圧計算
145 Function get_pressure()
146 Local var1, var2, p, raw_p%
147 ' 生データ
148 raw_p% = (data%(0) << 12 Or data%(1) << 4 Or data%(2)) >> 4
149 ' 補正データから気圧計算
150 var1 = t_fine / 2.0 - 64000.0
151 var2 = var1 * var1 * dig_P6 / 32768.0
152 var2 = var2 + var1 * dig_P5 * 2.0
153 var2 = var2 / 4.0 + dig_P4 * 65536.0
154 var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0
155 var1 = (1.0 + var1 / 32768.0) * dig_P1
156 If var1 = 0 Then
157 p = 0
158 Else
159 p = 1048576.0 - raw_p%
160 p = (p - var2 / 4096.0) * 6250.0 / var1
161 var1 = dig_P9 * p * p / 2147483648.0
162 var2 = p * dig_P8 / 32768.0
163 p = p + (var1 + var2 + dig_P7) / 16.0
164 EndIf
165 get_pressure = p
166 End Function
生データから湿度を計算
湿度の生データはdata%(6)とdata%(7)の16ビット分なのでdata%(6)を左へ8ビットシフトしdata%(7)との論理和で得られる。補正データから湿度を計算する。得られる値はPa単位になる。
168 ' --- 湿度計算
169 Function get_humidity()
170 Local hum, raw_h%
171 ' 生データ
172 raw_h% = data%(6) << 8 Or data%(7)
173 ' 補正データから湿度計算
174 hum = t_fine - 76800.0
175 hum = (raw_h% - (dig_H4 * 64.0 + dig_H5 / 16384.0 * hum)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * hum * (1.0 + dig_H3 / 67108864.0 * hum)))
176 hum = hum * (1.0 - dig_H1 * hum / 524288.0)
177 If hum > 100 Then hum = 100
178 If hum < 0 Then hum = 0
179 get_humidity = hum
180 End Function
温度、気圧、湿度の表示
温度、気圧、湿度のそれぞれの値を得られたので桁数を揃えてコンソールとOLEDディスプレイに出力します。
32 temp = get_temperature() ' 温度データ取得
33 pres = get_pressure() / 100 ' 気圧データ取得 hPa単位
34 humi = get_humidity() ' 湿度データ取得
35 '--- 結果表示 ---
36 Print Time$
37 Print "Temperature: "; Str$(temp, 4, 1); "C"
38 Print "Pressure : "; Str$(pres, 4, 1); " hPa"
39 Print "Humidity : "; Str$(humi, 4, 1); " %"
40 Print
41 Text 0, 0, Time$
42 Text 0, 12, Str$(temp, 4, 1) + Chr$(&H60) + "C",,4
43 Text 0, 28, Str$(pres, 4, 1) + "hPa",,4
44 Text 0, 44, Str$(humi, 4, 1) + "%",,4
プログラム全体
1 '----------------------------------------------------------
2 ' BME280 測定プログラム (MMBasic on Raspberry Pi Pico)
3 ' I2C bus#0, SDA=GP4, SCL=GP5 (100kHz)
4 ' I2Cアドレス 0x76
5 '----------------------------------------------------------
6 Option Explicit
7 Dim t_fine = 0.0
8 Dim data%(7) ' 生データ保管
9 Dim pres ' 気圧
10 Dim temp ' 温度
11 Dim humi ' 湿度
12 ' 補正値データ
13 Dim dig_T1, dig_T2, dig_T3
14 Dim dig_P1, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9
15 Dim dig_H1, dig_H2, dig_H3, dig_H4, dig_H5, dig_H6
16
17 Const BME280_ADDR = &H76
18 SetPin GP4, GP5, I2C
19 I2C OPEN 100, 100
20 ' SoftRest
21 I2C Write BME280_ADDR, 0, 1, &HE0
22 I2C Write BME280_ADDR, 0, 1, &HB6
23
24 calibration
25 Setup
26 '--- 無限ループで測定
27 Do
28 ' 生データのバルク読み取り
29 I2C Write BME280_ADDR, 0, 1, &HF7
30 I2C READ BME280_ADDR, 0, 8, data%()
31
32 temp = get_temperature() ' 温度データ取得
33 pres = get_pressure() / 100 ' 気圧データ取得
34 humi = get_humidity() ' 湿度データ取得
35 '--- 結果表示 ---
36 Print Time$
37 Print "Temperature: "; temp; "C"
38 Print "Pressure : "; pres; " hPa"
39 Print "Humidity : "; humi; " %"
40 Print
41 Text 0, 0, Time$
42 Text 0, 12, Str$(temp, 4, 1) + Chr$(&H60) + "C",,4
43 Text 0, 28, Str$(pres, 4, 1) + "hPa",,4
44 Text 0, 44, Str$(humi, 4, 1) + "%",,4
45 Pause 10000 ' 1秒待機
46 Loop
47
48 I2C CLOSE
49 End
50 '---- calibrationデータの読み取り
51 Sub calibration
52 Dim t%(1), l, h, th
53 ' 温度補正データ
54 I2C Write BME280_ADDR, 0, 1, &H88
55 I2C READ BME280_ADDR, 0, 2, t%()
56 dig_T1 = t%(0) + t%(1) * 256
57
58 I2C Write BME280_ADDR, 0, 1, &H8A
59 I2C READ BME280_ADDR, 0, 2, t%()
60 dig_T2 = t%(0) + t%(1) * 256
61 If dig_T2 > 32767 Then dig_T2 = dig_T2 - 65536
62
63 I2C Write BME280_ADDR, 0, 1, &H8C
64 I2C READ BME280_ADDR, 0, 2, t%()
65 dig_T3 = t%(0) + t%(1) * 256
66 If dig_T3 > 32767 Then dig_T3 = dig_T3-65536
67
68 ' 気圧補正データ
69 I2C Write BME280_ADDR, 0, 1, &H8E
70 I2C READ BME280_ADDR, 0, 2, t%()
71 dig_P1 = t%(0) + t%(1) * 256
72 I2C Write BME280_ADDR, 0, 1, &H90
73 I2C READ BME280_ADDR, 0, 2, t%()
74 dig_P2 = t%(0) + t%(1) * 256
75 If dig_P2 > 32767 Then dig_P2 = dig_P2-65536
76 I2C Write BME280_ADDR, 0, 1, &H92
77 I2C READ BME280_ADDR, 0, 2, t%()
78 dig_P3 = t%(0) + t%(1) * 256
79 If dig_P3 > 32767 Then dig_P3 = dig_P3-65536
80 I2C Write BME280_ADDR, 0, 1, &H94
81 I2C READ BME280_ADDR, 0, 2, t%()
82 dig_P4 = t%(0) + t%(1) * 256
83 If dig_P4 > 32767 Then dig_P4 = dig_P4-65536
84 I2C Write BME280_ADDR, 0, 1, &H96
85 I2C READ BME280_ADDR, 0, 2, t%()
86 dig_P5 = t%(0) + t%(1) * 256
87 If dig_P5 > 32767 Then dig_P5 = dig_P5-65536
88 I2C Write BME280_ADDR, 0, 1, &H98
89 I2C READ BME280_ADDR, 0, 2, t%()
90 dig_P6 = t%(0) + t%(1) * 256
91 If dig_P6 > 32767 Then dig_P6 = dig_P6-65536
92 I2C Write BME280_ADDR, 0, 1, &H9A
93 I2C READ BME280_ADDR, 0, 2, t%()
94 dig_P7 = t%(0) + t%(1) * 256
95 If dig_P7 > 32767 Then dig_P7 = dig_P7-65536
96 I2C Write BME280_ADDR, 0, 1, &H9C
97 I2C READ BME280_ADDR, 0, 2, t%()
98 dig_P8 = t%(0) + t%(1) * 256
99 If dig_P8 > 32767 Then dig_P8 = dig_P8-65536
100 I2C Write BME280_ADDR, 0, 1, &H9E
101 I2C READ BME280_ADDR, 0, 2, t%()
102 dig_P9 = t%(0) + t%(1) * 256
103 If dig_P9 > 32767 Then dig_P9 = dig_P9-65536
104
105 ' 湿度補正データ
106 I2C Write BME280_ADDR, 0, 1, &HA1
107 I2C READ BME280_ADDR, 0, 1, dig_H1
108 I2C Write BME280_ADDR, 0, 1, &HE1
109 I2C READ BME280_ADDR, 0, 2, t%()
110 dig_H2 = t%(0) + t%(1) * 256
111 If dig_H2 > 32767 Then dig_H2 = dig_H2-65536
112 I2C Write BME280_ADDR, 0, 1, &HE3
113 I2C READ BME280_ADDR, 0, 1, dig_H3
114 I2C Write BME280_ADDR, 0, 1, &HE4
115 I2C READ BME280_ADDR, 0, 1, l
116 I2C Write BME280_ADDR, 0, 1, &HE5
117 I2C READ BME280_ADDR, 0, 1, h
118 I2C Write BME280_ADDR, 0, 1, &HE6
119 I2C READ BME280_ADDR, 0, 1, th
120 dig_H4 = l * 16 + (h And &HF)
121 dig_H5 = th * 16 + Int(h / 16)
122 I2C Write BME280_ADDR, 0, 1, &HE7
123 I2C READ BME280_ADDR, 0, 1, dig_H6
124 If dig_H6 > 127 Then dig_H6 = dig_H6-256
125 End Sub
126
127 '---- オーバサンプリング、測定モード設定
128 Sub Setup
129 I2C Write BME280_ADDR, 0, 2, &HF2, &H01 ' ctrl_hum: x1
130 I2C Write BME280_ADDR, 0, 2, &HF4, &H27 ' ctrl_meas: temp x1, press x1, mode normal(3)
131 I2C Write BME280_ADDR, 0, 2, &HF5, &H20 ' config:
132 End Sub
133 '---- 温度計算
134 Function get_temperature()
135 Local var1, var2, raw_t%
136 ' 生データ
137 raw_t% = data%(3) << 12 Or data%(4) << 4 Or data%(5) >> 4
138 ' 補正データから温度計算
139 var1 = (raw_t% / 16384.0 - dig_T1 / 1024.0) * dig_T2
140 var2 = ((raw_t% / 131072.0 - dig_T1 / 8192.0) ^ 2) * dig_T3
141 t_fine = var1 + var2
142 get_temperature = t_fine / 5120.0
143 End Function
144 '---- 気圧計算
145 Function get_pressure()
146 Local var1, var2, p, raw_p%
147 ' 生データ
148 raw_p% = data%(0) << 12 Or data%(1) << 4 Or data%(2) >> 4
149 ' 補正データから気圧計算
150 var1 = t_fine / 2.0 - 64000.0
151 var2 = var1 * var1 * dig_P6 / 32768.0
152 var2 = var2 + var1 * dig_P5 * 2.0
153 var2 = var2 / 4.0 + dig_P4 * 65536.0
154 var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0
155 var1 = (1.0 + var1 / 32768.0) * dig_P1
156 If var1 = 0 Then
157 p = 0
158 Else
159 p = 1048576.0 - raw_p%
160 p = (p - var2 / 4096.0) * 6250.0 / var1
161 var1 = dig_P9 * p * p / 2147483648.0
162 var2 = p * dig_P8 / 32768.0
163 p = p + (var1 + var2 + dig_P7) / 16.0
164 EndIf
165 get_pressure = p
166 End Function
167
168 ' --- 湿度計算
169 Function get_humidity()
170 Local hum, raw_h%
171 ' 生データ
172 raw_h% = data%(6) << 8 Or data%(7)
173 ' 補正データから湿度計算
174 hum = t_fine - 76800.0
175 hum = (raw_h% - (dig_H4 * 64.0 + dig_H5 / 16384.0 * hum)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * hum * (1.0 + dig_H3 / 67108864.0 * hum)))
176 hum = hum * (1.0 - dig_H1 * hum / 524288.0)
177 If hum > 100 Then hum = 100
178 If hum < 0 Then hum = 0
179 get_humidity = hum
180 End Function
実行結果
Raspberry Pi PicoとPicoCalcでの実行結果は次の通り。PicoCalcではコンソール出力は削除している。