본문 바로가기

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

라즈베리 파이(Raspberry Pi)에서 RPi.GPIO Python module을 사용한 GPIO 출력 제어, 그리고 Drive Strength에 대하여

728x90
반응형

라즈베리 파이는 교육용으로 개발되었다고는 하지만, 대량 생산이 아닌 경우에는 여러 분야에서 외부 하드웨어 제어를 위해서 사용되기도 합니다. 개발자에게는 별도로 컴퓨팅 하드웨어를 개발하는 부담을 줄이고, 필요한 최소한의 하드웨어와 소프트웨어만으로 어플리케이션을 완성하게 하는 것이지요. 특히 라즈베리 파이에서 외부 하드웨어를 제어하고자 할 때, GPIO(General Purpose Input/Output; 범용 입출력)를 사용하여 간단한 외부 하드웨어를 제어합니다. GPIO에 대한 상세한 내용은 Wikipedia에 잘 나와 있으니 참조하시고, 우리는 라즈베리 파이의 GPIO, 나아가서는 다른 여러 MCU의 GPIO를 사용하는 데에 집중하도록 하겠습니다. 

☞ https://en.wikipedia.org/wiki/General-purpose_input/output

 

General-purpose input/output - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search User-controllable digital signal pin on an integrated circuit A general-purpose input/output (GPIO) is an uncommitted digital signal pin on an integrated circuit or electronic circuit

en.wikipedia.org

(링크: Wikipedia.org의  General-purpose input/output 영문판)

 

GPIO는 디지털 신호입니다. GPIO를 출력으로 사용하는 경우, 2가지 상태 중의 하나를 갖습니다. 어떤 경우에는 On과 Off라고 말하고, 어떤 경우에는 High와 Low, 또 어떤 경우에는 1과 0이라고 말합니다. 표현하는 방법이 다를 뿐, 모두 같은 말입니다. 중요한 것은 디지털 신호를 나타내는 하나의 전극으로 2가지 중 하나의 상태를 갖으며, 이 상태들은 전압으로써 표현이 된다라고 생각하면 됩니다. 이것은 라즈베리 파이 뿐만 아니라 어떠한 MCU에도 공통적인 사항입니다.

 

라즈베리 파이 컴퓨터에는 40핀의 헤더(Header)를 통하여 이 GPIO에 연결을 할 수 있습니다. 라즈베리 파이를 보면 윗부분에 검은색 몸체에 노란색 단자가 2열로 배치되어 있는 부품이 있는데, 이것이 GPIO에 연결되는 헤더입니다. 이 헤더의 40개의 핀(Pin)은 1번부터 40번까지 번호가 붙여져 있습니다. 이 각각의 핀에는 라즈베리 파이의 CPU로 쓰이는 Broadcom社의 SoC의 GPIO에도 연결이 되어 있고, 해당 GPIO는 "GPIO 몇 번"과 같이 이름이 붙여져 있습니다 - 예) GPIO 2.

원본출처: Raspberry Pi Documentation (https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header)

우리가 하려는 것은 이 GPIO의 출력을 제어해 보는 것입니다. 앞서 언급된 것처럼 GPIO의 출력은 2개의 상태 중 1개를 가집니다. 라즈베리 파이의 GPIO는 3.3V 또는 0V의 2개의 상태를 가집니다. 3.3V인 상태를 High, On, 1 등과 같이 부르고, 0V인 상태를 Low, Off, 0 등과 같이 부릅니다. 출력을 제어해서 상태가 3.3V가 되도록 하거나, 0V가 되도록 하거나 하는 것이죠.

 

해볼 수 있는 가장 간단한 실험은 LED 회로를 GPIO에 연결하고, LED를 켜고 끄는 동작을 해 보는 것입니다. LED의 동작에 대해서는 예전 포스트를 참조하세요. 

  1. LED의 이해
  2. LED를 켜라

