TOPに戻る

ラズパイ2023年10月更新 bookworm ⑤ 4桁7segment LED

 AdafruitのStemma QT/Qwiicボードの中に、I2Cバス接続の4桁7セグメントLED表示器があります。コントローラはHT16K33です。白色をスイッチサイエンスから入手しました。Adafruitには、白色以外の色も用意されています。Stemma QT/Qwiicコネクタがついていないモデルは、アマゾンでも入手できます。

   4桁の7セグメントLED表示器 i2c HT16K33

 裏面のA0をショートして、スレーブ・アドレスを0x77に変更して使っています。変更前のデフォルトは0x76です。

pythonのプログラム<step1>

 I2Cバスをアクセスするsmbus2ライブラリを利用します。

 1 2 3 4

 5 6 7 8

 9 0 - .

を7セグメントLEDに繰り返して表示します。  

 System Setup Registerに'0'を書き込んで、クロックを有効にします。

i2c.write_byte_data(i2c_address, HT16K33_GENERIC_SYSTEM_ON,  0)

この記述と、

i2c.write_byte(i2c_address,HT16K33_GENERIC_SYSTEM_ON)

は、同じ結果になるようです。

 HT16K33のデータシートはこれですが、プログラムを記述するには足りないように思えます。検索して見つかったプログラムを参考にします。

i2c.write_byte_data(i2c_address, HT16K33_GENERIC_DISPLAY_ON, 0)

は、

i2c.write_byte(i2c_address,HT16K33_GENERIC_DISPLAY_ON)

でも、同様に動作します。

i2c.write_byte_data(i2c_address, HT16K33_GENERIC_CMD_BRIGHTNESS, 8)

は、輝度の設定です。0~15が指定でき、15が最大の明るさになります。

i2c.write_i2c_block_data(i2c_address, 0, [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])

は、4桁のLEDを消灯します。この記述ではなく、もっと別の方法で消灯できるかもしれません。

import time
import smbus2

i2c_address = 0x71
i2c =  smbus2.SMBus(1)

HT16K33_GENERIC_SYSTEM_ON  = 0x21
HT16K33_GENERIC_DISPLAY_ON = 0x81
i2c.write_byte_data(i2c_address, HT16K33_GENERIC_SYSTEM_ON,  0)
i2c.write_byte_data(i2c_address, HT16K33_GENERIC_DISPLAY_ON, 0)

HT16K33_GENERIC_CMD_BRIGHTNESS = 0xe0
i2c.write_byte_data(i2c_address, HT16K33_GENERIC_CMD_BRIGHTNESS, 8)

while 1:
    i2c.write_i2c_block_data(i2c_address, 0, [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
    time.sleep(0.1)

    i2c.write_byte_data(i2c_address, 0, 0x06)  #1
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 2, 0x5b)  #2
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 6, 0x4f)  #3
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 8, 0x66)  #4
    time.sleep(2)
    i2c.write_i2c_block_data(i2c_address, 0, [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
    time.sleep(0.1)

    i2c.write_byte_data(i2c_address, 0, 0x6d)  #5
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 2, 0x7d)  #6
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 6, 0x07)  #7
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 8, 0x7f)  #8
    time.sleep(2)
    i2c.write_i2c_block_data(i2c_address, 0, [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
    time.sleep(0.1)

    i2c.write_byte_data(i2c_address, 0, 0x67)  #9
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 2, 0x3f)  #0
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 6, 0x40)  #-
    time.sleep(0.1)
    i2c.write_byte_data(i2c_address, 8, 0x80)  #dot
    time.sleep(1)

pythonのプログラム<step2>

 pythonの辞書機能を使って、

  • 左からseg1、seg2、seg3、seg4と表示LEDの位置を指定でき
  • 0~9はnum[x]で表示

できるプログラムです。

 今、7セグメントLEDには、'5678'が表示されています。

import time
import smbus2

i2c_address=0x71
i2c=smbus2.SMBus(1)

HT16K33_GENERIC_SYSTEM_ON=0x21
HT16K33_GENERIC_DISPLAY_ON=0x81
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_SYSTEM_ON,0)
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_DISPLAY_ON,0)

HT16K33_GENERIC_CMD_BRIGHTNESS=0xe0
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_CMD_BRIGHTNESS,8)

