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

Joseph Halfmoon

前回は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ボタンで温度表示と、湿度表示を切り替えることにいたしました。

    1. USERボタンを押すと温度表示と湿度表示をトグルする
    2. 現在の表示モードを示すため赤色LEDと青色LEDを接続し、温度表示で赤、湿度表示で青を点灯させる
    3. 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()
動作確認

上記のコードを走らせたところが以下に。まず初期状態は湿度表示モード。DisplayHumi

下側の青色LEDが点灯し、7セグLEDは54%とな。そんなもんかい。

さてNucleo F401REボード側の青いUSERボタンを押したところが以下に。DisplayTemp

今度は赤色LEDが点灯、22℃とな。まあ、前回述べたようにマイナス表示はできないのですが。

割り込みハンドラの書き方の小ネタ(ハンドラと共有する変数はuarray型にすること)が分かっていればどうということもなし。

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

MicroPython的午睡(95) STM32版、ハードウエアCRC32演算器の試用 へ進む