라즈베리 파이로부터 2개의 GPIO를 브레드 보드에 연결하여 LED 점등 회로를 구성해 봅니다. 모든 회로에서 마찬가지이지만 0V를 나타내는 GND를 서로 연결이 되어야 합니다. 여기에 사용된 빨간색 LED는 $V_F$, 즉 정방향 전압이 약 2V 정도입니다. $R_1$과 $R_2$는 우선 100Ω으로 하죠.

오른쪽 위에 있는 회로도 대로 회로를 구성해 봅니다. GPIO 2와 GPIO 3의 상태에 따라 LED가 켜지거나 꺼지겠죠.

 

라즈베리 파이에서 GPIO를 제어하는 방법으로는 Python을 사용하는 것이 가장 간편합니다. Interactive mode가 있기 때문에 명령어 하나 하나로 확인이 가능하기도 하고요. 우선 Raspberry Pi에서 Python Interactive mode를 시작합니다. 라즈베리 파이는 모니터와 키보드/마우스를 라즈베리 파이에 직접 연결하여 사용하여도 좋고, VNC 연결이나 SSH 접속을 사용해도 좋습니다. 라즈베리 파이가 아직 셋업 되지 않았다면 이 포스트를 참조해서 라즈베리 파이를 셋업 하도록 하세요. 

 

라즈베리 파이에서 터미널을 실행하고, 터미널에서 Python Interactive mode를 시작합니다. 여러 가지 사용 가능한 GUI 도구들이 있겠지만, 이 방법이 VNC나 SSH 접속을 사용하든, 직접 라즈베리 파이에서 작업하든 공통적으로 사용할 수 있는 방법입니다.

Python은 라즈베리 파이에 기본적으로 설치가 됩니다.

LED 회로를 정상적으로 구성했다면 다음 명령어를 Interactive mode에서 하나하나 실행하면서 동작을 확인해 보세요. 

 

우선은 Module을 준비합니다. GPIO를 제어하기 위해서는 RPi.GPIO Module을 import 해야 합니다. 이 모듈은 라즈베리 파이에는 기본적으로 포함되는 모듈이기 때문에 별도로 설치할 필요는 없습니다. 

import RPi.GPIO as GPIO

RPi.GPIO module을 GPIO라는 이름으로 import 합니다. 

 

GPIO Numbering을 어느 기준으로 할 것인지를 정합니다. 여기에는 BCM 혹은 BOARD로 지정이 가능합니다. 먼저 BOARD는 40핀 헤더에서의 핀 번호로 GPIO를 구분하겠다는 의미입니다. BCM은 그 핀에 할당된 신호의 이름에서 GPIO ?의 ?에 의해서 구분한다는 의미로, 예를 들면 40핀 헤더의 3번 핀에 할당되어 있는 신호는 GPIO 2인데, 이것을 2로 사용하는 것을 의미합니다.

GPIO.setmode(GPIO.BCM)

여기서는 GPIO 번호를 사용하여 GPIO를 구분합니다.

 

GPIO를 출력으로 사용하겠다고, 설정합니다. GPIO 2 (3번 핀), GPIO 3 (5번 핀)을 출력 용도로 사용합니다.

GPIO.setup(2, GPIO.OUT)
GPIO.setup(3, GPIO.OUT)

 

2개의 LED를 먼저 꺼 보겠습니다. 

GPIO.output(2, GPIO.LOW)
GPIO.output(3, GPIO.LOW)

2개의 LED는 이 상태에서 모두 꺼진 상태가 되어야 합니다. 

 

다음 명령으로 LED의 변화를 살펴보세요. 

GPIO.output(2, GPIO.HIGH)
GPIO.output(3, GPIO.HIGH)

 

2개의 LED가 모두 켜졌습니다.

첫 번째 명령에서 하나의 LED가, 두 번째 명령에서 그다음 LED가 켜질 것입니다. 

2개 중에 하나만 꺼 볼까요?

GPIO.output(3, GPIO.LOW)

하나만 남기고 꺼지지요?

이제는 원하는 대로 LED를 켰다가 껐다가 해 보세요. 만약 원하는 대로 동작하지 않는다면, 선 연결을 다시 한번 확인해 보세요.

 

