본문 바로가기

전자공학을 즐겁게/누구나 취미전자공학

7-Segment LED 표시하기

728x90
반응형

 

7-세그먼트 LED (7-segment LED)

아무리 전자 전기에 무관심한 사람이라고 하더라도 주위에 위의 사진과 같은 장치에 숫자가 표시되는 것은 많이 보았을 것입니다. 흔하게는 전자시계에 많이 나타나지요. 각각의 구분된 구간이 따로 불이 켜지는데, 이를 조합하여 숫자의 형상을 만들어 냅니다. 각각의 구분된 구간을 세그먼트(segment)라고 부르고, 숫자를 표시하기 위하여 7개의 세그먼트를 가지다고 하여 7-세그먼트(7-segment)라고 하는 장치입니다. 각각의 세그먼트가 각각 하나의 LED이기 때문에 7-세그먼트(7-segment) LED라고 부릅니다. 물론 소수점까지 표시하면 8개의 LED이지만, 숫자를 표시하는 부분만 따져서 7-세그먼트 LED라고 하지요.

 

7-세그먼트 LED 디코딩

각각의 7개 세그먼트는 위치에 따라 A부터 G까지 이름이 붙습니다.

숫자를 표기할 때, 어느 세그먼트를 켜느냐 따라서 다른 숫자, 즉 정보가 표시되는 것입니다. 예를 들어, 숫자 2라는 정보를 표시하고자 할 때에는, 위의 그림처럼 세그먼트 A, B, D, E, G를 켜고, 나머지는 끄게 됩니다. 이처럼 특정 정보, 여기에서는 숫자를 다른 형태, 여기에서는 켜는 세그먼트에 대한 정보로 바꾸는 것을 디코딩(decoding)한다고 합니다.

위의 그림에서 각 숫자의 디코딩에 대한 진리표(truth table)를 제시하였습니다.

 

7-세그먼트 LED의 구조. 그림: KOMI G-1056K 데이터시트 발췌

7-세그먼트 LED에서 각각의 세그먼트는 하나의 LED입니다. 소수점을 포함하면 8개의 LED가 하나의 소자를 구성합니다.

7-세그먼트 LED는 모두 공통 단자라는 것을 갖습니다. 8개의 LED가 모두 연결되는 단자입니다. LED의 캐소드(cathode) 또는 음극(-)이 공통으로 연결된 제품을 캐소드 공통(common cathode)라고 부르고, 애노드(anode) 또는 양극(+)이 공통으로 연결이 되어 있으면 애노드 공통(common anode)라고 부릅니다. 그리고, 나머지 단자들은 각각의 세그먼트에 연결이 됩니다. 7-세그먼트 LED 제품마다 어느 물리적인 단자가 어느 단자인지 다를 수 있습니다. 물리적인 단자의 위치는 각 제품의 데이터시트를 반드시 참조하세요. 하지만, 위의 그림에 표시된 제가 사용한 제품의 단자 배치, 또는 핀 번호는 우리나라에서 흔히 쉽게 구하는 제품들은 거의 같을 것입니다.

LED를 켜기 위해서는 LED를 정방향 바이어스로 만들어서 전류를 흐르게 하면 됩니다. 물론 정방향 바이어스 때의 정방향 전압은 데이터 시트 꼭 확인하세요. 제가 사용한 제품은 G-1056K라는 초록색으로 표시되는 제품이고, 정방향 전압 $V_F$는 2.25V입니다. 

캐소드 공통 제품인 경우에는 공통 단자는 음(minus)이 됩니다. 그리고, 각 세그먼트에 해당하는 단자를 양(plus)으로 연결하면 해당 세그먼트가 정방향 바이어스가 되니 켜지게 됩니다. 반대로 애노드 공통 제품인 경우에는 공통 단자를 양(plus)으로, 각 세그먼트에 해당하는 단자를 음(minus)으로 하면 켜집니다. 

 

숫자 2를 표시하도록 하기 위하여 전원으로 바이어스를 만들어 보았습니다.

제가 가진 캐소드 공통 7-세그먼트 LED에 숫자 2를 표시하기 위하여 바이어스 해 보았습니다. 디코딩 진리표에 나와 있는 것처럼 세그먼트 A, B, D, E, G를 정방향 바이어스해 주고, 나머지는 역방향 바이어스 또는 정방향 바이어스 되지 않도록 하면 되겠지요. 위의 그림에 있는 회로도에서 공통 단자는 GND, 즉 0V로 연결하고, 정방향 바이어스 되어야 하는 세그먼트는 VCC로 연결하고, 나머지 세그먼트는 GND로 연결하였습니다. 1kΩ의 저항은 전류 제한을 위해서 사용한 것입니다.

 

숫자 2가 표시될 때의 등가 회로

앞서 숫자 2를 표시하기 위한 연결을 등가 회로로 그려 보면 위의 그림처럼 됩니다. 세그먼트 A, B, D, E, G만 정방향 바이어스 되어 있는 것을 알아볼 수 있겠지요?

 

