LoginSignup
1
0

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

Last updated at Posted at 2024-02-20

 ラズパイ4を用いた<ラズパイ 2023年10月更新 bookworm 連載記事>をラズパイ5で再検証した記事です。

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

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

ht16k33-3.png

 裏面の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表示器に表示します。

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

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

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

ras101-e4e3ed25.png

 プログラムです。

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)

 実行中の様子です。

IMGP2094.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0