はじめに
前回は気温・気圧センサー(BMP280)を用いて気温と気圧を測定した。その際、通信手段としてI2Cを用いた。今回は、SPI通信を用いて計測値を取得する。
BMP280のピン
BMP280はI2CとSPIの両方に対応している。ピン配置を以下に示す。ELECTROCREDIBLE(https://electrocredible.com/bmp280-pinout-specifications-applications/)

回路図
BMP280とPicoの接続図を以下に示します。I2Cに比べると線が2本増えますので、複雑に見えます。


プログラム
プログラムは以下のようになります(ChatGPT5を使用)。
from machine import Pin, SPI
import struct, time
# --- Pin設定(ご提示の通り) ---
MOSI_PIN = 15
MISO_PIN = 12
CLK_PIN = 14
CS_PIN = 13
SPI_CH = 1
spi = SPI(SPI_CH, sck=Pin(CLK_PIN), mosi=Pin(MOSI_PIN), miso=Pin(MISO_PIN), baudrate=1000000, polarity=0, phase=0)
cs = Pin(CS_PIN, Pin.OUT, value=1)
def _write_reg(addr, val):
cs.value(0)
spi.write(bytearray([addr & 0x7F, val & 0xFF]))
cs.value(1)
def _read_regs(addr, n):
cs.value(0)
spi.write(bytearray([addr | 0x80])) # read
data = spi.read(n) # read n dummy-clocked bytes
cs.value(1)
return data
# --- 確認: チップID ---
chip_id = _read_regs(0xD0, 1)[0]
if chip_id != 0x58: # BMP280=0x58, BME280=0x60
raise RuntimeError("BMP280 not found (chip_id=0x%02X)" % chip_id)
# --- リセット(任意) ---
_write_reg(0xE0, 0xB6)
time.sleep(0.005)
# --- 設定 ---
# config(0xF5): standby=1000ms(0b101<<5), filter=16x(0b100<<2) など好みで
_write_reg(0xF5, (5<<5) | (4<<2))
# ctrl_meas(0xF4): 温度x1(001<<5), 圧力x4(011<<2), 正常モード(11)
_write_reg(0xF4, (1<<5) | (3<<2) | 3)
# --- 補正係数の読込 ---
cal = _read_regs(0x88, 24)
dig_T1, dig_T2, dig_T3, \
dig_P1, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9 = struct.unpack('<HhhHhhhhhhhh', cal)
t_fine = 0
def _compensate_T(adc_T):
global t_fine
var1 = (((adc_T >> 3) - (dig_T1 << 1)) * dig_T2) >> 11
var2 = (((((adc_T >> 4) - dig_T1) * ((adc_T >> 4) - dig_T1)) >> 12) * dig_T3) >> 14
t_fine = var1 + var2
T = (t_fine * 5 + 128) >> 8 # 0.01 degC
return T / 100.0
def _compensate_P(adc_P):
global t_fine
var1 = t_fine - 128000
var2 = var1 * var1 * dig_P6
var2 = var2 + ((var1 * dig_P5) << 17)
var2 = var2 + (dig_P4 << 35)
var1 = ((var1 * var1 * dig_P3) >> 8) + ((var1 * dig_P2) << 12)
var1 = (((1 << 47) + var1) * dig_P1) >> 33
if var1 == 0:
return 0 # 過剰防御
p = 1048576 - adc_P
p = (((p << 31) - var2) * 3125) // var1
var1 = (dig_P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (dig_P8 * p) >> 19
p = ((p + var1 + var2) >> 8) + (dig_P7 << 4)
return p / 256.0 # Pa
time.sleep(0.02) # 設定反映待ち
while True:
# 一括読み出し:圧力(0xF7..0xF9), 温度(0xFA..0xFC)
data = _read_regs(0xF7, 6)
# 20-bit (MSB:LSB:XLSB[7:4])
adc_p = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
adc_t = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
temp_c = _compensate_T(adc_t)
pres_pa = _compensate_P(adc_p)
pres_hpa = pres_pa / 100.0
print("Temp: {:.2f} °C Pressure: {:.2f} hPa".format(temp_c, pres_hpa))
time.sleep(1)
動作例
上のプログラムを実行した結果は以下のようになります。

おわりに
I2C通信に続き、SPI通信でも温度データ、気圧データを取得することができた。プログラムではレジスタへのアクセスが必要であるため難しい(センサーによって異なる)。その部分は生成AIを用いたところ、訂正を加えることのいらない完成プログラムが一回のプロンプトで作成された。プログラムの基本形は書籍を使って作成したが、レジスタ周りのプログラムを生成AIに助けてもらった。


コメント