MicroPython的午睡(93) STM32版、7SEG2桁でAHT21Bの温度表示

Joseph Halfmoon

前回Nucleo-F406REのSPIの先に7セグLED2桁を接続。数字2桁で「だいたい済む」表示例として、今回はそれに気温を表示させてみたいと思います。インタフェースはI2C、センサはAHT21Bです。それにしてもAHT21B、MicroPythonで制御していた気になっていたのだけれどやってなかったのだな。

※「MicroPython的午睡」投稿順 Indexはこちら

ST Microelectronics社製Nucleo-F401REボード上で使用しているSTM32版MicroPythonについてはこちら

AHT21Bセンサ、Python3で制御していたの回

忘却力の年寄は、MicroPythonからも以前AHT21Bセンサを扱っていた記憶があったのですが、今回見直したらRaspberry Pi 3のPython3でした。「Microじゃない」Pythonね。記事が以下に。

部品屋根性(77) AHT21B、CRC8でのデータ検査を追加。ラズパイPython

文法はほとんど同じ、互換性も高いのですが、Python3のI2C制御は smbus モジュールを使用、MicroPythonでは、機種依存性を拭いきれない?machineパッケージのI2Cクラスを使用です。やることは一緒なんだけれども細かいところが違う、と。

実験に使用した回路

前回使用の回路をほぼほぼ流用、追加したのはAHT21BセンサとSCL、SDAの2本の信号です。後忘れずにプルアップ抵抗。回路はこんな感じとなりました。

STM32aht21bDUTschematic

実験に使用したソース

Python3版のAHT21B向け関数はなるべくそのまま流用していますが、smbusとI2Cモジュールの差があるので、i2cとインタフェースしているところのみ書き換えている感じです。これでAHT21Bから温度、湿度を読み取り、CRCチェック結果とあわせて標準出力に結果をたれ流してます。

そして前回の7セグインタフェース用の関数もまた流用。2桁の整数で気温を表示するようにしてみました。気温だと0℃以下ということもあるのでその場合はごめんなさいの0℃表示。0から100%の間に決まっている湿度の表示の方が良かったか?

#STM32: I2C1 AHT21B sensor I/F
#I2C1_SCL   PB_8 D15
#I2C1_SDA   PB_9 D14
#STM32: SPI1 74HC595 x 2 I/F
#SPI1_SCLK  PA_5 D13
#SPI1_MOSI  PA_7 D11
#LATCH RCLK PB_6 D10
import time
from machine import Pin, I2C, SPI

spi1 = SPI(1, 100_000)
rclk = Pin(machine.Pin.board.D10, Pin.OUT)
rclk.value(0)

dispPAT = [
  0b00111111,
  0b00000110,
  0b01011011,
  0b01001111,
  0b01100110,
  0b01101101,
  0b01111101,
  0b00000111,
  0b01111111,
  0b01101111,
  0b00000000,
  ]

addr = 0x38
i2c = I2C(1, freq=100000)

def calcCRC8(bytLis, poly=0x31, opt=0):
    """Caluculate CRC8 for byte List
    
    poly=0x31 for the AHT21b.
    """
    crc = opt
    for item in bytLis:
        crc ^= item
        for idx in range(8):
            if crc & 0x80:
                crc = ((crc << 1) & 0xFF) ^ poly
            else:
                crc = ((crc << 1) & 0xFF)
    return crc

def triggerAHT21B():
    """Triger measurement
    
    send 0xAC, 0x33, 0x00
    """
    time.sleep_ms(10)
    i2c.writeto(addr, bytes([0xAC, 0x33, 0x00]))

def readMeasurementResult():
    """Read 7 bytes
    
    status 8bit, Humidity 20bit, Temparature 20bit, CRC 8bit 
    """
    time.sleep_ms(80)
    msg = i2c.readfrom(addr, 7)
    return list(msg)

def initAHT21B():
    time.sleep_ms(100)
    i2c.writeto(addr, bytes([0x71]))
    msg = i2c.readfrom(addr, 1)
    res = list(msg)
    if len(res) == 1:
        if res[0] == 0x18:
            return True
    return False

def calcHumidity(buf):
    humInt = (buf[1]<<12) + (buf[2]<<4) + ((buf[3] & 0xF0)>>4)
    return (humInt / 2**20) * 100

def calcTemp(buf):
    tempInt = ((buf[3] & 0x0F)<<16) + (buf[4]<<8) + buf[5]
    return (tempInt / 2**20) * 200 - 50

def writeSEQ(datH, datL):
    work = bytes([datH, datL])
    spi1.write(work)
    rclk.value(1)
    time.sleep_ms(1)
    rclk.value(0)

def displayFLT(arg):
    Hi=0
    Lo=0
    if arg > 99.0:
        Hi = 9
        Lo = 9
    elif arg > 0.0:
        Hi, Lo = divmod(arg + 0.5, 10)
    writeSEQ(dispPAT[int(Hi)], dispPAT[int(Lo)])
    
def main():
    print("STM32F401RE I2C1-AHT21B SPI1-7SEG.")
    while True:
        triggerAHT21B()
        buf = readMeasurementResult()
        if len(buf)==7:
            print("Status: 0x{0:02x}".format(buf[0]))
            humi = calcHumidity(buf)
            temp = calcTemp(buf)
            print("Humidity [RH%]: {0:3.1f}".format(humi))
            print("Temperature[C]: {0:3.1f}".format(temp))
            displayFLT(temp)
            crcVerify = False
            if buf[6] == calcCRC8(buf[0:6], opt=0xFF):
                crcVerify = True
            print("CRC Verify: {0}".format(crcVerify))
        else:
            print("ERROR!")
        time.sleep(10)
    # Normal End

if __name__ == "__main__":
    main()
実行結果

動作中の写真を冒頭のアイキャッチ画像に掲げました。23度とな(いい加減な四捨五入ですが。)

一方、測定結果を標準出力にたれ流している方はこんな感じの表示となります。aht21bSTDIO

気温を測って7セグ表示。古めかしい。いつの時代だ。

MicroPython的午睡(92) STM32版、74HC595で7SEG LED2桁駆動 へ戻る

MicroPython的午睡(94) STM32版、Key割り込みで温度/湿度表示切替 に進む