여기에서 주의할 것은 BCM, BOARD, OUT, LOW, HIGH 등이 모두 RPi.GPIO 모듈에 정의되어 있는 것이기 때문에 사용할 때 모듈 이름을 써 주어야 한다는 것입니다. 여기에서는 GPIO라는 이름으로 import 했으니 GPIO.BCM 이런 식으로요.

 

만약 처음부터 다시 해 보고자 한다면, 다음 명령을 실행한 이후에 하여야 합니다. 모든 설정된 내용을 처음 값으로 돌린다는 의미입니다. 처음부터 다시 설정하여야 동작합니다. 

GPIO.cleanup()

 

이 실험은 GPIO에 3.3V 또는 0V의 출력을 함으로써, 저항 - LED로 구성된 회로에 전류가 흘러 LED를 켜고 끄는 것입니다. 3번 핀과 6번 핀(GPIO 2와 Ground) 사이, 5번 핀과 6번 핀(GPIO 3와 Ground) 사이의 전압을 2가지 중 하나로 조작하는 것입니다.

728x90

한 가지 더, Drive Strength에 대하여...

GPIO의 출력을 만드는 방법에 대하여 이야기를 하고 있습니다. 이제부터 이야기할 내용이 정말로 살펴보고자 했던 내용인데요, 바로 Drive Strength입니다. 우리말로 어떻게 해야 하는지 모르겠는데, 그냥 Drive Strength라고 하겠습니다. 

먼저 앞에서 하던 실험을 계속하죠.

GPIO 2의 LED를 켜지도록 해 보겠습니다. 

GPIO.output(2, GPIO.HIGH)

LED가 켜졌나요? 켜졌으면 GPIO 2와 Ground, 즉 3번 핀과 6번 핀 사이의 전압을 측정해 봅시다. R1 - LED의 양끝 전압을 측정하면 됩니다. 전압 측정하는 방법에 대한 내용에 대해서는 멀티미터에 대한 포스트 참조하세요. 

 

측정을 해 보신 분은 전압이 얼마가 측정이 되었나요? 제 경우엔 약 2.8V로 측정이 되었습니다.

2.8V? 3.3V 아니고? 라즈베리 파이 GPIO는 HIGH가 3.3V라면서? 3.3V 출력이라면서? 무엇인가 속은 느낌이 들죠?

이야기를 더 이어 가기 전에 한 가지 더 해 보죠. GPIO2에 LED 전류 제한 저항 $R_1$이 100Ω으로 되어 있죠? 이것을 1kΩ으로 바꾸어 봅시다. 보는 사람마다 다르게 느끼겠지만, LED는 조금 어두워졌을 것입니다. 그리고, 다시 같은 전압을 측정해 봅시다. 얼마인가요? 제 경우에는 약 3.1V가 측정되었습니다. 100Ω이었던 경우보다 조금 올랐네요. 

마지막으로 GPIO 2에 연결된 선을 완전히 끊고, GPIO 2 출력(40핀 헤더의 3번 핀)과 Ground(40핀 헤더의 6번 핀) 사이의 전압을 측정해 봅니다. 아마도 3.3V라고 생각되는 전압(조금씩 오차가 있을 테니까요.)이 측정될 것입니다. 

 

이것에 대한 설명이 Drive Strength입니다. 마이크로컨트롤러(Microcontroller)와 같은 반도체 소자들은 데이터시트(Datasheet)와 같은 문서에 어떤 형태로든 Drive Strenth에 대한 언급을 하고 있습니다. Drive Strength라고 하는 것은 특정 포트(Port)가 나머지 사양들을 모두 만족하는 상태에서 출력 또는 입력받을 수 있는 전류를 의미합니다. 무슨 말인지 모르겠다고요? 그럼 차근차근 살펴보도록 하겠습니다. 

라즈베리파이도 문서에 GPIO의 Drive Strength에 대하여 언급하고 있습니다. 

