본문 바로가기
로보틱스/라즈베리파이

4-Digit 디스플레이 연결하기 [라즈베리파이(Raspberry Pi)]

by J-Build 2020. 9. 10.

오늘 포스팅에선 라즈베리파이에 4-Digit 디스플레이(Display)를 연결을 해보고 파이썬 프로그램으로 시간을 표시해 보도록 할께요.

 

제가 사용할 4-Digit 디스플레이는 seeedstudio의 Grove 4-Digit Display입니다. 

준비물

  • 최신 OS가 설치된 라즈베리파이 (설치 과정은 이 글을 참고 하세요)
  • 브레드 보드(빵판)
  • 점퍼 케이블
  • 4-Digit 디스플레이 

준비물이 세팅이 되었다면 라즈베리파이에 아래처럼 점퍼 케이블을 연결해주세요. 

 

아래 핀 번호로 다시 살펴보면 빨간선(전원)은 2번, 검은선(그라운드)는 6번, 흰선은 33번 노란선은 32번 핀에 연결해 주었습니다. 

 

그리고 브레드 보드를 사용해서 연결을 해줍니다. 디스플레이에서 직접 같은 색깔끼리 연결해주어도 무방합니다. 저는 연결의 편의성을 위해서 브레드 보드를 사용했습니다. 

 

파이썬 라이브러리 설치 

라즈베리파이에서 파이썬 프로그램으로 GPIO 제어를 위해서 RPi.GPIO 라이브러리를 설치하겠습니다. 라즈베리파이를 켜고 터미널을 열어주세요. 

 

저는 파이썬 3.7을 사용하고 있고 독립적으로 라이브러리 관리를 위해서 vitualenv 툴을 사용하고 있습니다. 라이브러리의 버전이 꼬여버리는것을 방지하기 위해서 저는 virtualenv를 사용하는것을 추천드립니다. 그럼 먼저 virtualenv를 설치해 볼께요. (virtualenv를 사용하지 않아도 무방합니다. 설치를 원하지 않으시면 pip를 사용해서 RPi.GPIO를 설치하는 곳부터 읽으시면 됩니다)

pi@raspberrypi:~ $ sudo pip install virtualenv

 

설치가 완료되었으면 파이썬코드를 저장할 폴더를 만들어주세요. 저는 저는 Projects라는 폴더를 만들고 그 안에 gpio-control이라는 폴더를 만들었어요. 

pi@raspberrypi:~ $ mkdir -p ~/Projects/gpio-control

 

Projects 폴더로 이동후 virtualenv로 python3 개발환경을 하나 만들께요. 

pi@raspberrypi:~ $ cd ~/Projects
pi@raspberrypi:~/Projects $ virtualenv venv-py3 -p python3

 

이제 방금 만들 python3 virtualenv 환경을 로드할께요. 그럼 쉘 앞쪽에 방금 위에서 만든 venv-py3 환경 이름이 아래처럼 추가가 됩니다. 그리고 이 환경에 GPIO 제어에 필요한 라이브러리를 설치해 줄께요. 

pi@raspberrypi:~/Projects $ source venv-py3/bin/activate
(venv-py3) pi@raspberrypi:~/Projects $ pip install RPi.GPIO

 

그럼 실제 프로젝트 폴더인 gpio-control 폴더로 이동합니다. 

(venv-py3) pi@raspberrypi:~/Projects $ cd gpio-control
(venv-py3) pi@raspberrypi:Projects/gpio-control $

 

그리고 digit.py 파일을 만들고 아래 내용을 입력시켜 주세요. 

import sys
import time
import RPi.GPIO

__all__ = ['GPIO']

RPi.GPIO.setwarnings(False)
RPi.GPIO.setmode(RPi.GPIO.BCM)


class GPIO(object):
    OUT = RPi.GPIO.OUT
    IN = RPi.GPIO.IN
    
    def __init__(self, pin, direction=None):
        self.pin = pin
        if direction is not None:
            self.dir(direction)

        self._event_handle = None

    def dir(self, direction):
        RPi.GPIO.setup(self.pin, direction)

    def write(self, output):
        RPi.GPIO.output(self.pin, output)

    def read(self):
        return RPi.GPIO.input(self.pin)

    def _on_event(self, pin):
        value = self.read()
        if self._event_handle:
            self._event_handle(pin, value)

    @property
    def on_event(self):
        return self._event_handle

    @on_event.setter
    def on_event(self, handle):
        if not callable(handle):
            return

        if self._event_handle is None:
            RPi.GPIO.add_event_detect(self.pin, RPi.GPIO.BOTH, self._on_event)

        self._event_handle = handle
 
 
charmap = {
    '0': 0x3f,
    '1': 0x06,
    '2': 0x5b,
    '3': 0x4f,
    '4': 0x66,
    '5': 0x6d,
    '6': 0x7d,
    '7': 0x07,
    '8': 0x7f,
    '9': 0x6f,
    'A': 0x77,
    'B': 0x7f,
    'b': 0x7C,
    'C': 0x39,
    'c': 0x58,
    'D': 0x3f,
    'd': 0x5E,
    'E': 0x79,
    'F': 0x71,
    'G': 0x7d,
    'H': 0x76,
    'h': 0x74,
    'I': 0x06,
    'J': 0x1f,
    'K': 0x76,
    'L': 0x38,
    'l': 0x06,
    'n': 0x54,
    'O': 0x3f,
    'o': 0x5c,
    'P': 0x73,
    'r': 0x50,
    'S': 0x6d,
    'U': 0x3e,
    'V': 0x3e,
    'Y': 0x66,
    'Z': 0x5b,
    '-': 0x40,
    '_': 0x08,
    ' ': 0x00
}
 