그러면, 7-세그먼트 LED에 숫자를 표시하기 위해서는 전원에 전선으로 연결을 항상 이렇게 바꿔 연결해야 할까요? 아니죠. 표시하고자 하는 정보에 맞게 진리표에 따라서 각 세그먼트에 전원을 주기도 하고 끊기도 하고 하면 내가 표시하고자 하는 정보가 표시되는 것입니다. MCU나 라즈베리 파이와 같은 임베디드 컴퓨터에서 이련 역할을 GPIO를 사용해서 할 수가 있습니다. GPIO의 Drive Strenth에 따라 GPIO 출력 자체가 전원이 되기도 하고, GPIO 출력을 스위치 신호로 사용하여 FET와 같은 소자를 켜거나 끄기도 합니다.

 

라즈베리 파이의 GPIO를 사용해서 표시해 보도록 합시다. 전류 공급과 함께 전압이 조금 떨어진다고 하더라도 동작에 별 지장이 없으니 그대로 연결하도록 하겠습니다.

7-세그먼트 LED 연결 회로

7-세그먼트 LED와 저항으로 회로를 만들고, 8개의 GPIO로 연결을 합니다. 라즈베리 파이의 40핀 헤더에서 각 GPIO의 배치는 여기에 있습니다. 위의 회로도에 어느 GPIO로 연결을 했는지 표시는 해 두었습니다만, 여기에 얽매일 필요는 없습니다. 편한 곳에 연결하고 나중에 프로그램을 수정해도 되니 너무 여기에 있는 핀 번호에 집착하지 마세요. 

 

모두 연결했으면 시험을 해 봅시다. 먼저 라즈베리 파이에서 파이썬을 대화형 모드로 실행을 합니다.

 

먼저 RPi.GPIO 모듈을 import 하고, 모드를 GPIO.BCM으로 하여 GPIO 번호를 사용하겠다고 선언합니다. GPIO.BOARD로 사용해도 되겠지만, 저는 그냥 GPIO 번호로 사용하는 것이 덜 헷갈리네요.

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

 

사용할 GPIO를 모두 출력으로 설정합니다. 

GPIO.setup(2, GPIO.OUT) 
GPIO.setup(3, GPIO.OUT) 
GPIO.setup(14, GPIO.OUT) 
GPIO.setup(15, GPIO.OUT) 
GPIO.setup(17, GPIO.OUT) 
GPIO.setup(27, GPIO.OUT) 
GPIO.setup(23, GPIO.OUT) 
GPIO.setup(24, GPIO.OUT)

 

이제 각각의 출력을 하나씩 켜 보세요. 

GPIO.output(2, GPIO.HIGH)
GPIO.output(3, GPIO.HIGH)
GPIO.output(14, GPIO.HIGH)
GPIO.output(15, GPIO.HIGH)
GPIO.output(17, GPIO.HIGH)
GPIO.output(27, GPIO.HIGH)
GPIO.output(23, GPIO.HIGH)
GPIO.output(24, GPIO.HIGH)

 

한 줄씩 실행할 때마다 세그먼트가 하나씩 켜지는 것이 보일 것입니다. 모두 실행하고 나면 다음 사진처럼 표시될 거예요. 

라즈베리 파이에 연결된 모든 GPIO를 HIGH로 하여 모든 세그먼트가 켜진 모습

 

이제는 다시 하나씩 꺼 보겠습니다. 

GPIO.output(3, GPIO.LOW)
GPIO.output(2, GPIO.LOW)
GPIO.output(14, GPIO.LOW)
GPIO.output(15, GPIO.LOW)
GPIO.output(17, GPIO.LOW)
GPIO.output(27, GPIO.LOW)
GPIO.output(23, GPIO.LOW)
GPIO.output(24, GPIO.LOW)

켜진 반대 순서대로 꺼지지요? 이것이 라즈베리 파이의 GPIO를 이용해서 7-세그먼트 LED를 제어하는 기본적인 개념입니다.

그럼 실제로 숫자를 디코딩하여 바로 7-세그먼트 LED를 표시하는 코드를 만들어 봅시다.

 

각각의 세그먼트가 하나의 LED라고 했으니, 전에 만들었던 LED 클래스도 재활용해 봅시다. 이 샘플 코드가 포함된 repository에서 이 디렉터리의 상위의 하위, 즉 이 디렉터리와 같은 레벨에 전에 만들었던 클래스가 존재하니 그것을 import 하기 위하여 모듈을 찾는 디렉터리에 상위 디렉터리를 포함합니다. 

import sys
sys.path.append('..')

 

이렇게 하면 <디렉터리 이름>.<파일 이름>을 이용해서 현재 디렉터리와 같은 레벨에 있는 디렉터리, 즉 ../<디렉터리 이름> 에 해당하는 디렉터리의 파일을 import 할 수 있게 됩니다. 이렇게요.

from led_control.led_toggle import *

 

SEVEN_SEG_LED 클래스를 구현하였습니다. 아래는 help(SEVEN_SEG_LED) 출력의 주요 부분입니다..