원본출처: Raspberry Pi Documentation (https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#general-purpose-io-gpio)

앞의 표는 라즈베리파이 문서에서 발췌한 라즈베리파이 4의 GPIO 특성을 나타낸 것입니다. 빨간색으로 표시한 $V_{OH}$를 눈여겨보세요. 아래 b에 대한 각주를 보면 Drive Strength가 4mA인 경우의 값이 라고 되어 있고, 이때 4mA가 흐르는 조건이라고 되어 있습니다. 그리고, HIGH에 대한 출력 전압이 최소 2.6V입니다. 즉, 4mA가 흐르는 조건이라면 2.6V 이상은 보장한다는 의미입니다. 무슨 소린지 더 어렵다고요?

Drive Strength를 4mA로 설정한다는 것에 대해서는 뒤에 살펴보고, Drive Strength가 4mA 일 때, 4mA를 흐르게 한다라는 것에 대하여 살펴보겠습니다. 여기에는 일전에 포스팅한 적이 있는 테브난의 등가 회로를 적용하여 생각해 볼 수 있습니다. LED를 켜거나 무엇인가 구동한다면 GPIO의 전압/전류도 전원으로 볼 수 있죠. 위에 이야기한 상황을 GPIO의 출력을 테브난의 등가 회로로 표현하여 그려 보도록 하겠습니다.

GPIO를 테브난의 등가회로로 표현하고, 전류가 흐르도록 했습니다.

$V$는 3.3V입니다. High 출력을 했으니까요. 테브난의 저항을 $R_S$라고 하고, $I$라는 전류를 흘렸습니다. GPIO의 특성을 나타낸 표에서는 $I=4mA$라고 했습니다. $R_S$는 얼마인지 언급하지 않았지만, 이 경우 출력은 아무리 낮아도 2.6V 이상이라고 규정하는 것입니다. $V=3.3V$인데, $V_{OH}\geq2.6V$라고 하는 것은 $R_S$에 의한 $V$의 전압 강하는 $0.7V$보다는 적다고 하는 있는 것이죠. 즉, $$V-V_{R_S}\geq2.6V$$$$V-IR_S\geq2.6V$$이라고 하는 것입니다. 우리가 $I=4mA$인 경우를 생각하고 있으니까, $I$ 대신 4mA, $V$ 대신 3.3V를 대입해서 생각한다면, $$R_S\leq175Ω$$와 같이 생각할 수 있겠습니다. 

다시 우리가 한 실험으로 돌아가서 전류 제한 저항을 1kΩ으로 바꾼 경우를 생각하면, $I$가 줄어드는 것이고, $R_S$에 의한 전압 강하가 낮아져서, $V_{OH}$가 높게 나타나는 것이죠. LED로의 연결을 완전히 끊은 경우는 $I=0mA$로 생각하면 됩니다. $V_{R_S}=0V$이므로, $V=V_{OH}$, 즉 3.3V를 그대로 볼 수 있었던 것이죠.

이것과 같은 방법으로 $V_{OL}$도 생각을 해 보세요. 

 

라즈베리 파이 GPIO의 Drive Strength는 8단계 설정이 가능합니다.

원본출처: Raspbery Pi Documentation (https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#gpio-pads)

라즈베리 파이 4의 경우에는 1~8mA까지, 그 이외의 모델들은 2~16mA까지 Drive Strength가 설정이 가능합니다. 위에서는 4mA의 Drive Strength에서 $V_{OH}$나 $V_{OL}$에 대한 사양을 언급한 것이고, Drive Strength가 더 낮게 설정되면 같은 전류가 출력될 때 더 낮은 전압이 나타나겠죠. Drive Strength가 더 높게 설정되면 더 높게 설정되면 더 높은 전압이 나타날 것입니다. 

 

우리는 여기에서 LED 정도를 켜고 있기 때문에 이런 전압 변화가 크게 중요하지 않을 수도 있습니다. 하지만, 이러한 출력 전압의 변화가 중요한 것은 이 출력이 또 다른 디지털 로직에 연결되었을 경우입니다. 위 GPIO 특성 표에서 보면 파란색으로 표시한 $V_{IH}$라는 특성이 있습니다. 이것은 입력을 받았을 때, High로 인지하는 전압을 나타내는 것입니다. 3.3V가 High라고 했지만, 정확히 3.3V라는 것은 있을 수가 없겠죠. 어디에서 어디 사이면 High 또는 1로 받아들일게라고 하는 약속입니다. 라즈베리파이 4에는 2.0V 이상으로 되어 있네요. High를 출력해서 라즈베리파이로 연결하는 경우에는 꼭 High의 전압이 이 범위에 드는지 확인하여야 합니다. 마찬가지로 $V_{IL}$은 Low 또는 0으로 인지하는 범위입니다. 다른 로직에 연결하는 경우에는 해당 로직의 $V_{IH}$와 $V_{IL}$을 꼭 확인하여야 하는 것이고요. 이 연결이 많은 전류를 흘려야 하는 경우에는 출력 쪽 Drive Strength에 따라 서로 약속한 전압을 못 맞출 수 있습니다. 이러한 경우에는 별도의 회로를 사용하여야 합니다. 이것에 대해서는 다음 기회에 또 알아보죠. 

 

하드웨어(Hardware)를 제어하는 코드(Code)를 작성하는 경우에는 내 코드가 하드웨어에 어떤 변화를 일으키는지를 잘 생각하고 미리 예상하여야 합니다. 단순히 코딩(Coding)만 할 줄 안다고 해서 잘할 수 있는 것은 아니죠. 하드웨어와 프로그램을 유기적으로 연결할 수 있는 사고가 필요합니다. 

 

여기까지 GPIO와 Drive Strength에 대하여 이야기하였습니다. 기왕 GPIO 제어하는 법을 알았으니, LED를 깜박이는 Python Code를 만들어 보죠.

# Import required modules
import RPi.GPIO as GPIO # RPi.GPIO module to contol GPIOs
from enum import Enum   # import Enum class to inherit and use enumumerators

class POLARITY(Enum):
    '''
    Enumerators for LED polarity
    ACTIVE_HIGH means LED is on when the state of GPIO is high and vice versa.
    '''
    ACTIVE_HIGH = 1
    ACTIVE_LOW = 0

class LED:
    '''
    Class for LED On/Off control
    '''
    def __init__(self, gpio, polarity=POLARITY.ACTIVE_HIGH):
        '''
        Initialize self. Specify gpio and polarity.
        The polarity is ACTIVE_HIGH by default.
        '''
        self.gpio = gpio
        self.polarity = polarity
        GPIO.setup(self.gpio, GPIO.OUT)
        self.off()
    def on(self):
        '''
        Turn on the LED
        '''
        GPIO.output(self.gpio, GPIO.HIGH if self.polarity == POLARITY.ACTIVE_HIGH else GPIO.LOW)
    def off(self):
        '''
        Turn off the LED
        '''
        GPIO.output(self.gpio, GPIO.LOW if self.polarity == POLARITY.ACTIVE_HIGH else GPIO.HIGH)

if __name__ == '__main__':
    # import time module for sleep to delay
    # Used only here so imported in this block
    import time
    
    GPIO.setmode(GPIO.BCM) # Specify the GPIO numbering mode.

    # Configure 2 LEDs
    led1 = LED(2)
    led2 = LED(3)

    # State flag to toggle LEDs
    on = False

    try:
        while(True):
            if (on):
                led1.on()
                led2.off()
                on = False # Invert the state
            else:
                led1.off()
                led2.on()
                on = True # Invert the state
            
            # Time delay for 1 sec
            time.sleep(1)
    except KeyboardInterrupt: # Ctrl+C will bering us here.
        GPIO.cleanup()
        exit(0)

여기에서는

  • RPi.GPIO module을 사용하는 방법
  • Python의 Class 개념
  • 여러가지 module을 import 하는 방법
  • time.sleep으로 지연을 만드는 방법

을 눈여겨 보도록 하세요. 

다음에 보이는 것처럼 동작하면 제대로 된 것입니다. 

이렇게 동작하면 정상적으로 된 것입니다.

이 코드는 GitHub에도 공유해 두도록 하겠습니다. 

https://github.com/sangyoungn/play_with_RPi/led_control

 

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

 

728x90
반응형