ADDR_AUTO = 0x40
ADDR_FIXED = 0x44
STARTADDR = 0xC0
BRIGHT_DARKEST = 0
BRIGHT_DEFAULT = 2
BRIGHT_HIGHEST = 7
 
 
class Grove4DigitDisplay(object):
    colon_index = 1
 
    def __init__(self, clk, dio, brightness=BRIGHT_DEFAULT):
        self.brightness = brightness
 
        self.clk = GPIO(clk, direction=GPIO.OUT)
        self.dio = GPIO(dio, direction=GPIO.OUT)
        self.data = [0] * 4
        self.show_colon = False
 
    def clear(self):
        self.show_colon = False
        self.data = [0] * 4
        self._show()
 
    def show(self, data):
        if type(data) is str:
            for i, c in enumerate(data):
                if c in charmap:
                    self.data[i] = charmap[c]
                else:
                    self.data[i] = 0
                if i == self.colon_index and self.show_colon:
                    self.data[i] |= 0x80
                if i == 3:
                    break
        elif type(data) is int:
            self.data = [0, 0, 0, charmap['0']]
            if data < 0:
                negative = True
                data = -data
            else:
                negative = False
            index = 3
            while data != 0:
                self.data[index] = charmap[str(data % 10)]
                index -= 1
                if index < 0:
                    break
                data = int(data / 10)
 
            if negative:
                if index >= 0:
                    self.data[index] = charmap['-']
                else:
                    self.data = charmap['_'] + [charmap['9']] * 3
        else:
            raise ValueError('Not support {}'.format(type(data)))
        self._show()
 
    def _show(self):
        with self:
            self._transfer(ADDR_AUTO)
 
        with self:
            self._transfer(STARTADDR)
            for i in range(4):
                self._transfer(self.data[i])
 
        with self:
            self._transfer(0x88 + self.brightness)
 
    def update(self, index, value):
        if index < 0 or index > 4:
            return
 
        if value in charmap:
            self.data[index] = charmap[value]
        else:
            self.data[index] = 0
 
        if index == self.colon_index and self.show_colon:
            self.data[index] |= 0x80
 
        with self:
            self._transfer(ADDR_FIXED)
 
        with self:
            self._transfer(STARTADDR | index)
            self._transfer(self.data[index])
 
        with self:
            self._transfer(0x88 + self.brightness)
 
 
    def set_brightness(self, brightness):
        if brightness > 7:
            brightness = 7
 
        self.brightness = brightness
        self._show()
 
    def set_colon(self, enable):
        self.show_colon = enable
        if self.show_colon:
            self.data[self.colon_index] |= 0x80
        else:
            self.data[self.colon_index] &= 0x7F
        self._show()
 
    def _transfer(self, data):
        for _ in range(8):
            self.clk.write(0)
            if data & 0x01:
                self.dio.write(1)
            else:
                self.dio.write(0)
            data >>= 1
            time.sleep(0.000001)
            self.clk.write(1)
            time.sleep(0.000001)
 
        self.clk.write(0)
        self.dio.write(1)
        self.clk.write(1)
        self.dio.dir(GPIO.IN)
 
        while self.dio.read():
            time.sleep(0.001)
            if self.dio.read():
                self.dio.dir(GPIO.OUT)
                self.dio.write(0)
                self.dio.dir(GPIO.IN)
        self.dio.dir(GPIO.OUT)
 
    def _start(self):
        self.clk.write(1)
        self.dio.write(1)
        self.dio.write(0)
        self.clk.write(0)
 
    def _stop(self):
        self.clk.write(0)
        self.dio.write(0)
        self.clk.write(1)
        self.dio.write(1)
 
    def __enter__(self):
        self._start()
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        self._stop()
 
 
Grove = Grove4DigitDisplay
 
 
def main():
    if len(sys.argv) < 3:
        print('Usage: {} clk dio'.format(sys.argv[0]))
        sys.exit(1)
 
    display = Grove4DigitDisplay(int(sys.argv[1]), int(sys.argv[2]))
 
    count = 0
    while True:
        t = time.strftime("%H%M", time.localtime(time.time()))
        display.show(t)
        display.set_colon(count & 1)
        count += 1
        time.sleep(1)
 
 
if __name__ == '__main__':
    main()

 

프로그램 실행

이제 프로그램을 실행시켜 볼께요. 

(venv-py3) pi@raspberrypi:Projects/gpio-control $ python digit.py 12 13

 

아래처럼 시간이 디스플레이에 잘 표시되고 있습니다. 

 

 

터미널에서 Ctrl C 를 눌러서 프로그램을 빠져나올 수 있습니다. 

 

그럼 즐파이 하세요~!! 

 

댓글