ラズパイPicoW(Raspberry Pi Pico W)に温度センサ(ADT7310)と液晶ディスプレイ(LCD)を接続し、SPI通信を使ってLCDに温度センサで測定した気温を表示させます。
実験準備
実験に必要な環境や部品を準備します。
機器とプログラム
「I2C通信で液晶ディスプレイ(LCD)に文字表示。」の回路に温度センサ(ADT7310)を追加し、プログラムを改造して実験します。
使う部品
温度センサ(ADT7310)及び液晶ディスプレイ(LCD)、I2CシリアルI/Fモジュールなど実験に使う部品を準備します。(「I2C通信で液晶ディスプレイ(LCD)に文字表示。」と一部、重複しています。)
| 部 品 名 | 規 格 | 数 量 | 取扱い店(参考) | 
| ADT7310 温度センサモジュール (ピンヘッダ 要半田付け) | AE-ADT7310 | 1 | 秋月電子通商 | 
| 液晶ディスプレイ(LCD) | LCD 1602A | 1 | Amazon (セット) | 
| I2CシリアルI/Fモジュール | LCM1602 | ||
| ブレッドボード | BB-102 | 1 | 秋月電子通商 | 
| ジャンパーワイヤ | オス-メス (約20cm) | 1 | 電子工作ステーション | 
| ジャンパーワイヤ | オス-オス (約20cm) | 1 | 電子工作ステーション | 
AE-ADT7310の概要は秋月電子通商さん提供のマニュアルを参考にしてください。
配線
準備した機器と部品をつなぎ、MicroPythonでプログラミングを行って、温度センサで測定した気温を、液晶ディスプレイ(LCD)に表示させます。
配線リスト
温度センサ(ADT7310)は、SPI通信のチャンネルにジャンパーワイヤで接続し、液晶ディスプレイ(LCD)は、I2C通信のチャンネルにジャンパーワイヤで接続します。
液晶ディスプレイ(LCD)は5Vで動作しますので、VBUS (5V)に接続し、温度センサ(ADT7310)も、仕様上、5Vで動作しますが、動作が不安定となるため、3.3Vの3V3に接続します。
▶️温度センサ(ADT7310)の配線
| ラズパイPicoW | 温度センサ(ADT7310) | 備 考 | 
| GP16 | SDO | |
| GP17 | CS(上部に-が付いています。) | |
| GP18 | SCL | |
| GP19 | SDI | |
| 3V3 (3.3V) | VDD | |
| GND | GND | 
▶️液晶ディスプレイ(LCD)の配線
| ラズパイPicoW | 液晶ディスプレイ(LCD) | 備 考 | 
| GP0 | SDA | |
| GP1 | SCL | |
| VBUS (5V) | VCC | |
| GND | GND | 
配線図

液晶ディスプレイ(LCD)とI2CシリアルI/Fモジュールは、ブレッドボード内部の配線で接続します。
気温測定プログラム
温度センサ(ADT7310)は、測定した温度を、内臓のA/Dコンバータで、13ビットまたは16ビットのディジタルデータに変換し、SPI通信を使ってラズパイPicoWなどのコンピュータに提供します。
ラズパイPicoWは読み込んだディジタルデータを処理し、温度を摂氏として液晶ディスプレイ(LCD)に表示します。
Raspi4BのThonnyを起動し、次のコードを「エディタ」に入力するか、リストをコピーしてペーストします。
#モジュールの読み込み(インポート)
from machine import Pin, I2C, SPI
from pico_i2c_lcd import I2cLcd
from time import sleep
#I2Cパラメータ設定
I2C_SDA = Pin(0)
I2C_SCL = Pin(1)
#I2Cを利用するため、オブジェクト(i2c_obj)を作成
i2c_obj = I2C(0,sda=I2C_SDA, scl=I2C_SCL, freq=400000)
#SPIのパラメータを設定
SPI_MISO = Pin(16)
SPI_SCK  = Pin(18)
SPI_MOSI = Pin(19)
#SPIのチップセレクト(スレーブセレクト)用の出力ピンを設定
spi_cs = Pin(17, mode=Pin.OUT)
#SPIのチップセレクトをOFFに設定
spi_cs.value(1)
#SPI通信でADT7310を利用するため、オブジェクト(spi_obj)を作成
spi_obj = SPI(0, baudrate=125000, polarity=1, phase=1, bits=8, \
              firstbit=SPI.MSB, mosi=SPI_MOSI, miso=SPI_MISO, sck=SPI_SCK)
