Dynamic LED

7セグメントLEDをマイコンにつないで表示するためには、ドットを含めると8本の制御線が必要になる。一個だけならば良いが、複数個になると個数x8本の制御線が必要になるので、そのままでは不可能。

良く使われているのがダイナミック点灯という方式で、これは7セグメントLEDを一個ずつ順番に点灯させ、高速に切り替えることで全ての桁が点灯しているように見せる、残像を利用した方式。この方式なら制御線は8本+LEDの個数だけで済む。

秋月電子通商で7セグメントLED4個をダイナミック点灯用に並べたモジュールが出ているので、これをRaspberry Piで試してみた。使用したのはカソードコモンの高輝度青色LEDタイプ

LEDのダイナミック点灯プログラムは高速なコンパイラ言語で作るのが普通で、Pythonのようなインタプリタ言語ではチラついたりして上手く行かないのでは無いか?と思ったのだが、結論から言うとそれほど問題なく使うことができた。
ただし他に重い処理が走っていない場合で、負荷が高くなるとチラつきが発生してしまう可能性は十分にある。

Raspberry PiとLEDモジュールの接続は、GPIOの左列でI2C用のポートを除いたGPIO4以降をLEDのセグメントA~Fの信号線、右列のGPIO14以降をLED1~4のセレクト用、GPIO7をDPの信号線として使用した。

7segWire

LEDセレクト用の信号線には47Ωの抵抗を入れてある。

プログラムは以下の通り。ダイナミック点灯処理はスレッドとして実装した。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import RPi.GPIO as GPIO
import threading
import time
import socket

ledport = (14, 15, 18, 23)
segport = (4, 17, 27, 22, 10, 9, 11, 7)
digit = ((1, 1, 1, 1, 1, 1, 0),     # 0
         (0, 1, 1, 0, 0, 0, 0),     # 1
         (1, 1, 0, 1, 1, 0, 1),     # 2
         (1, 1, 1, 1, 0, 0, 1),     # 3
         (0, 1, 1, 0, 0, 1, 1),     # 4
         (1, 0, 1, 1, 0, 1, 1),     # 5
         (1, 0, 1, 1, 1, 1, 1),     # 6
         (1, 1, 1, 0, 0, 0, 0),     # 7
         (1, 1, 1, 1, 1, 1, 1),     # 8
         (1, 1, 1, 1, 0, 1, 1),     # 9
         (0, 0, 0, 0, 0, 0, 0),     # Blank
         (0, 0, 0, 0, 0, 0, 1))     # Minus

class DynamicLed:
    def __init__(self):
        for n in range(8):
            GPIO.setup(segport[n], GPIO.OUT)
            GPIO.output(segport[n], False)
        for n in range(4):
            GPIO.setup(ledport[n], GPIO.OUT)
            GPIO.output(ledport[n], True)
    def set_digit(self, no, num):
        dot = num & 0x80
        num = num & 0x7F
        if(no == 0):
            GPIO.output(ledport[3], True)
        else:
            GPIO.output(ledport[no - 1], True)
        for n in range(7):
            GPIO.output(segport[n], digit[num][n])
        GPIO.output(segport[7], dot)
        GPIO.output(ledport[no], False)

rlock = threading.RLock()

class LedThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.ss = DynamicLed()
        self.dig = [0, 0, 0, 0]
        self.running = True
    def run(self):
        while self.running:
            rlock.acquire()
            for n in range(0, 4):
                self.ss.set_digit(n, self.dig[n])
                time.sleep(0.005)
            rlock.release()
    def stop(self):
        self.running = False
    def set(self, a, b, c, d):
        rlock.acquire()
        self.dig[0] = a
        self.dig[1] = b
        self.dig[2] = c
        self.dig[3] = d
        rlock.release()
    def set_num(self, num, width=0, dot=-1):
        str = '{0:>.{width}f}'.format(num, width=width)
        dp = 0;
        pos = 3;
        rlock.acquire()
        for n in range(len(str) - 1, -1, -1):
            if str[n] == '.':
                dp = 0x80
            elif str[n] == '-':
                self.dig[pos] = 11  # MINUS
                pos = pos - 1
            else:
                self.dig[pos] = int(str[n]) | dp
                dp = 0
                pos = pos - 1
            if pos < 0:
                break
        for n in range(0, pos + 1):
            self.dig[n] = 10    # BLANK
        if dot >= 0:
            self.dig[dot] = self.dig[dot] | 0x80
        rlock.release()

if __name__ == "__main__":
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    # get ip address
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.connect(('google.com', 0)) # dummy connect
    ip = sock.getsockname()[0]
    sock.close()
    array = ip.rsplit('.')
    # led thread start
    led = LedThread()
    led.start();
    try:
        while True:
            led.set_num(int(array[0]), dot=3)
            time.sleep(1)
            led.set_num(int(array[1]), dot=3)
            time.sleep(1)
            led.set_num(int(array[2]), dot=3)
            time.sleep(1)
            led.set_num(int(array[3]))
            time.sleep(1)
    except KeyboardInterrupt:
        print '\nbreak'
    led.stop()
    led.join()
    GPIO.cleanup()

LEDに表示させる適当なデータが思い付かなかったので、Raspberry Pi自身のIPアドレスを取得して4回に分けて表示させるようにしてみた。実行すると以下のように表示される。

7segip

数字4桁だけでは表示できるデータ量が少ないので用途が限られるが、バックライト付きLCDよりも消費電力が少なく、離れた場所からでも目立つという利点がある。

桁数がこれ以上多くなるとRaspberry PiのGPIOで直接制御するのは難しくなるが、その場合はデコーダICを使うと、少ない制御線で更に多くのLEDをダイナミック点灯させる事が可能になる。
ただし、その場合はタイミングがまた変わってくるので、注意が必要だ。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中