i2c.write_i2c_block_data(i2c_address,0,[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
time.sleep(0.1)

num={0:0x3f,1:0x06,2:0x5b,3:0x4f,4:0x66,5:0x6d,6:0x7d,7:0x07,8:0x7f,9:0x67} # -;0x40,dot;0x80
seg1=0
seg2=2
seg3=6
seg4=8

i2c.write_byte_data(i2c_address, seg1, num[5])
i2c.write_byte_data(i2c_address, seg2, num[6])
i2c.write_byte_data(i2c_address, seg3, num[7])
i2c.write_byte_data(i2c_address, seg4, num[8])

 関数化を図ります。

 作ったのは、LEDを消灯するLEDclear()、7セグメントLEDの表示桁位置と、数字を引数とするdispLED(segment,number)です。

import time
import smbus2

i2c_address=0x71
i2c=smbus2.SMBus(1)

HT16K33_GENERIC_SYSTEM_ON=0x21
HT16K33_GENERIC_DISPLAY_ON=0x81
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_SYSTEM_ON,0)
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_DISPLAY_ON,0)

HT16K33_GENERIC_CMD_BRIGHTNESS=0xe0
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_CMD_BRIGHTNESS,8)

def LEDclear():
    i2c.write_i2c_block_data(i2c_address,0,[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])

num={0:0x3f,1:0x06,2:0x5b,3:0x4f,4:0x66,5:0x6d,6:0x7d,7:0x07,8:0x7f,9:0x67} # -;0x40,dot;0x80
seg={1:0,2:2,3:6,4:8}

def dispLED(segment,number):
    i2c.write_byte_data(i2c_address, seg[segment], num[number])

#main
LEDclear()
dispLED(1,0)
dispLED(2,9)
dispLED(3,8)
dispLED(4,7)

 実数dataを受けて表示をできるようにします。

 実数を引数とするdisp7seg(data)関数です。最初に、負の数かを判断しています。負の数であれば、neg=Trueとします。

 次に、小数点があるかどうかを見て、その位置dotNumPlaceを知ります。

    segmentPlace=1
    if neg==True:
        i2c.write_byte_data(i2c_address, seg[1], 0x40)
        segmentPlace=2

 表示は、左詰めにしています。segmentPlace=1は一番左の桁の位置用の変数です。負の数であれば、その位置にマイナス0x40を表示します。segmentPlace=2と表示位置を進めます。

 正の数であれば、segmentPlace=1のままです。

 lenString= len(dataString) 

 実数の長さlenStringを知ります。負の数の時は、マイナスを省きます。

    while lenString>0:
        dispNum=dataString[mojiichi-1:mojiichi]

  ...

 lenString=lenString-1

 長さlenStringをカウンタとして利用したループです。lenStringは一つの桁を表示するとだんだん減少していきますが、最初の桁位置位置を知るためのカウンタmojiichiを用意しています。最初は'1'でループに入り、表示すると増加します。

 実数を文字列とした文字列dataStringから1文字取り出して変数dispNumを得ます。

 もし小数点であれば、小数点の前の文字にドットを追加して表示dispLED(segmentPlace,int(dispNum),True)します。小数点と関係ないなら、そのまま表示dispLED(segmentPlace,int(dispNum),False)します。

 

dispNum=dataString[mojiichi-1:mojiichi]
        if  dispNum==".":
            mojiichi=mojiichi-1
            segmentPlace=segmentPlace-1
            dispNum=dataString[mojiichi-1:mojiichi]
            dispLED(segmentPlace,int(dispNum),True)
            mojiichi=mojiichi+1
        else:
            dispLED(segmentPlace,int(dispNum),False)

 表示関数dispLED(segment,number,dot)の引数は、表示LEDの桁位置segment、表示する数字number、ドットの有無を示すbool変数dotです。dotがTrueであれば、表示する数字の最上位ビットを'1'にして、ドットが点灯します。

def dispLED(segment,number,dot):
    if dot:
        i2c.write_byte_data(i2c_address, seg[segment], num[number] +128)  #  |= 0x80
    else:
        i2c.write_byte_data(i2c_address, seg[segment], num[number])

 23.4、-23.0、0、105.6を表示します。表示できる実数の範囲は制限を設けていないので、あくまでも、半導体センサが測定する温度ぐらいの表示用です。

import time
import smbus2

i2c_address=0x71
i2c=smbus2.SMBus(1)

HT16K33_GENERIC_SYSTEM_ON=0x21
HT16K33_GENERIC_DISPLAY_ON=0x81
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_SYSTEM_ON,0)
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_DISPLAY_ON,0)

HT16K33_GENERIC_CMD_BRIGHTNESS=0xe0
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_CMD_BRIGHTNESS,8)

def clearLED():
    i2c.write_i2c_block_data(i2c_address,0,[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])