#液晶ディスプレイ(LCD)のパラメータを設定
LCD_ADR = 0x27
LCD_ROW = 2
LCD_COL = 16
#LCDを利用するため、オブジェクト(i2c_lcd)を作成
i2c_lcd = I2cLcd(i2c_obj, LCD_ADR, LCD_ROW, LCD_COL)
#メイン処理
#例外処理(「Ctrl + c」キーにより中断)を設定
try:
  
        
    while True:
    
        #********** ADT7310 温度測定 **********
        
        
        #シリアル・インターフェース リセット
        spi_cs.value(1)
        buff=bytearray([0xff,0xff,0xff,0xff])
        spi_cs.value(0)
        spi_obj.write(buff)
        spi_cs.value(1)
        sleep(0.1)
        
        
        #コンフィギュレーション・レジスタのアドレスと
        #内容(一回のみの測定/変換、分解能を16ビット)を設定
        buff=bytearray([0x08,0xa0])
        
        
        #SPIのチップセレクトをONに設定
        spi_cs.value(0)
        
        #コマンド・バイトとコンフィギュレーション・レジスタに設定値を書き込む
        spi_obj.write(buff)
        
        
        #SPIのチップセレクトをOFFに設定
        spi_cs.value(1)
    
        while True:
                
            # ステータスレジスタの読み込み
            sleep(0.01)
            buff=bytearray([0x40])
            spi_cs.value(0)
            spi_obj.write(buff)
            status_reg = bytearray(spi_obj.read(1,0x00))
            spi_cs.value(1)
            if ((status_reg[0] >> 7) & 1) == 0:
                break       
        
        
        #温度値レジスタのアドレスを設定
        buff=bytearray([0x50])
         
         
        #SPIのチップセレクトをONに設定
        spi_cs.value(0)
        
        
        #コマンド・バイトに設定値を書き込む
        spi_obj.write(buff)        
   
    
        #温度データ(2バイト)を読込
        raw = bytearray(spi_obj.read(2,0x02))
        
        
        #SPIのチップセレクトをOFFに設定
        spi_cs.value(1)
        
        
        
        #温度データの上位バイト
        msb = raw[0]       
        #温度データの下位バイト
        lsb = raw[1]
        
        
        #バイト連結
        temp = (msb << 8) | lsb
    
    
        #32768以上は65536を引いて負の値に変換
        if(temp >= 32768):
            temp = temp - 65536
    
    
        #温度に変換    
        temp = temp/128
      
        #********** 液晶ディスプレイ(LCD)に温度を表示 ********** 
        #表示位置を初期化
        i2c_lcd.move_to(0, 0)
    
    
        #LCDに小数点第一位までの温度を表示
        i2c_lcd.putstr("SPI-TEMP:{:.1f}".format(temp))
    
    
        #℃表示
        ch=[
        #°
        bytearray([0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00]),
        #C
        bytearray([0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E, 0x00])
        ]
    
        for i in range(len(ch)):
            i2c_lcd.custom_char(i, ch[i])
            i2c_lcd.putchar(chr(i))   
         
    
        #1秒待つ
        sleep(1)
      
#「Ctrl + c」キーにより中断。
except KeyboardInterrupt:
    # Turn off the display
    print("「Ctrl + c」キーが押されました。")
    
    #LCD消灯
    i2c_lcd.backlight_off()
    i2c_lcd.display_off()
