RaspberryPI と MAX31865 と Python3 で温度を取得する

はじめに

 Raspberry Pi 3 Model B に MAX31865 RTD to Digital コンバーター(周辺部品を実装済みの基板を使用しました)を SPI 接続して温度を取得する Python プログラムを作ってみました。
 ハードウェアの準備や Python3 環境の整備については省略します。

プログラム

 Python3 から SPI 通信ができるように、spidev パッケージをインストールしておいてください。
 MAX31865 は8ビットのアドレスを指定して、そこに値を書き込むか、読み込むか、という使い方をします。書き込みはアドレスのあとに8ビットを続けて送信します。読み込みは読み込むアドレス8ビットを指定したあと、必要な分だけクロックを回してあげます。ADC変換結果(RTDの抵抗値)を読み取るには、0x01 と 0x02 の2つのレジスタから値を取得する必要があります。読み取る先頭のアドレス 0x01 を指定して、読み取りのために2バイト分のクロックを追加で送信するためにダミーの2バイトを続けます。つまり、合計3バイト分を RaspberryPI の MOSI 端子から送信することになります。MAX31865 からの読み取りは指定したアドレスからクロックが続く限り順次送る仕様ですので、指定した 0x01 のデータを RaspberryPI に送ったあとは、続けて 0x02 のデータを送信してくれます。
 受信信号については RaspberryPI の MISO 端子から1バイト目を含めて受け取っています。しかし、1バイト目は RaspberryPI からアドレス指定のため送信中ですので、ダミーのデータとなります。つまり、有効なデータは2バイト目以降ということになります。ADC変換結果から温度を求めるため、仕様書にある近似式を使用しました。仕様書では RREF に 400Ω を設定していますが、今回使用した基板は 430Ω が実装されています。ADC変換結果は RTD の抵抗値 RRTD と基準抵抗の抵抗値 RREF の比として保持されます。このため、RREF が 400Ω のときの ADC の値を求める式を挿入しました。
 MAX31865 はクロック信号を最大 5MHz の転送速度で受信できます。今回、余裕を見て 1MHz としました。SPI モードは 1 と 3 をサポートしています。今回、1 を指定しました。

temperature_with_max31865.py
from datetime import datetime
import spidev
from time import sleep

def printbits(data, padding=8):
    template = '{{:0{}b}}'.format(padding)
    for d in data:
        print(template.format(d))

def spisetup():
    spi = spidev.SpiDev()
    spi.open(0, 0)
    spi.max_speed_hz = 1000000
    spi.bits_per_word = 8
    spi.mode = 1
    spi.xfer([0x80, 0b00010010])             # write configuration
    #printbits(spi.xfer([0x00, 0x00])[1:])   # read configuration
    return spi

def spiread(spi, r_ref=430):
    spi.xfer([0x80, 0b10010010])             # v-bias on
    sleep(0.1)                               # wait for RTDIN-capacitor full
    spi.xfer([0x80, 0b10110010])             # start 1-shot reading
    sleep(0.1)                               # wait for saving to register
    bits = spi.xfer([0x01, 0x00, 0x00])[1:]  # read bits
    spi.xfer([0x80, 0b00010010])             # v-bias off
    adc = bits[0] << 7 | bits[1] >> 1        # make 15 bits
    #printbits(bits)
    #printbits([adc], padding=15)
    #r_rtd = (adc * r_ref) / 2 ** 15
    #print('r_rtd:{}ohm'.format(r_rtd))
    adc = adc * r_ref / 400                  # convert adc on r_ref == 400
    temperature = adc / 32 - 256             # convert adc to temperature
    return temperature

def spiquit(spi):
    spi.close()


if __name__ == '__main__':
    try:
        spi = spisetup()
        while True:
            tempareture = spiread(spi)
            print('{:%Y-%m-%d %H:%M:%S} temp {:5.2f}'.format(
                datetime.now(), tempareture))
            sleep(5)
    except KeyboardInterrupt:
        spiquit(spi)
        exit(0)

実行結果

 無事温度を表示できるようになりました。検証のためアルコール温度計が手元にあると便利です。

$ python temperature_with_max31865.py
2018-02-24 15:24:23 temp 17.87
2018-02-24 15:24:28 temp 17.87
2018-02-24 15:24:33 temp 17.84
2018-02-24 15:24:38 temp 17.87

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください