0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

4桁7セグメントLEDにデータを出力するPython用制御クラスを作る

Posted at

前回の投稿でHT16K33ドライバーモジュールを使ってユニバーサル基板に4桁7セグLEDを4個接続する方法を解説しました。
18x6 LEDドライバーモジュールを使って4桁7セグメントLEDを4個接続する

今回はHT16K33ドライバーモジュールを使った4桁7セグメントLEDへの出力を pythonで制御する方法を解説します。

開発環境

  • OS: Ubuntu 22.04
  • python3.7: ソースコードからビルドしたpythonで仮想環境を作る
    ※1 実行環境がRaspberry Pi OS なので、そのOS上のpythonバージョンに合わせる
    ※2 インストールするライブラリは実行環境と同じ
  • Python IDE: Pycharm Community Edition for Linux
    ※1 実行環境は Headless OS のため Thonny Pyton IDE による開発はできない
    ※2 pythonスクリプトを直接実行することはできないが関数補完は可能

実行環境

  • Rasbpebrry Pi Zero WH
  • OS: Raspbian GNU/Linux 10 (buster) ※Headless OS
  • python: 3.7.3
    • 使用するライブラリ: pigpio
      pip install pigpio

データシート

(1) システムセットアップレジスタ(内部システム発振器)

  • 起動時 ON: 0x20 + 1
  • シャットダウン時 OFF: 0x20 + 0

ht16k33_02_system_setup.jpg

(2) ディスプレーセットアップレジスタ

  • 起動時 ON: 0x80 + 1
  • シャットダウン時 OFF: 0x80 + 0

ht16k33_04_display_setup.jpg

(3) デジタル調光データ入力

ht16k33_06_digital_dimming_data_input.jpg

(4)メモリレイアウト

制御クラスの構成

  • HT16K33モジュールを制御するベースクラス
    GPIO制御用のPythonライブラリとして pigpio を使用
    pigpio library Python interface
  • 4桁7セグメントLED表示制御クラス
    ベースクラスを継承する

1. HT16K33ドライバーモジュール制御クラス

データシートに示された各種設定を操作するクラス

(1) 定数、列挙クラス

  • パス番号 (BUS_NUM): 1
    最近のラズパイのデフォルト。※この番号は変更可能なため定数として定義
  • デジタル調光の最低値 (BRIGHTNESS_BASE): 0xe0
    • Brightness (Enum)クラス
      ※4階調を定義
ht16k33.py
BUS_NUM = 1
BRIGHTNESS_BASE = 0xe0


class Brightness:
    HIGH = 0x0f
    MID = 0x08
    LOW = 0x04
    DIM = 0x02

(2) コンストラクタ

  • 引数
    • pi: pigpio オブジェクト
    • slave_addr: I2Cデバイス (スレーブ) アドレス
    • brightness: 接続デバイスの初期調光値
  • 処理内容
    • I2Cデバイス(キャラクタ・デバイス)ハンドルのオーブン
      //crw-rw---- 1 root i2c 89, 1 12月 24 14:29 /dev/i2c-1
      オープンしたI2Cデバイスハンドルをオブジェクトに保持する
    • システムセットアップ ON (0x21)
    • ディスプレーセットアップ ON (0x81)
    • 接続デバイスの初期調光値を設定
class HT16K33:
    MEM_LAST = 0x0f

    def __init__(self, pi, slave_addr, bus_number=BUS_NUM, brightness=Brightness.MID):
        self.pi = pi
        self.i2c_handle = pi.i2c_open(bus_number, slave_addr)
        self.opened = True
        # System setup: Turn on System oscillator(発振器) [0x20 + 1(on)]
        self.pi.i2c_write_byte(self.i2c_handle, 0x21)
        # Display setup: Display on [0x80 + 1(on)]
        self.pi.i2c_write_byte(self.i2c_handle, 0x81)
        # Brightness: [0xe0 + f{1,0,0,0}]
        self.pi.i2c_write_byte(self.i2c_handle, (BRIGHTNESS_BASE | brightness))

(3) クリーンアップ

  • 処理内容
    • メモリクリア
    • ディスプレーセットアップ OFF (0x80)
    • システムセットアップ OFF (0x20)
    • オブジェクトのI2Cデバイスハンドルをクローズ
    def cleanup(self):
        # Poweroffでもメモリーの値は残っている
        self.clear_memory()
        # Display setup: Display off
        self.pi.i2c_write_byte(self.i2c_handle, 0x80)
        # System setup: Turn on System oscillator off
        self.pi.i2c_write_byte(self.i2c_handle, 0x20)
        self.pi.i2c_close(self.i2c_handle)
        self.opened = False

(4) 調光値の変更

任意の時点でデバイスの調光値を変更する

    def set_brightness(self, brightness):
        self.pi.i2c_write_byte(self.i2c_handle, (BRIGHTNESS_BASE | brightness))

(5) メモリクリア
メモリ(バイト単位)に [0x0] を設定する
※デバイスが表示器の場合は消灯

    def clear_memory(self):
        for m_addr in range(self.MEM_LAST + 1):
            self.pi.i2c_write_byte_data(self.i2c_handle, m_addr, 0x0)

(6) データ転送関数

指定されたメモリの開始アドレスに N 桁分のデータを設定する
※1 想定する最大桁数は4桁分
※2 前回送信したアドレスに2バイト分加算したアドレスが次の送信アドレスになる

    def send_data(self, start_reg, datas):
        # 送信データを下位メモリから送信する
        reg = start_reg
        for i in range(len(datas)):
            val = datas[i]
            self.pi.i2c_write_byte_data(self.i2c_handle, reg, val)
            reg += 0x02

(7) 全ソースの再掲

※ログ出力処理を含んでいます。

lib/ht16k33.py
import logging

"""
LEDドライバモジュール(HT16K33)制御クラス for pigpio
"""

BUS_NUM = 1
BRIGHTNESS_BASE = 0xe0


class Brightness:
    HIGH = 0x0f
    MID = 0x08
    LOW = 0x04
    DIM = 0x02


class HT16K33:
    MEM_LAST = 0x0f

    def __init__(self, pi, slave_addr, bus_number=BUS_NUM, brightness=Brightness.MID, logger=None):
        self.pi = pi
        # i2c_handle = /dev/self.i2c_bus-1
        self.i2c_handle = pi.i2c_open(bus_number, slave_addr)
        self.logger = logger
        self.debug_once = logger is not None and (logger.getEffectiveLevel() <= logging.DEBUG)
        if logger is not None:
            logger.info("i2c_handle: {}".format(self.i2c_handle))
        self.opened = True
        # System setup: Turn on System oscillator(発振器) [0x20 + 1(on)]
        self.pi.i2c_write_byte(self.i2c_handle, 0x21)
        # Display setup: Display on [0x80 + 1(on)]
        self.pi.i2c_write_byte(self.i2c_handle, 0x81)
        # Brightness: [0xe0 + f{1,0,0,0}]
        self.pi.i2c_write_byte(self.i2c_handle, (BRIGHTNESS_BASE | brightness))

    def clear_memory(self):
        for m_addr in range(self.MEM_LAST + 1):
            self.pi.i2c_write_byte_data(self.i2c_handle, m_addr, 0x0)

    def debug_memory(self):
        for m_addr in range(0x0f + 1):
            r_data = self.pi.i2c_read_byte_data(self.i2c_handle, m_addr)
            if self.debug_once:
                self.logger.debug("r_data[{:#04x}]: {:#04x}".format(m_addr, r_data))

    def cleanup(self):
        # Poweroffでもメモリーの値は残っている
        self.clear_memory()
        # Display setup: Display off
        self.pi.i2c_write_byte(self.i2c_handle, 0x80)
        # System setup: Turn on System oscillator off
        self.pi.i2c_write_byte(self.i2c_handle, 0x20)
        self.pi.i2c_close(self.i2c_handle)
        self.opened = False

    # クリーンアップ途中でクローズに失敗した場合に単独で実行
    def force_close(self):
        if self.opened:
            self.pi.i2c_close(self.i2c_handle)

    def send_data(self, start_reg, datas):
        # 送信データを下位メモリから送信する
        reg = start_reg
        for i in range(len(datas)):
            val = datas[i]
            self.pi.i2c_write_byte_data(self.i2c_handle, reg, val)
            reg += 0x02

    def set_brightness(self, brightness):
        self.pi.i2c_write_byte(self.i2c_handle, (BRIGHTNESS_BASE | brightness))

2. 4桁7セグメントLED出力制御

2-1. 出力仕様

2-1-1. 出力文字に対応する16進表現

7Seg_16numbers.jpg

2-1-2. 4桁7セグメントLEDの配線位置と出力する桁に対応するメモリ構造

2-2. 4桁7セグメントLED出力制御クラス

  • カソードコモンのみを対象とする
  • 数値出力: マイナスを含め4桁
    • 整数: -999 〜 9999
    • 実数 (小数点第1位固定): -99.9 〜 999.9

※ デバック用ログ出力は省略

2-2-1. インポートと他のクラス定義

  • LEDのカソード・アノード区分 Enumクラス定義 (LEDCommon)
  • 出力する4桁7セグメントLEDの番号 Enumクラス定義 (LEDNumber)
led4digit7seg.py
import logging
from enum import Enum
from .ht16k33 import HT16K33, BUS_NUM


class LEDCommon(Enum):
    CATHODE = 0
    ANODE = 1


class LEDNumber(Enum):
    N1 = 0
    N2 = 1
    N3 = 2
    N4 = 3

2-2-2. クラス外の関数定義

(1) 整数値を数字の逆順リストに変換する処理

DIGIT = 4

def _make_digits(number):
    """
    数値を数字のリストに変換する (リストは逆順になる)
    (例) 123 ->  [3, 2, 1]
    :param number: 数値(最大4桁の整数 or マイナスの場合は3桁)
    :return: 数値を逆順にした数字のリスト
    """
    digits = []
    num, mod = number, 0
    for _ in range(DIGIT):
        num, mod = divmod(num, 10)
        digits.append(mod)
        if num == 0:
            break
    return digits

上記処理で生成される数値リストのイメージは下記のようにになります。

makeData_1_int_1.jpg

2-2-3. 4桁7セグメントLED制御クラス

(1) クラスの定数定義

  • 数字の16進数表現配列: SEG_CHAR
  • ハイフン(マイナス)の16進数表現: SEG_MINUS
  • エラー表示用('EEEE')の16進数表現: SEG_ERRORS
  • 初期表示用('----')の16進数表現: SEG_OUTOFRANGE
  • 各4桁7セグメントLEDに出力するメモリ開始アドレス
    REG_LED1 〜 REG_LED4
  • カソードコモンLEDのメモリアドレスマップ: STAREG_CATHODE
class LED4digit7Seg(HT16K33):
    # 表示文字定義: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    SEG_CHAR = [0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x67]
    # ハイフン:'-'
    SEG_MINUS = 0x40
    # エラー:'EEEE'
    SEG_ERRORS = [0x79] * DIGIT
    # 測定不能:'----'
    SEG_OUTOFRANGE = [SEG_MINUS] * DIGIT
    # メモリ開始アドレス
    REG_LED1 = 0x00
    REG_LED2 = 0x08
    REG_LED3 = 0x01
    REG_LED4 = 0x09
    # メモリ開始アドレスマップ
    STAREG_CATHODE = {LEDNumber.N1: REG_LED1, LEDNumber.N2: REG_LED2, LEDNumber.N3: REG_LED3, LEDNumber.N4: REG_LED4}

(2) コンストラクタ

  • 引数
    • pi: pigpio オブジェクト
    • slave_addr: I2Cデバイス (スレーブ) アドレス
    • brightness: 接続デバイスの初期調光値
    • 7セグメントLEDのコモン種別
  • 処理内容
    • スーパークラス(HT16K33)のコンストラクタ呼び出し
    • オブジェクトに7セグメントLEDのコモン種別を保持
    def __init__(self, pi, slave_addr, bus_number=BUS_NUM, brightness=None,
                  common=LEDCommon.CATHODE):
        super().__init__(pi, slave_addr, bus_number, brightness=brightness)
        self.common = common

(3) メモリに転送するデータの初期化
※整数データ、実数データ共通

    datas = [0] * DIGIT // DIGIT=4

※4桁7セグメントLEDの全ての桁が消灯となる
makeData_1_int_2_data_init.jpg

2-2-3-1. 整数データの転送用データ変換処理

(1) 数字の逆順リストから転送用データを生成

  • 処理手順
    • 転送用データの初期化
    • 正の数値リストをメモリ転送用データの4桁目から格納
    • 元の整数値がマイナスの場合
      • 最後のデータの1つ前 (先頭側) にマイナスの16進表現を設定
    def _make_int_datas(self, digits, has_minus=False):
        # カソードコモンLED用
        datas = [0] * DIGIT
        # 数値列(入力値の逆順で4桁目が先頭)を送信データの4桁目から格納する
        elem = DIGIT - 1
        for i in range(len(digits)):
            datas[elem] = self.SEG_CHAR[digits[i]]
            elem -= 1
        # 整数値がマイナスのケースに対応
        if has_minus:
            # 正数部分は1桁少ない
            elem -= 1
            datas[elem] = self.SEG_MINUS
        return datas

(2) 整数値を転送用データに変換する

  • 処理手順
    • 整数値がマイナスの場合
      • マイナスフラグをONにセット
      • 正の整数値に変換
    • 正の整数値を数字の逆順リストに変換
    • 数字の逆順リストからメモリ転送用データを生成する
    def _generate_int_datas(self, number):
        is_minus = False
        if number >= 0:
            val = number
        else:
            # マイナスなら絶対値にしてマイナスフラグをTrueに設定
            val = abs(number)
            is_minus = True
        digits = _make_digits(val)
        datas = self._make_int_datas(digits, has_minus=is_minus)
        return datas

この処理で生成される転送用データの表示イメージは以下のようになります。

(3) 整数値の出力処理

メインのアプリケーションから呼び出される

  • 引数
    • 整数データ: int_val
    • 出力するLED番号: led_num
  • 処理内容
    • 数値チェック
      • 範囲外の数値
        • 範囲外(オールハイフン)のメモリ転送用データを生成
      • 有効な数値
        • 数値データをメモリ転送用データに変換する
    • LED番号に対応する開始アドレス (カソードコモン用) を取得する
    • 開始アドレスとメモリ転送用データをHT16K33オブジェクトに設定
      ※指定したLED番号の4桁7セグメントLEDに数値が表示される
    def printInt(self, int_val, led_num=LEDNumber.N1):
        if int_val < -999 or int_val > 9999:
            datas = self.SEG_OUTOFRANGE
        else:
            datas = self._generate_int_datas(int_val)
        stareg = self.STAREG_CATHODE[led_num]
        self.send_data(stareg, datas)
2-2-3-2. 実数データの転送用データ変換処理
  • 処理手順
    • 空の仮データリストを生成
    • 数値がマイナスの場合
      • 仮データリストにマイナスの16進数表現をセット
      • 正の実数に変換
    • 数値を小数点第1位で四捨五入してから文字列に変換
    • 文字列の長さ分処理を繰り返す
      • ドットが出現した場合
        • 前の数値 (16進数表現) に128をプラスする
        • 次の文字を処理する
      • 数値の文字列に対応する16進数表現を仮データリストに追加する
    • ドットが出現しなかった場合
      • 仮データリスト末尾の16進数表現に128をプラスする
      • 小数点以下のゼロを補う
    • 転送用データの初期化
    • 仮データリストを転送用データに逆順で格納しなおす
    def _generate_float_datas(self, float_val):
        t_datas = []
        # 数値が負なら先頭にマイナスのLED表現をセット
        if float_val < 0:
            t_datas.append(self.SEG_MINUS)
            # マイナス符号を除去
            float_val *= -1
        # 浮動小数点の場合は文字列に変換 ※小数点1桁で4捨5入
        s_val = str(round(1.0 * float_val, 1))
        has_dot = False
        for s in list(s_val):  # 数値文字列をリストに変換
            if s == '.':
                # ドットが出現したら前の数値に128をプラス
                t_datas[len(t_datas) - 1] += 128
                has_dot = True
                continue

            # ドット以外は数値
            t_datas.append(self.SEG_CHAR[ord(s) - 48])  # '0': 48, '1':49, ...

        # ドットの出現有無判定
        if not has_dot:
            # 出現しなかったら配列末尾の数値表現+128
            t_datas[len(t_datas) - 1] += 128
            # 小数点以下のゼロを補う
            t_datas.append(self.SEG_CHAR[0])

        # 出力用4桁バッファに逆順に格納しなおす
        datas = [0] * DIGIT
        pos = DIGIT
        for i in range(len(t_datas) - 1, -1, -1):
            pos -= 1
            datas[pos] = t_datas[i]
        return datas

この処理で生成される転送用データの表示イメージは以下のようになります。

(2) 実数値の出力処理

メインのアプリケーションから呼び出される

  • 引数
    • 実数データ: float_val ※小数点第1位固定
    • 出力するLED番号: led_num
  • 処理内容
    • 数値チェック
      • 範囲外の数値
        • 範囲外(オールハイフン)のメモリ転送用データを生成
      • 有効な数値
        • 数値データをメモリ転送用データに変換する
    • LED番号に対応する開始アドレス (カソードコモン用) を取得する
    • 開始アドレスとメモリ転送用データをHT16K33オブジェクトに設定
      ※指定したLED番号の4桁7セグメントLEDに数値が表示される
    def printFloat(self, float_val, led_num=LEDNumber.N1):
        if float_val < -99.9 or float_val > 999.9:
            datas = self.SEG_OUTOFRANGE
        else:
            datas = self._generate_float_datas(float_val)
        stareg = self.STAREG_CATHODE[led_num]
        self.send_data(stareg, datas)

(3) 全ソース再掲

※1 ログ出力処理を含んでいます。
※2 アノードコモン用のLED出力 (最大2個) にも対応してます。

lib/led4digit7seg.py
import logging
from enum import Enum
from .ht16k33 import HT16K33, BUS_NUM

"""
LEDドライバモジュール(HT16K33)を使った4桁7セグメントLED表示ライブラリ for pigpio
最大4個まで出力
[出力仕様]
(1) 整数値: -999 〜 9999
(2) 実数値: -99.9 〜 999.9 ※小数点第1位
[部品]
 4桁7セグLED x 1〜4個
 16x8マトリクスLEDドライバモジュール(HT16K33) x 1個
"""

DIGIT = 4


def _make_digits(number):
    """
    数値を数字のリストに変換する (リストは逆順になる)
    (例) 123 ->  [3, 2, 1]
    :param number: 数値(最大4桁の整数 or マイナスの場合は3桁)
    :return: 数値を逆順にした数字のリスト
    """
    digits = []
    num, mod = number, 0
    for _ in range(DIGIT):
        num, mod = divmod(num, 10)
        digits.append(mod)
        if num == 0:
            break
    return digits


def _to_bins(val):
    """
    数値の2進数計算 ※アノードコモンのみ
    :param val:数値
    :return: 2進数のリスト
    """
    # 配列は8bit分初期化
    bins = [0] * 8
    num, mod = val, 0
    for i in range(8):
        num, mod = divmod(num, 2)
        bins[i] = mod
        if num == 0:
            break
    # ビット計算用に逆順にする
    return bins[::-1]


class LEDCommon(Enum):
    CATHODE = 0
    ANODE = 1


class LEDNumber(Enum):
    N1 = 0
    N2 = 1
    N3 = 2
    N4 = 3