Thonnyの「F5」キーを押して、文字表示プログラムを実行します。
気温測定プログラムは、温度センサ(ADT7310)の測定した温度を、小数点第一位までの数値として、液晶ディスプレイ(LCD)に表示します。
確認後、Thonnyの「Ctrl + c」キーを押すと、液晶ディスプレイ(LCD)が消灯し、処理が中断しますので、中断後、「Ctrl + F2」キーを押して、プログラムを終了させます。
任意のファイル名でラズパイPicoWに保存します。(ここでは「3_8spitmprtr.py」で保存しました。)
プログラムの仕組み
温度センサ(ADT7310)や液晶ディスプレイ(LCD)と、どのようにやり取りをするのか、プログラムの動きを簡単に見ていきます。
▶️I2C、SPIモジュール等の読み込み
液晶ディスプレイ(LCD)とI2C通信するモジュールと、温度センサ(ADT7310)とSPI通信するためのモジュール等を読み込みます。
液晶ディスプレイ(LCD)と通信をするために、GitHubユーザー(T-622)が開発したライブラリ、「 lcd_api.py」と「 pico_i2c_lcd.py」の2種類のモジュールを組み合わせて使います。
ライブラリが保存されていない場合は、こちらの手順で保存してください。
#モジュールの読み込み(インポート)
from machine import Pin, I2C, SPI
from pico_i2c_lcd import I2cLcd
from time import sleep▶️I2Cを利用するためのオブジェクトを作成
液晶ディスプレイ(LCD)とI2C接続するGP0とGP1の変数を設定後、I2C接続するオブジェクトを作成します。
#I2Cパラメータ設定
I2C_SDA = Pin(0)
I2C_SCL = Pin(1)
#I2Cを利用するため、オブジェクト(i2c_obj)を作成
i2c_obj = I2C(0,sda=I2C_SDA, scl=I2C_SCL, freq=400000)
【i2c_objのパラメータ】
| 項 目 | 説 明 | 
| 0 | I2Cのチャンネル番号(ラズパイPicoWの場合は0または1) | 
| sda=I2C_SDA | SDA(シリアルデータ)として使うGPピン番号 | 
| scl=I2C_SCL | SCL(シリアルクロック)として使うGPピン番号 | 
| freq=400000 | 通信速度(400000bps=400kbps) | 
▶️SPI通信で温度センサ(ADT7310)を利用
温度センサ(ADT7310)とSPI接続するGP16~GP19の変数を設定します、
GP17は温度センサ(ADT7310)の選択を制御する出力ピンとして設定し、初期設定は出力をOFF(1)にして非選択状態にします。
SPI接続するオブジェクト(spi_obj)を作成します。
#SPIのパラメータを設定
SPI_MISO = Pin(16)
SPI_SCK  = Pin(18)
SPI_MOSI = Pin(19)
#SPIのチップセレクト(スレーブセレクト)用の出力ピンを設定
spi_cs = Pin(17, mode=Pin.OUT)
#SPIのチップセレクトをOFFに設定
spi_cs.value(1)
#SPI通信でADT7310を利用するため、オブジェクト(spi_obj)を作成
spi_obj = SPI(0, baudrate=125000, polarity=1, phase=1, bits=8, \
              firstbit=SPI.MSB, mosi=SPI_MOSI, miso=SPI_MISO, sck=SPI_SCK)
【spi_objのパラメータ】
| 項 目 | 説 明 | 
| 0 | SPIのチャンネル番号(ラズパイPicoWの場合は0または1) | 
| baudrate=125000 | 通信速度(125000bps=125kbps) | 
| polarity=1 | クロック(SCLK)の極性を表わすパラメータ(0または1)で、1の場合、通信を行っていない間はSCLK信号はHに固定し、通信時には、Lのクロックパルスを生成します。 | 
| phase=1 | クロックパルスがデータをサンプルするタイミング(0または1)で、1の場合、クロックパルスの最後の部分で、MOSIやMISOの信号がサンプリングされます。 | 
| bits=8 | 転送のビットは8ビット固定です。 | 
| firstbit=SPI.MSB | データの転送の時、マスタから送出される最初のビット(MSBまたはLSB)を設定します。 | 
| mosi=SPI_MOSI | マスタからスレーブにデータを転送する、信号線のGPピンを指定します。 | 
| miso=SPI_MISO | スレーブからマスタにデータを転送する、信号線のGPピンを指定します。 | 
| sck=SPI_SCK | シリアルクロック。MISOやMOSIのデータは、動作モードによりSCKの立ち上がりまたは立ち下がりに同期して転送されます。 | 
▶️液晶ディスプレイ(LCD)の選択と表示情報を設定
液晶ディスプレイ(LCD)のI2Cアドレス(0x27)と表示範囲(2行16列)を設定します。
#液晶ディスプレイ(LCD)のパラメータを設定
LCD_ADR = 0x27
LCD_ROW = 2
LCD_COL = 16▶️I2C通信で液晶ディスプレイ(LCD)を利用
液晶ディスプレイ(LCD)に文字を表示させるため、I2cLcd() 関数を使ってオブジェクト(i2c_lcd)を作成し、i2c オブジェクト、アドレス(ADR)、行数(ROW)と列数(COL)を引数として渡します。
#LCDを利用するため、オブジェクト(i2c_lcd)を作成
i2c_lcd = I2cLcd(i2c_obj, LCD_ADR, LCD_ROW, LCD_COL)▶️「Ctrl + c」キーにより中断させる。
メイン処理は「while」文を使った無限ループの中で、1秒ごとに温度センサ(ADT7310)からデータを読み込み、計算した温度を摂氏として液晶ディスプレイ(LCD)に表示します。
「Ctrl + c」キーを押して、無限ループを抜けるために、KeyboardInterrupt例外「try … except KeyboardInterrupt: …」を利用します。
#例外処理(「Ctrl + c」キーにより中断)を設定
try:
    
    while True:
    
        #********** ADT7310 温度測定 **********   
             ・・・
             ・・・
        #********** 液晶ディスプレイ(LCD)に温度を表示 ********** 
             ・・・
             ・・・
#「Ctrl + c」キーにより中断。
except KeyboardInterrupt:
             ・・・▶️温度センサ(ADT7310)を初期化
ラズパイPicoWから温度センサ(ADT7310)に 「0xff,0xff,0xff,0xff」(32クロックの間High)を送り、温度センサ(ADT7310)をリセットします。
ラズパイPicoWと温度センサ(ADT7310)の間のデータ転送は一般的に次の手順で行います。
- 温度センサ(ADT7310)を非選択状態にします。
- 転送するデータを設定します。
- 温度センサ(ADT7310)を選択状態にします。
- データを転送します。
- 温度センサ(ADT7310)を非選択状態にします。
#シリアル・インターフェース リセット
spi_cs.value(1)
buff=bytearray([0xff,0xff,0xff,0xff])
spi_cs.value(0)
spi_obj.write(buff)
spi_cs.value(1)
sleep(0.1)▶️測定方法と測定値のデータの提供方法(13ビット、16ビット)の設定
測定した温度を即座にディジタル・データに変換、停止する測定方法に設定し、データを16ビットで提供するように設定します。
設定は次の手順で行います。
- 「コマンド・レジスタ」に「コンフィギュレーション・レジスタ」のアドレス(0x01)と、W(0)(書き込み)を設定します。(0x08)
- 「コンフィギュレーション・レジスタ」に、測定方法とデータの変換方法を(0xa0)設定し、上記の(0x08)と一緒に、spi_objオブジェクトのwriteメソッドで書き込みます。
【コマンド・レジスタ】
| MSB | 6 | 5 | 4 | 3 | 2 | 1 | LSB | 
| 0 | R(1) /W(0) | レジスタのアドレス | 連続読み出し | 0 | 0 | ||
【コンフィギュレーション・レジスタ】

#コンフィギュレーション・レジスタのアドレスと
#内容(一回のみの測定/変換、分解能を16ビット)を設定
buff=bytearray([0x08,0xa0])
        
        
#SPIのチップセレクトをONに設定
spi_cs.value(0)
     
#コマンド・バイトとコンフィギュレーション・レジスタに設定値を書き込む
spi_obj.write(buff)
        
        
#SPIのチップセレクトをOFFに設定
spi_cs.value(1)   ▶️16ビットのデータとして提供できるか確認
測定された温度をディジタル・データに変換するには時間を要するため、「ステータス・レジスタ(アドレス:0x00)」のビット7の状態から、ディジタル・データの保存状況を確認します。
「コマンド・レジスタ」に「ステータス・レジスタ」のアドレス(0x00)と、R(1)(読み込み)を設定(0x40)し、spi_objオブジェクトのwriteメソッドで書き込みます。
書き込み後、spi_objオブジェクトのreadメソッドで1バイトを読み込み、ビット7の状態を判定します、
【ステータス・レジスタ】

while True:
                
    # ステータスレジスタの読み込み
    sleep(0.01)
    buff=bytearray([0x40])
    spi_cs.value(0)
    spi_obj.write(buff)
    status_reg = bytearray(spi_obj.read(1,0x00))
    spi_cs.value(1)
    if ((status_reg[0] >> 7) & 1) == 0:
        break     ▶️ADT7310の温度データ(2バイト)を読み込み