class SEVEN_SEG_LED(builtins.object)
 |  SEVEN_SEG_LED(pins: tuple, init_val=None, isCC=True)
 |  
 |  Class to represent 7-segment LED
 |  
 |  pins is a tuple which has GPIO numbers for each segment - A to G and DP in turns.
 |  init_val is a value to present after initilization.
 |  isCC is to indicate the 7-segment in use is Common-Carhod if True or Comman-Anode oterwise.
 |  
 |  Methods defined here:
 |  
 |  __init__(self, pins: tuple, init_val=None, isCC=True)
 |      Initialize a 7-segment LED.
 |  
 |  update(self, val=None, dot=False)
 |      Update the display with a givein init_val.
 |      
 |      init_val is to be a number ranged 0~9, A~F in case of the hexa-decimal number or can be its string representation.
 |

 

여기에서 구현한 SEVEN_SEG_LED 클래스는 아래처럼 사용이 되는데, 각 인자는 각 세그먼트와 연결된 GPIO 번호입니다. update() method를 사용하여 실제로 숫자를 표시합니다. 아래 예는 2를 표시하기 위한 것이죠. 

a = SEVEN_SEG_LED((3, 2, 15, 23, 24, 17, 27, 14))

a.update(2)

 

SEVEN_SEG_LED의 초기화는 각 GPIO 번호로부터 각각의 LED 인스턴스를 생성하여 list를 만드는 것으로 시작했습니다. list의 각 아이템으로 직접 LED를 끄고 켤 수 있게요.  

def __init__(self, pins:tuple, init_val=None, isCC=True):
    '''
    Initialize a 7-segment LED.
    '''

    self.led_array = list()

    for pin in pins:
        self.led_array.append(LED(pin, 
                                 POLARITY.ACTIVE_HIGH if isCC == True else POLARITY.ACTIVE_LOW))

    self.update(init_val)

 

표시를 위한 update() method에서는 진리표를 dict를 사용해서 Look Up 테이블을 만들었습니다. 그리고는 입력에 해당하는 숫자를 찾아서 각 GPIO를 그대로 끄거나 켜게 만들었습니다. 마지막 LED는 표시하는 숫자와는 독립적이라 이 이후에 따로 처리하였습니다. 그래서 index가 7인 경우에는 별도 처리 없이 루프를 빠져나가게 만들어 놓았습니다. 

def update(self, val=None, dot=False):
    '''
    Update the display with a givein init_val.

    init_val is to be a number ranged 0~9, A~F in case of the hexa-decimal number or can be its string representation.
    '''

    # 'Digit': (A, B, C, D, E, F, G)
    look_up_table  = {  '0': (True, True, True, True, True, True, False),
                        '1': (False, True, True, False, False, False, False),
                        '2': (True, True, False, True, True, False, True),
                        '3': (True, True, True, True, False, False, True),
                        '4': (False, True, True, False, False, True, True),
                        '5': (True, False, True, True, False, True, True),
                        '6': (True, False, True, True, True, True, True),
                        '7': (True, True, True, False, False, False, False),
                        '8': (True, True, True, True, True, True, True),
                        '9': (True, True, True, True, False, True, True),
                        'a': (False, False, True, True, True, False, True),
                        'A': (False, False, True, True, True, False, True),
                        'b': (False, False, True, True, True, True, True),
                        'B': (False, False, True, True, True, True, True),
                        'c': (False, False, False, True, True, False, True),
                        'C': (False, False, False, True, True, False, True),
                        'd': (False, True, True, True, True, False, True),
                        'D': (False, True, True, True, True, False, True),
                        'e': (True, True, False, True, True, True, True),
                        'E': (True, True, False, True, True, True, True),
                        'f': (True, False, False, False, True, True, True),
                        'F': (True, False, False, False, True, True, True) }

    if type(val) != str:
        val = str(val) 


    if val not in look_up_table:
        for each_led in self.led_array:
            each_led.off()
    else:
        for each_led in self.led_array:
            if self.led_array.index(each_led) == 7: 
                break
            each_led.on() if look_up_table[val][self.led_array.index(each_led)] == True else each_led.off()

    self.led_array[-1].on() if dot==True else self.led_array[-1].off()

 

주석이 포함된 전체 코드는 GitHub에서 확인하세요.

https://github.com/sangyoungn/play_with_RPi/tree/main/seven_seg_led

 

GitHub - sangyoungn/play_with_RPi: Example Codes for Raspberry Pi

Example Codes for Raspberry Pi. Contribute to sangyoungn/play_with_RPi development by creating an account on GitHub.

github.com

 

실행은 repository의 README.md에도 있지만, seven_seg_led.py를 python을 이용해서 실행하면 됩니다. 

python seven_seg_led.py

 

다음 동영상처람 동작할 것입니다.

 

 

컴퓨터에서 프로그램을 사용하여 7-세그먼트 LED를 디코딩해서 표시해 보았습니다. 요즘은 임베디드 컴퓨팅이 발달해서 예전엔 모두 하드웨어를 사용했던 것을 간단하게 GPIO와 소프트웨어로 문제를 풀어볼 수가 있네요. 다음에 기회가 되면 좀 더 하드웨어적인 방법도 살펴 보도록 하죠. 

728x90
반응형