class LED4digit7Seg(HT16K33):
    # 表示文字定義: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    SEG_CHAR = [0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x67]
    # ハイフン:'-'
    SEG_MINUS = 0x40
    # エラー:'EEEE'
    SEG_ERRORS = [0x79] * DIGIT
    # 測定不能:'----'
    SEG_OUTOFRANGE = [SEG_MINUS] * DIGIT
    # [LED1] DIG1:COM0(0x00),DIG2:COM1(0x02),DIG3:COM2(0x04),DIG4:COM3(0x06)
    #        ROW7(dp[3]), ROW6(g[5]), ROW5(f[10]), ROW4(e[1]), ROW3(d[2]), ROW2(c[4]), ROW1(b[7]), ROW0(a[11])
    REG_LED1 = 0x00
    # [LED2] DIG1:COM4(0x08),DIG2:COM5(0x0A),DIG3:COM6(0x0C),DIG4:COM7(0xEH)
    #        ROW7, ROW6(D6),..., ROW1, ROW0
    REG_LED2 = 0x08
    # [LED3] DIG1:COM0(0x01),DIG2:COM1(0x03),DIG3:COM2(0x05),DIG4:COM3(0x07)
    #        ROW15(dp[3]), ROW14(g[5]), ROW13(f[10]), ROW12(e[1]), ROW11(d[2]), ROW10(c[4]), ROW9(b[7]), ROW8(a[11])
    REG_LED3 = 0x01
    # [LED4] DIG1:COM4(0x09),DIG2:COM5(0x0B),DIG3:COM6(0x0D),DIG4:COM7(0xFH)
    #        ROW15, ROW14,..., ROW9, ROW8
    REG_LED4 = 0x09
    # アノードコモン
    REG_ANODE_LED1 = REG_LED1
    REG_ANODE_LED2 = REG_LED3
    # メモリ開始アドレスマップ
    STAREG_CATHODE = {LEDNumber.N1: REG_LED1, LEDNumber.N2: REG_LED2, LEDNumber.N3: REG_LED3, LEDNumber.N4: REG_LED4}
    STAREG_ANODE = {LEDNumber.N1: REG_ANODE_LED1, LEDNumber.N2: REG_ANODE_LED2}

    def __init__(self, pi, slave_addr, bus_number=BUS_NUM, common=LEDCommon.CATHODE,
                 brightness=None, logger=None):
        super().__init__(pi, slave_addr, bus_number, brightness=brightness, logger=logger)
        self.common = common
        self.logger = logger
        self.debug_once = logger is not None and (logger.getEffectiveLevel() <= logging.DEBUG)

    def _make_int_datas(self, digits, has_minus=False):
        # カソードコモンLED用
        datas = [0] * DIGIT
        # 数値列(入力値の逆順で4桁目が先頭)を送信データの4桁目から格納する
        elem = DIGIT
        for i in range(len(digits)):
            elem -= 1
            datas[elem] = self.SEG_CHAR[digits[i]]
        # 整数値がマイナスの場合は先頭側にマイナスの16進数表現を追加
        if has_minus:
            elem -= 1
            datas[elem] = self.SEG_MINUS
        return datas

    def _convert_anode(self, cathode_datas):
        # カソードコモンLED用データをアノードコモンLED用に変換
        datas = [0] * 8
        for row in range(len(cathode_datas)):
            val = cathode_datas[row]
            val_bins = _to_bins(val)
            if self.debug_once:
                self.logger.debug("cathode_datas[{0}]: ({1}) - {1:#04x}".format(row, val))
                self.logger.debug("val_bins: {}".format(val_bins))
            # 8bit分: D7,D6,D5,D4, D3, D2, D1, D0
            #          0, 0, 0, 0, <<3,<<2,<<1,<<0
            for com_j in range(8):
                datas[com_j] = datas[com_j] | (val_bins[com_j] << (3 - row))
        return datas

    def _generate_int_datas(self, number):
        is_minus = False
        if number >= 0:
            val = number
        else:
            # マイナスなら絶対値にしてマイナスフラグをTrueに設定
            val = abs(number)
            is_minus = True
        # 数値を数字の逆順配列に変換する
        digits = _make_digits(number)
        if self.debug_once:
            self.logger.debug("number: {} -> digits: {}".format(number, digits))
        # ドライバーモジュールのメモリ形式に変換
        datas = self._make_int_datas(digits, has_minus=is_minus)
        if self.debug_once:
            self.logger.debug("datas: {}".format(datas))
        if self.common == LEDCommon.ANODE:
            # アノードコモンLEDに変換
            datas = self._convert_anode(datas)
        if self.debug_once:
            for i, data in enumerate(datas):
                self.logger.debug("datas[{}]: {:#04x}".format(i, data))
        return datas

    def _generate_float_datas(self, float_val):
        if self.debug_once:
            self.logger.debug("float_val: {}".format(float_val))

        t_datas = []
        # 数値が負なら先頭にマイナスのLED表現をセット
        if float_val < 0:
            t_datas.append(self.SEG_MINUS)
            # マイナス符号を除去
            float_val *= -1
        # 浮動小数点の場合は文字列に変換 ※小数点1桁で4捨5入
        s_val = str(round(1.0 * float_val, 1))
        has_dot = False
        for s in list(s_val):  # 数値文字列をリストに変換
            if s == '.':
                # ドットが出現したら前の数値に128をプラス
                t_datas[len(t_datas) - 1] += 128
                has_dot = True
                continue

            # ドット以外は数値
            t_datas.append(self.SEG_CHAR[ord(s) - 48])  # '0': 48, '1':49, ...

        # ドットの出現有無判定
        if not has_dot:
            # 出現しなかったら配列末尾の数値表現+128
            t_datas[len(t_datas) - 1] += 128
            # 小数点以下のゼロを補う
            t_datas.append(self.SEG_CHAR[0])

        if self.debug_once:
            for i in range(len(t_datas)):
                self.logger.debug("t_datas[{}]: {:#04x}".format(i, t_datas[i]))
        # 出力用4桁バッファに逆順に格納しなおす
        datas = [0] * DIGIT
        pos = DIGIT
        for i in range(len(t_datas) - 1, -1, -1):
            pos -= 1
            datas[pos] = t_datas[i]
        if self.debug_once:
            for i in range(len(datas)):
                self.logger.debug("datas[{}]: {:#04x}".format(i, datas[i]))
        return datas

    def printFloat(self, float_val, led_num=LEDNumber.N1):
        if float_val < -99.9 or float_val > 999.9:
            datas = self.SEG_OUTOFRANGE
            if self.logger is not None:
                self.logger.warning("float value is out of range: {}".format(float_val))
        else:
            datas = self._generate_float_datas(float_val)
            if self.common == LEDCommon.ANODE:
                # アノードコモン: アノードコモン用のデータに変換
                datas = self._convert_anode(datas)
        stareg = self.STAREG_CATHODE[led_num] if self.common == LEDCommon.CATHODE else self.STAREG_ANODE[led_num]
        self.send_data(stareg, datas)

    def printInt(self, int_val, led_num=LEDNumber.N1):
        if int_val < -999 or int_val > 9999:
            datas = self.SEG_OUTOFRANGE
            if self.logger is not None:
                self.logger.warning("int value is out of range: {}".format(int_val))
        else:
            datas = self._generate_int_datas(int_val)
        stareg = self.STAREG_CATHODE[led_num] if self.common == LEDCommon.CATHODE else self.STAREG_ANODE[led_num]
        self.send_data(stareg, datas)

    def printOutOfRange(self, led_num=LEDNumber.N1):
        """
        範囲外: '----'
        :param led_num: 出力先LED
        """
        stareg = self.STAREG_CATHODE[led_num] if self.common == LEDCommon.CATHODE else self.STAREG_ANODE[led_num]
        self.send_data(stareg, self.SEG_OUTOFRANGE)

    def printError(self, led_num=LEDNumber.N1):
        """
        測定値エラー: 'EEEE'
        :param led_num: 出力先LED
        """
        stareg = self.STAREG_CATHODE[led_num] if self.common == LEDCommon.CATHODE else self.STAREG_ANODE[led_num]
        self.send_data(stareg, self.SEG_ERRORS)

