micro:bit / MicroPython / I2C デバイス (温湿度センサー HTU21D) を外づけする

#概要
I2C デバイス (温湿度センサー HTU21D) を micro:bit に外づけしてみる。I2C バスは micro:bit の標準端子 (P19 が SCL、P20 が SDA) をそのまま使った。プログラミング言語には MicroPython を使った。

##I2C の write 操作 (マスターからスレーブへのデータ転送)
構文: ```microbit.i2c.write(スレーブアドレス, バイト列 [, repeat=False])```

+ ```repeat=``` はオプション (```False``` がデフォルト)。```repeat=True``` を指定すれば Repeated Start となる。
+ スレーブアドレスは 7 ビットで指定する。
+ バイト列は以下の例では bytes() で作ったが bytearray() でもよい。bytes() で作った場合は tuple と同じで変更はできない。


##I2C の read 操作 (スレーブからマスターへのデータ転送)
構文: ``` microbit.i2c.read(スレーブアドレス, バイト数 [, repeat=False])```

+ ```repeat=``` はオプション (```False``` がデフォルト)。```repeat=True``` を指定すれば Repeated Start となる。
+ スレーブアドレスは 7 ビットで指定する。
  

#温度、湿度を読む出すための MicroPython スクリプト
温度、湿度の取得のほか、ソフトリセット、ユーザーレジスタの読み出し、測定分解能の変更もできるようにした。中身は[前回 mbed 用に作ったコード](https://qiita.com/cyq04000/items/74f574e4517b612cb9d3)と同じである。最新版は [GitHub](https://github.com/ti-nspire/microbit-in-micropython-library-for-HTU21D-sensor) にある。

```HTU21D.py
from microbit import *

class HTU21D:
    def __init__(self):
        self.HTDU21D_ADDRESS           = 0x40
        self.TRIGGER_TEMP_MEASURE_HOLD = 0xE3
        self.TRIGGER_HUMD_MEASURE_HOLD = 0xE5
        self.SHIFTED_DIVISOR           = (2**8 + 2**5 + 2**4 + 1)<<15
        self.READ_USER_REG             = 0xE7
        self.WRITE_USER_REG            = 0xE6
        self.SOFT_RESET                = 0xFE
        
        self.RH12_TEMP14 = 0b00000000
        self.RH08_TEMP12 = 0b00000001
        self.RH10_TEMP13 = 0b10000000
        self.RH11_TEMP11 = 0b10000001
        
    def readTemp(self):
        buf = bytes([self.TRIGGER_TEMP_MEASURE_HOLD])
        i2c.write(self.HTDU21D_ADDRESS, buf) 
                  
        msb, lsb, crc = i2c.read(self.HTDU21D_ADDRESS, 3)
        crcResult     = self.__check_crc(msb, lsb, crc)
        raw           = (msb<<8 | lsb) & 0xfffc
        temp          = -46.85 + 175.72 * raw / 65536.0
        
        return temp if crcResult == 0 else crcResult
        
    def readHumid(self):
        buf = bytes([self.TRIGGER_HUMD_MEASURE_HOLD])
        i2c.write(self.HTDU21D_ADDRESS, buf) 
                  
        msb, lsb, crc = i2c.read(self.HTDU21D_ADDRESS, 3)
        crcResult     = self.__check_crc(msb, lsb, crc)
        raw           = (msb<<8 | lsb) & 0xfffc
        humid         = -6.0 + 125.0 * raw / 65536.0
        
        return humid if crcResult == 0 else crcResult
        
    def __check_crc(self, msb, lsb, crc):
        divisor   = self.SHIFTED_DIVISOR
        remainder = msb<<16 | lsb<<8 | crc
        
        for i in range(23, 7, -1):
            if remainder & 1<<i:
                remainder ^= divisor
             
            divisor >>= 1
            
        return 0 if remainder == 0 else 999
    
    def readUserRegister(self):
        buf = bytes([self.READ_USER_REG])
        i2c.write(self.HTDU21D_ADDRESS, buf)
        
        return i2c.read(self.HTDU21D_ADDRESS, 1)
        
    def setResolution(self, resolution):
        userRegister = self.readUserRegister()[0]
        userRegister &= 0b01111110
        resolution   &= 0b10000001
        userRegister |= resolution
        
        buf = bytes([self.WRITE_USER_REG, userRegister])
        i2c.write(self.HTDU21D_ADDRESS, buf)
        
    def softReset(self):
        buf = bytes([self.SOFT_RESET])
        i2c.write(self.HTDU21D_ADDRESS, buf)

##############
# how to use #
##############
if __name__ == "__main__":
    HTU = HTU21D()
    
    #HTU.softReset() # To soft-reset the HTU21D, uncomment this line.
    
    #HTU.setResolution(HTU.RH12_TEMP14) # You can select one of the four resolutions.
    #HTU.setResolution(HTU.RH08_TEMP12)
    #HTU.setResolution(HTU.RH10_TEMP13)
    #HTU.setResolution(HTU.RH11_TEMP11)
    while True:
        #print(HTU.readUserRegister()) # To serial.print the user register, uncomment this line.
        
        temp  = HTU.readTemp()
        humid = HTU.readHumid()
        print("%.1f C, %.1f %%" % (temp, humid))
        sleep(1000)
```

#実行結果
<img src="https://qiita-image-store.s3.amazonaws.com/0/193936/a597c729-a179-a3b5-657c-9502ed69e699.png" width=400>


#参考
- Harry Fairhead, _micro:bit IoT in C_, I/O Press, pp.91-101
- 勝 純一, mbed 電子工作レシピ, 翔泳社
- [HTU21D データシート](http://www.te.com/commerce/DocumentDelivery/DDEController?Action=showdoc&DocId=Data+Sheet%7FHPC199_6%7FA6%7Fpdf%7FEnglish%7FENG_DS_HPC199_6_A6.pdf%7FHPP845E031R4)
- https://qiita.com/inachi/items/6ed7c42dc1faa35ba89c

#関連
- [Qiita / micro:bit / mbed / I2C デバイス (温湿度センサー HTU21D) を外づけする](https://qiita.com/cyq04000/items/74f574e4517b612cb9d3)
- [https://github.com/ti-nspire/microbit-in-mbed-library-for-HTU21D-sensor](https://github.com/ti-nspire/microbit-in-mbed-library-for-HTU21D-sensor)
- [はてなブログ / 温湿度センサー HTU21D / I2C](http://ti-nspire.hatenablog.com/archive/category/%E6%B8%A9%E6%B9%BF%E5%BA%A6%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%20HTU21D%20%2F%20I2C)