num={0:0x3f,1:0x06,2:0x5b,3:0x4f,4:0x66,5:0x6d,6:0x7d,7:0x07,8:0x7f,9:0x67} # -;0x40,dot;0x80
seg={1:0,2:2,3:6,4:8}

def dispLED(segment,number,dot):
    if dot:
        i2c.write_byte_data(i2c_address, seg[segment], num[number] +128)  #  |= 0x80
    else:
        i2c.write_byte_data(i2c_address, seg[segment], num[number])


def disp7seg(data):
    if data<0 :
        neg=True
    else:
        neg=False
    dataString=str(data)
    dotNumPlace=dataString.find('.')+1

    dataString=str(abs(data))
    dotNumPlace=dataString.find('.')+1

    segmentPlace=1
    if neg==True:
        i2c.write_byte_data(i2c_address, seg[1], 0x40)
        segmentPlace=2
    lenString= len(dataString)
    mojiichi=1

    while lenString>0:
        dispNum=dataString[mojiichi-1:mojiichi]
        if  dispNum==".":
            mojiichi=mojiichi-1
            segmentPlace=segmentPlace-1
            dispNum=dataString[mojiichi-1:mojiichi]
            dispLED(segmentPlace,int(dispNum),True)
            mojiichi=mojiichi+1
        else:
            dispLED(segmentPlace,int(dispNum),False)
        segmentPlace=segmentPlace+1
        lenString=lenString-1
        mojiichi=mojiichi+1

print("test start")
clearLED()
data=23.4
print(data)
disp7seg(data)
time.sleep(3)

clearLED()
data=-23.0
print(data)
disp7seg(data)
time.sleep(3)

clearLED()
data=0
print(data)
disp7seg(data)
time.sleep(3)

clearLED()
data=105.6
print(data)
disp7seg(data)

pythonのプログラム<step3>

 第4回を参照して、I2Cバスに気圧センサBME280をつなぎ、測定値の中の温度を4桁7セグメントLED表示器に表示します。

 上記<step2>で作ったdisp7seg(data)関数は室温付近だと桁がオーバフローすることはありません。

 第4回を参照してデバイス・ドライバを組み込んでリブートします。

 組み込まれたことを確認します。0x77がUUになってます。

 プログラムです。

import time
import smbus2

i2c_address=0x71
i2c=smbus2.SMBus(1)

HT16K33_GENERIC_SYSTEM_ON=0x21
HT16K33_GENERIC_DISPLAY_ON=0x81
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_SYSTEM_ON,0)
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_DISPLAY_ON,0)

HT16K33_GENERIC_CMD_BRIGHTNESS=0xe0
i2c.write_byte_data(i2c_address,HT16K33_GENERIC_CMD_BRIGHTNESS,8)

def clearLED():
    i2c.write_i2c_block_data(i2c_address,0,[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])

num={0:0x3f,1:0x06,2:0x5b,3:0x4f,4:0x66,5:0x6d,6:0x7d,7:0x07,8:0x7f,9:0x67} # -;0x40,dot;0x80
seg={1:0,2:2,3:6,4:8}

def dispLED(segment,number,dot):
    if dot:
        i2c.write_byte_data(i2c_address, seg[segment], num[number] +128)  #  |= 0x80
    else:
        i2c.write_byte_data(i2c_address, seg[segment], num[number])

def disp7seg(data):
    if data<0 :
        neg=True
    else:
        neg=False
    dataString=str(data)
    dotNumPlace=dataString.find('.')+1

    dataString=str(abs(data))
    dotNumPlace=dataString.find('.')+1

    segmentPlace=1
    if neg==True:
        i2c.write_byte_data(i2c_address, seg[1], 0x40)
        segmentPlace=2
    lenString= len(dataString)
    mojiichi=1

    while lenString>0:
        dispNum=dataString[mojiichi-1:mojiichi]
        if  dispNum==".":
            mojiichi=mojiichi-1
            segmentPlace=segmentPlace-1
            dispNum=dataString[mojiichi-1:mojiichi]
            dispLED(segmentPlace,int(dispNum),True)
            mojiichi=mojiichi+1
        else:
            dispLED(segmentPlace,int(dispNum),False)
        segmentPlace=segmentPlace+1
        lenString=lenString-1
        mojiichi=mojiichi+1

# main
print("test start")
while 1:
    clearLED()
    f = open('/sys/bus/i2c/devices/1-0077/iio:device0/in_temp_input')
    Temp = round(int(f.read()) / 1000.0,1)
    f.close
    data= Temp
    print(data)
    disp7seg(data)
    time.sleep(3)

 実行中の様子です。

-