3. メインアプリケーション

下記のように出力する Ptyhonアプリケーションのコードを示します。
※1 1分後に全ての4桁7セグメントLEDが消灯して終了
※2 エラー処理は省略

import logging
from lib.led4digit7seg import LED4digit7Seg, LEDCommon, LEDNumber
from log import logsetting


if __name__ == '__main__':
    logging.basicConfig(format='%(levelname)s %(message)s')
    app_logger = logging.getLogger(__name__)
    app_logger.setLevel(level=logging.DEBUG)

    # pigpioオブジェクト生成
    pi = pigpio.pi()
    # 本来はここで pigpioサービスが起動されているかチェックする
    
    i2c_slave_addr = 0x70
    # カソードコモンを指定
    led_common = LEDCommon.CATHODE
    led_driver = LED4digit7Seg(pi, i2c_slave_addr, common=led_common, logger=logger)
    try:
        led_driver.printFloat(26.7, led_num=LEDNumber.N1)
        led_driver.printFloat(20.5, led_num=LEDNumber.N2)
        led_driver.printFloat(56.7, led_num=LEDNumber.N3)
        led_driver.printInt(1002, led_num=LEDNumber.N4)
        
        # 1分後に終了
        time.sleep(60.0)
    except KeyboardInterrupt:
        pass
    finally:
        led_driver.cleanup()
    logger.info("Finished!")    

参考までに上記画面のpythonアプリケーションのソースを下記GitHubで公開しています。

気象データ表示板の制御プログラム (Pythonソースコード)
Github@pipito-yukio/home_weather_sensors/raspi_zero/bin/pigpio

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?