目的
raspberrypi用GPIOライブラリである、「pigpio」のSPI exampleがいまいちよくわからなかったので、調べた結果を記載する。
対象
pigpio library http://abyz.me.uk/rpi/pigpio/index.html
Examples: MAX6675 SPI Temperature Sensor
codeと詳細
#!/usr/bin/env python
# MAX6675.py
# 2016-05-02
# Public Domain
import time
import pigpio # http://abyz.co.uk/rpi/pigpio/python.html
"""
This script reads the temperature of a type K thermocouple
connected to a MAX6675 SPI chip.
Type K thermocouples are made of chromel (+ve) and alumel (-ve)
and are the commonest general purpose thermocouple with a
sensitivity of approximately 41 uV/C.
The MAX6675 returns a 12-bit reading in the range 0 - 4095 with
the units as 0.25 degrees centigrade. So the reported
temperature range is 0 - 1023.75 C.
Accuracy is about +/- 2 C between 0 - 700 C and +/- 5 C
between 700 - 1000 C.
The MAX6675 returns 16 bits as follows
F E D C B A 9 8 7 6 5 4 3 2 1 0
0 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0 0 0 X
The reading is in B11 (most significant bit) to B0.
The conversion time is 0.22 seconds. If you try to read more
often the sensor will always return the last read value.
"""
pi = pigpio.pi()
if not pi.connected:
exit(0)
# pi.spi_open(0, 1000000, 0) # CE0, 1Mbps, main SPI
# pi.spi_open(1, 1000000, 0) # CE1, 1Mbps, main SPI
# pi.spi_open(0, 1000000, 256) # CE0, 1Mbps, auxiliary SPI
# pi.spi_open(1, 1000000, 256) # CE1, 1Mbps, auxiliary SPI
# pi.spi_open(2, 1000000, 256) # CE2, 1Mbps, auxiliary SPI
# →spiFlagsの8bit目'A'を1にして、acxiliary SPIをONにしている 8bit目1=2^8=256
sensor = pi.spi_open(2, 1000000, 256) # CE2 on auxiliary SPI
# datasheetだとクロック立下りでリードになっているが、SPI mode 0で動作している
# SPI mode 1のほうが良いのでは?
# →auxiliary SPIは SPI mode 0 or 2でしか動作できない = PHA ラッチ先行のみ
stop = time.time() + 600
while time.time() < stop:
c, d = pi.spi_read(sensor, 2) # read 2bytes from senser. c:読み込まれたバイト数(正常時は2)d:読み込まれたバイト
# ここでは2bytesなので、d[0]8bitとd[1]8bitとなる (MSBからd[0]に入る)
"""
センサー出力値
F E D C B A 9 8 7 6 5 4 3 2 1 0
0 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0 0 0 X
d[0]
7 6 5 4 3 2 1 0
0 B11 B10 B9 B8 B7 B6 B5
d[1]
7 6 5 4 3 2 1 0
B4 B3 B2 B1 B0 0 0 X
"""
if c == 2:
word = (d[0]<<8) | d[1] # d[0]とd[1]を結合し、センサー出力値を復元する
"""
d[0]<<8 左に8bitシフトする
F E D C B A 9 8 7 6 5 4 3 2 1 0
0 B11 B10 B9 B8 B7 B6 B5 0 0 0 0 0 0 0 0
d[1]
F E D C B A 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 B4 B3 B2 B1 B0 0 0 X
(d[0]<<8) | d[1] 論理和をとる
F E D C B A 9 8 7 6 5 4 3 2 1 0
0 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0 0 0 X
"""
if (word & 0x8006) == 0: # Bits 15, 2, and 1 should be zero.
# 0x8006=0b1000000000000110 "word"の15, 2, 1bitのすべてが 0なら論理積が 0となる
# bitズレ確認と、2bit目の熱電対断線フラグの確認をしているっぽい
t = (word >> 3)/4.0 # binaryって割り算できたっけ?→リテラルなので、pythonでは数値型として扱われる(ex. 0xff/5 = 51.0)
# なんで4で割る?→MX6675のB0は 0.25℃=2^-2 B1は 0.50℃=2^-1
# 25.75℃は0b1100111と表現されるが、これをそのまま数値型に変換すると103℃となる
# これはリテラルの0bit目は0乗というルールがあるから
# MX6675の0bit目は-2乗であるため、2^-2=1/4を掛けて桁合わせをしなくてはいけない
"""
word >> 3 不要となった0, 1, 2bit目を消し、0bit目から詰める
F E D C B A 9 8 7 6 5 4 3 2 1 0
0 0 0 0 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0
(word >> 3)/4.0 リテラルを温度に変換する
2^13 2^12 2^11 2^10 2^9 2^8 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 2^-1 2^-2
0 0 0 0 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0
"""
print("{:.2f}".format(t)) # tを小数点以下2桁の整数に変換し表示
else:
print("bad reading {:b}".format(word))
time.sleep(0.25) # 読み込み頻度の設定 MX6675の変換時間は最大0.22sのため、これを下回ると同じ値を読み込んでしまう
pi.spi_close(sensor)
pi.stop()
参考
MAX6675 datasheet https://www.maximintegrated.com/jp/products/sensors-and-sensor-interface/MAX6675.html/tb_tab2