温度センサ(ADT7310)のデータは2バイト(16ビット)で構成されているため、spi_objオブジェクトのreadメソッドを使って、指定のレジスタから2バイト分を読み込みます
「コマンド・レジスタ」に「温度の値を保存しているレジスタ」のアドレス(0x02)と、、R(1)(読み込み)を設定(0x50)し、spi_objオブジェクトのwriteメソッドで書き込みます。
「温度の値を保存しているレジスタ」(0x02)から2バイト分を読み込み、上位バイトと下位バイトをそれぞれの変数に保存します。
上位バイトと下位バイトを連結した2バイトデータから、温度を算出します。
#温度値レジスタのアドレスを設定
buff=bytearray([0x50])
         
         
#SPIのチップセレクトをONに設定
spi_cs.value(0)
        
        
#コマンド・バイトに設定値を書き込む
spi_obj.write(buff)        
   
    
#温度データ(2バイト)を読込
raw = bytearray(spi_obj.read(2,0x02))
        
        
#SPIのチップセレクトをOFFに設定
spi_cs.value(1)
        
        
        
#温度データの上位バイト
msb = raw[0]       
#温度データの下位バイト
lsb = raw[1]
        
        
#バイト連結
temp = (msb << 8) | lsb
    ▶️温度の算出
有効データ16ビットの内、最上位ビットは符号ビットであるため、温度の値は15ビット(0~32,768)で表現されます。
15ビットのデータで、−55°C~+150°Cの範囲の温度を、0.0078125°C刻みで表わすことができます。
下位7ビットは小数点を表わすビットになっているため、128で除算し、最終的に16ビットのデータを、小数点第七位を含めた温度に変換します。
#32768以上は65536を引いて負の値に変換
        if(temp >= 32768):
            temp = temp - 65536
    
    
        #温度に変換    
        temp = temp/128次の図は、温度センサ(ADT7310)の「温度の値を保存しているレジスタ」(0x02)から、msb = 0x0b、lsb = 0xa0のデータを読み込んだ時の温度の算出過程です。

次の表は、温度とデータとの関連です。
| 温 度 | ディジタルデータ(2進数) | ディジタルデータ(16進数) | 
| -55℃ | 1110 0100 1000 0000 | 0xE480 | 
| −50°C | 1110 0111 0000 0000 | 0xE700 | 
| −25°C | 1111 0011 1000 0000 | 0xF380 | 
| −0.0078125°C | 1111 1111 1111 1111 | 0xFFFF | 
| 0°C | 0000 0000 0000 0000 | 0x0000 | 
| +0.0078125°C | 0000 0000 0000 1000 | 0x0008 | 
| +25°C | 0000 1100 1000 0000 | 0x0C80 | 
| +50°C | 0001 1001 0000 0000 | 0x1900 | 
| +125°C | 0011 1110 1000 0000 | 0x3E80 | 
| +150°C | 0100 1011 0000 0000 | 0x4B00 | 
以下は温度を液晶ディスプレイ(LCD)に表示させるのプログラムです。詳しい表示方法については、「I2C通信で液晶ディスプレイ(LCD)に文字表示。」を参照してください。
▶️液晶ディスプレイ(LCD)に温度を表示
表示位置を初期化した後、小数点第一位までの温度を℃記号を含めて、1秒ごとに表示します。
#表示位置を初期化
i2c_lcd.move_to(0, 0)
    
    
#LCDに小数点第一位までの温度を表示
i2c_lcd.putstr("SPI-TEMP:{:.1f}".format(temp))
    
    
#℃表示
ch=[
#°
bytearray([0x07, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00]),
#C
bytearray([0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E, 0x00])
]
    
for i in range(len(ch)):
    i2c_lcd.custom_char(i, ch[i])
    i2c_lcd.putchar(chr(i))   
         
    
#1秒待つ
sleep(1)▶️プログラムの中断。
「Ctrl + c」キーを押すと、「KeyboardInterrupt」例外が発生し、液晶ディスプレイ(LCD)消灯後、処理が中断します。
#「Ctrl + c」キーにより中断。
except KeyboardInterrupt:
    # Turn off the display
    print("「Ctrl + c」キーが押されました。")
    
    #LCD消灯
    i2c_lcd.backlight_off()
    i2c_lcd.display_off()まとめ
ラズパイPicoW(Raspberry Pi Pico W)に温度センサ(ADT7310)と液晶ディスプレイ(LCD)を接続し、SPI通信を使って、温度センサで測定した気温を、液晶ディスプレイ(LCD)に表示させました。
SPI通信に接続された、デバイスの制御方法を学びました。
温度センサ(ADT7310)を使った、温度測定の計算原理を学びました。
