
前回はNucleo-F406REボードにAHT21B温湿度センサを接続。接続済の7セグLEDに温度を表示しました。しかし、折角の温湿度センサなのに湿度が表示できません。そこでボードにもれなくついてくる青色のUSERボタンで温度表示と湿度表示を切り替えるようにいたしました。ついでに赤LEDなら温度、青LEDなら湿度とな。
※「MicroPython的午睡」投稿順 Indexはこちら
※ST Microelectronics社製Nucleo-F401REボード上で使用しているSTM32版MicroPythonについてはこちら
AHT21Bセンサの湿度も表示したい
AHT21B温湿度センサは、1回のI2Cバス読み込みで温度と湿度の両方のデータを読み込むことができます。しかし前回は温度のみを7セグLEDに表示。湿度の方はprint関数でシリアルポートにたれ流すだけでした。折角なので両方表示したいです。そこで、Nucleoボードには「もれなくついてくる筈」の青のUSERボタンで温度表示と、湿度表示を切り替えることにいたしました。
-
- USERボタンを押すと温度表示と湿度表示をトグルする
- 現在の表示モードを示すため赤色LEDと青色LEDを接続し、温度表示で赤、湿度表示で青を点灯させる
- LEDの表示数値は毎秒更新
USERボタンは割り込み受けすることとしました。MicroPythonで割り込み受けするときのコマケー話は、以下で一度やってます。
MicroPython的午睡(86) STM32版、タイマ・チャネル、割り込み受け TIPS
なおUSERボタンはCPU端子名のPC13端子に接続されてます。この端子はMorphoピンヘッダ側には出てますが、Arduino互換ピンソケット側には出てない端子です。
赤色LEDは、Arduino互換ピンソケットのD6端子に1kΩの電流制限抵抗を介して接続。青色LEDは、Arduino互換ピンソケットのD7端子に1kΩの電流制限抵抗を介して接続しました。
今回実験のMicroPythonスクリプト
前回作成のAHT21B温湿度センサ用スクリプトに割り込み受けとLED表示のためのもろもろを追加したものが以下です。I2CとSPIとGPIO割り込みを併用しているのでちょいとメンドい感じになってきました。
#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
import micropython
import pyb
import uarray
from machine import Pin, I2C, SPI
micropython.alloc_emergency_exception_buf(100)
spi1 = SPI(1, 100_000)
rclk = Pin(machine.Pin.board.D10, Pin.OUT)
rclk.value(0)
userButton = machine.Pin.board.PC13
blueLED = Pin(machine.Pin.board.D7, Pin.OUT)
redLED = Pin(machine.Pin.board.D6, Pin.OUT)
blueLED.high()
redLED.low()
modFlag = uarray.array("i",[0])
def callback(line):
if modFlag[0]:
modFlag[0] = 0
redLED.low()
blueLED.high()
else:
modFlag[0] = 1
blueLED.low()
redLED.high()
extint = pyb.ExtInt(userButton, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, callback)
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))
if modFlag[0]:
displayFLT(temp)
else:
displayFLT(humi)
crcVerify = False
if buf[6] == calcCRC8(buf[0:6], opt=0xFF):
crcVerify = True
print("CRC Verify: {0}".format(crcVerify))
else:
print("ERROR!")
time.sleep(1)
# Normal End
if __name__ == "__main__":
main()
動作確認
上記のコードを走らせたところが以下に。まず初期状態は湿度表示モード。
下側の青色LEDが点灯し、7セグLEDは54%とな。そんなもんかい。
さてNucleo F401REボード側の青いUSERボタンを押したところが以下に。
今度は赤色LEDが点灯、22℃とな。まあ、前回述べたようにマイナス表示はできないのですが。
割り込みハンドラの書き方の小ネタ(ハンドラと共有する変数はuarray型にすること)が分かっていればどうということもなし。