Raspberry Pi 3に温湿度センサ「SHT21」と「SHT11」を接続し、温湿度データを入力して表示します。プログラム言語はPython3でライブラリ「pigpio」を使用します。Raspberry Pi 3の設定については「pigpioによるI2CとSPIインタフェースの実装」を参考にしてください。
温湿度センサ「SHT21」の接続
温湿度センサ「SHT21」は、I2CでRaspberry Pi 3と接続します。仕様を次に示します。
- 動作電圧:2.1V~3.6V
- 測定範囲:-40~+125℃,0~100%RH
- 精度:温度±0.3℃ 湿度±2%RH
- 変換時間:温度 85ms 湿度 30ms
温湿度センサ「SHT21」は、ebayから購入しました。
次のebayから購入したSOT23のDIP変換基板にSHT21をはんだ付けし、ブレッドボードで使用できるようにしました(裏面のGNDの部分にはんだ付けされないように、DIP変換基板のパターンをカットしています)。
Raspberry Pi 3と温湿度センサ「SHT21」間で、I2CのSDAとSCLのそれぞれに接続します。温湿度センサ「SHT21」のVCCにはRaspberry Piの3.3Vを入力します。接続した画像を次に示します。
温湿度センサ「SHT21」のピン配置を次に示します。
次のコマンドでRaspberry Pi 3との接続を確認します。
$ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
- 温湿度センサ「SHT21」のアドレス - 0x40
温湿度センサ「SHT21」のPythonスクリプト
Python3でライブラリ「pigpio」を使用して、温湿度センサ「SHT21」のPythonスクリプト「mSHT21.py」を作成します。SHT21のデータシートを示します。
- 温湿度センサ「SHT21」から温度データを取得するには「Trigger T measurement(no hold master)」コマンド「0xF3」、湿度データを取得するには「Trigger RH measurement(no hold master)」コマンド「0xF5」を使用します。温湿度センサ「SHT21」のコマンド一覧を次に示します。
- 温湿度センサ「SHT21」からのセンサーデータにより、次の計算式に従って、温度/湿度を計算します。
- 温湿度センサ「SHT21」は、通信データの信頼性を確保するため8ビットのCRCが付与されています。
SHT21のCRC-8演算多項式: x8 + x5 + x4 +1
# -*- coding: utf-8 -*- import pigpio import time import devtemperature def _calculate_checksum(data, number_of_bytes): """5.7 CRC Checksum using the polynomial given in the datasheet""" # CRC POLYNOMIAL = 0x131 # //P(x)=x^8+x^5+x^4+1 = 100110001 crc = 0 # calculates 8-Bit checksum with given polynomial for byteCtr in range(number_of_bytes): crc ^= ((data[byteCtr])) for bit in range(8, 0, -1): if crc & 0x80: crc = (crc << 1) ^ POLYNOMIAL else: crc = (crc << 1) return crc def _get_temperature_from_buffer(data): """This function reads the first two bytes of data and returns the temperature in C by using the following function: T = -46.85 + (175.72 * (ST/2^16)) where ST is the value from the sensor """ unadjusted = ((data[0]) << 8) + (data[1]) unadjusted &= Sht21._STATUS_BITS_MASK # zero the status bits unadjusted *= 175.72 unadjusted /= 1 << 16 # divide by 2^16 unadjusted -= 46.85 return unadjusted def _get_humidity_from_buffer(data): """This function reads the first two bytes of data and returns the relative humidity in percent by using the following function: RH = -6 + (125 * (SRH / 2 ^16)) where SRH is the value read from the sensor """ unadjusted = ((data[0]) << 8) + (data[1]) unadjusted &= Sht21._STATUS_BITS_MASK # zero the status bits unadjusted *= 125.0 unadjusted /= 1 << 16 # divide by 2^16 unadjusted -= 6 return unadjusted class Sht21(object): # control constants _SOFTRESET = 0xFE DEFAULT_ADDRESS = 0x40 _TRIGGER_TEMPERATURE_NO_HOLD = 0xF3 _TRIGGER_HUMIDITY_NO_HOLD = 0xF5 _STATUS_BITS_MASK = 0xFFFC # datasheet (v4), page 9, table 7, thanks to Martin Milata # for suggesting the use of these better values # code copied from https://github.com/mmilata/growd _TEMPERATURE_WAIT_TIME = 0.086 # (datasheet: typ=66, max=85) _HUMIDITY_WAIT_TIME = 0.030 # (datasheet: typ=22, max=29) """コンストラクタ""" def __init__(self, pi): self.pi = pi self._device = pi.i2c_open(1, self.DEFAULT_ADDRESS) reg_data = [self._SOFTRESET] self.pi.i2c_write_device(self._device,reg_data) time.sleep(0.050) def read_temp(self): reg_data = [self._TRIGGER_TEMPERATURE_NO_HOLD] self.pi.i2c_write_device(self._device,reg_data) time.sleep(self._TEMPERATURE_WAIT_TIME) wc, data = self.pi.i2c_read_device(self._device, 3) if _calculate_checksum(data, 2) == (data[2]): return _get_temperature_from_buffer(data) def read_humidity(self): """Reads the humidity from the sensor. Not that this call blocks for ~30ms to allow the sensor to return the data""" reg_data = [self._TRIGGER_HUMIDITY_NO_HOLD] self.pi.i2c_write_device(self._device,reg_data) time.sleep(self._HUMIDITY_WAIT_TIME) wc, data = self.pi.i2c_read_device(self._device, 3) if _calculate_checksum(data, 2) == (data[2]): return _get_humidity_from_buffer(data) def cancel(self): """ Cancels the sensor and releases resources. """ if self._device is not None: self.pi.i2c_close(self._device) self._device = None if __name__ == "__main__": pi = pigpio.pi() if not pi.connected: exit(0) logger = 0 temp = devtemperature.Sht21(pi) while True: temperature = temp.read_temp() humidity = temp.read_humidity() print("temperature:{:.2f}℃ humidity:{:.2f}% ".format(temperature,humidity)) time.sleep(2.0)
温湿度センサ「SHT21」のPythonスクリプトの実行
作成したPythonスクリプトを次のコマンドで実行します。2秒ごとに温湿度センサ「SHT21」からの温湿度データを表示します。
$ python3 mSHT21.py temperature:20.91℃ humidity:52.24% temperature:20.91℃ humidity:52.24% temperature:20.91℃ humidity:52.24% temperature:20.91℃ humidity:52.27% temperature:20.91℃ humidity:52.24% temperature:20.91℃ humidity:52.24% temperature:20.92℃ humidity:52.27% temperature:20.92℃ humidity:52.27% temperature:20.92℃ humidity:52.27% temperature:20.93℃ humidity:52.30% temperature:20.93℃ humidity:52.30% temperature:20.93℃ humidity:52.30% temperature:20.93℃ humidity:52.30% temperature:20.93℃ humidity:52.30% temperature:20.94℃ humidity:52.33% temperature:20.94℃ humidity:52.36% temperature:20.95℃ humidity:52.36%
温湿度センサ「SHT11」の接続
温湿度センサ「SHT11」は、二本の信号線「DATA」「SCK」でRaspberry Pi 3と接続します。仕様を次に示します。
- 完全1チップの温度・湿度センサー
- A/Dコンバータ内蔵で完全デジタルで温度・湿度を出力
- 2線式でマイコンと接続
- 3~5V単一電源
- 調整不要で湿度±3.5%RH,温度±0.5℃の精度
- 分解能 湿度:0.03%RH,温度:0.01℃(
温湿度センサ「SHT11」のPythonスクリプト
Python3でライブラリ「pigpio」を使用して、温湿度センサ「SHT11」のPythonスクリプト「mSHT11.py」を作成します。SHT11のデータシートを示します。
- 最初にアドレス「000」を送信し、次に5ビットのコマンド「温度測定」「相対温度測定」を送信します。温湿度センサ「SHT11」のコマンド一覧を次に示します。
- 温度の計算は、温度の入力値(SOT)を温度値に変換するには次の式を用います(係数の値を次の表に示します)
- 相対湿度は、湿度指示値(SORH)に以下の公式と次に示される係数を適用して値を変換します。
# -*- coding: utf-8 -*- import pigpio import logging.config import time DATAPINT1 = 0x4 DATAPINTCW = 0x5 class SHT11(object): # Conversion coefficients from SHT15 datasheet D1 = -40.0 # for 14 Bit @ 5V D2 = 0.01 # for 14 Bit DEGC C1 = -2.0468 # for 12 Bit C2 = 0.0367 # for 12 Bit C3 = -0.0000015955 # for 12 Bit T1 = 0.01 # for 14 Bit @ 5V T2 = 0.00008 # for 14 Bit @ 5V """コンストラクタ""" def __init__(self, pidata, loggerdata, datapin): self.pi = pidata self.logger = loggerdata self.dataPin = datapin self.sckPin = SCKPIN # pigpio.setmode(GPIO_BOARD) self.__lastinvocationtime = 0 def read_temperature_and_humidity(self): temperature = humidity = 0 try: temperature = self.read_temperature_c() self.__wait() humidity = self._read_humidity(temperature) except SystemError: self.logger.error("温湿度取得エラー") finally: return temperature, humidity def __wait(self): last_invocation_delta = time.time() - self.__lastinvocationtime # if we queried the sensor less then a second ago, wait until a second is passed if last_invocation_delta < 1: time.sleep(1 - last_invocation_delta) self.__lastinvocationtime = time.time() def read_temperature_c(self): temperature_command = 0b00000011 self.__sendcommand(temperature_command) self.__waitforresult() raw_temperature = self.__getdata16bit() # self.logger.debug("raw_temperature:{:x}".format(raw_temperature)) self.__skipcrc() # pigpio.cleanup() return raw_temperature * SHT71.D2 + SHT71.D1 def _read_humidity(self, temperature): humidity_command = 0b00000101 self.__sendcommand(humidity_command) self.__waitforresult() raw_humidity = self.__getdata16bit() self.__skipcrc() # GPIO_BOARD.cleanup() # Apply linear conversion to raw value linear_humidity = SHT71.C1 + SHT71.C2 * raw_humidity + SHT71.C3 * raw_humidity * raw_humidity # Correct humidity value for current temperature return (temperature - 25.0) * (SHT71.T1 + SHT71.T2 * raw_humidity) + linear_humidity def __sendcommand(self, command): # Transmission start self.pi.set_mode(self.dataPin, pigpio.OUTPUT) self.pi.set_mode(self.sckPin, pigpio.OUTPUT) self.pi.write(self.dataPin, pigpio.HIGH) self.__clocktick(pigpio.HIGH) self.pi.write(self.dataPin, pigpio.LOW) self.__clocktick(pigpio.LOW) self.__clocktick(pigpio.HIGH) self.pi.write(self.dataPin, pigpio.HIGH) self.__clocktick(pigpio.LOW) for i in range(8): if (command & (1 << 7 - i)) != 0: commanddata = 1 else: commanddata = 0 self.pi.write(self.dataPin, commanddata) self.__clocktick(pigpio.HIGH) self.__clocktick(pigpio.LOW) self.__clocktick(pigpio.HIGH) self.pi.set_mode(self.dataPin, pigpio.INPUT) ack = self.pi.read(self.dataPin) # self.logger.debug("ack1: %s", ack) if ack != pigpio.LOW: self.logger.error("nack1") self.__clocktick(pigpio.LOW) ack = self.pi.read(self.dataPin) # self.logger.debug("ack2: %s", ack) if ack != pigpio.HIGH: self.logger.error("nack2") def __clocktick(self, value): self.pi.write(self.sckPin, value) # 100 nanoseconds time.sleep(.0000001) def __getdata16bit(self): self.pi.set_mode(self.dataPin, pigpio.INPUT) self.pi.set_mode(self.sckPin, pigpio.OUTPUT) # Get the most significant bits value = self.__shiftin(8) value *= 256 # Send the required ack self.pi.set_mode(self.dataPin, pigpio.OUTPUT) self.pi.write(self.dataPin, pigpio.HIGH) self.pi.write(self.dataPin, pigpio.LOW) self.__clocktick(pigpio.HIGH) self.__clocktick(pigpio.LOW) # Get the least significant bits self.pi.set_mode(self.dataPin, pigpio.INPUT) value |= self.__shiftin(8) return value def __shiftin(self, bitnum): value = 0 for i in range(bitnum): self.__clocktick(pigpio.HIGH) value = value * 2 + self.pi.read(self.dataPin) self.__clocktick(pigpio.LOW) return value def __skipcrc(self): # Skip acknowledge to end trans (no CRC) self.pi.set_mode(self.dataPin, pigpio.OUTPUT) self.pi.set_mode(self.sckPin, pigpio.OUTPUT) self.pi.write(self.dataPin, pigpio.HIGH) self.__clocktick(pigpio.HIGH) self.__clocktick(pigpio.LOW) def __waitforresult(self): self.pi.set_mode(self.dataPin, pigpio.INPUT) ack = pigpio.LOW for i in range(100): # 10 milliseconds time.sleep(.01) ack = self.pi.read(self.dataPin) if ack == pigpio.LOW: break if ack == pigpio.HIGH: raise SystemError def cancel(self): self.pi = 0 if __name__ == "__main__": logging.config.fileConfig('logging.conf') logger = logging.getLogger() pi = pigpio.pi() if not pi.connected: exit(0) temp = SHT11(pi, logger, DATAPINT4) while True: wtemperature, whumidity = temp.read_temperature_and_humidity() print("temperature:{:.2f}℃ humidity:{:.2f}% ".format(wtemperature, whumidity)) time.sleep(2.0)