
前回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本の信号です。後忘れずにプルアップ抵抗。回路はこんな感じとなりました。
実験に使用したソース
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度とな(いい加減な四捨五入ですが。)
一方、測定結果を標準出力にたれ流している方はこんな感じの表示となります。
気温を測って7セグ表示。古めかしい。いつの時代だ。

