개발자/라즈베리파이4

RPi.GPIO 모듈 GPIO를 입력, 출력, PWM으로 사용할 때 알아야 할 것

지구빵집 2021. 8. 16. 10:53
반응형

 

RPi.GPIO 모듈 입력으로 사용할 때 알아야 할 것  

 

입력

 

프로그램에 GPIO 입력을 가져오는 방법에는 여러 가지가 있습니다. 첫 번째이자 가장 간단한 방법은 특정 시점에서 입력 값을 확인하는 것입니다. 이것을 '폴링'이라고 하며 프로그램이 잘못된 시간에 값을 읽는 경우 잠재적으로 입력을 놓칠 수 있습니다. 폴링은 루프에서 수행되며 잠재적으로 프로세서 집약적일 수 있습니다. GPIO 입력에 응답하는 다른 방법은 '인터럽트'(에지 감지)를 사용하는 것입니다. 에지는 HIGH에서 LOW(하강 에지) 또는 LOW에서 HIGH(상승 에지)로의 전환 이름입니다. 

 

풀업/풀다운 저항

 

입력 핀이 아무것도 연결되어 있지 않으면 '플로팅'됩니다. 즉, 버튼이나 스위치를 누를 때까지 어떤 것과도 연결되어 있지 않기 때문에 읽어들인 값은 정의되지 않습니다. 주전원 간섭을 수신한 결과 값이 많이 변경될 것입니다.

 

이 문제를 해결하기 위해 풀업 또는 풀다운 저항을 사용합니다. 이런 식으로 입력의 기본값을 설정할 수 있습니다. 하드웨어 및 소프트웨어를 사용하여 풀업/다운 저항을 가질 수 있습니다. 하드웨어에서 입력 채널과 3.3V(풀업) 또는 0V(풀다운) 사이에 10K 저항이 일반적으로 사용됩니다. RPi.GPIO 모듈을 사용하면 소프트웨어에서 이를 수행하도록 Broadcom SOC를 구성할 수 있습니다. 

 

GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  # or
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

 

(여기서 channel은 BOARD 또는 BCM과 같이 지정한 번호 체계를 기반으로 하는 채널 번호입니다.) 입력 테스트(폴링) 특정 시점에 입력의 스냅샷을 찍을 수 있습니다. 

 

if GPIO.input(channel):
    print('Input was HIGH')
else:
    print('Input was LOW')

 

루프에서 폴링하여 버튼 누름을 기다리려면: 

 

while GPIO.input(channel) == GPIO.LOW:
    time.sleep(0.01)  # wait 10 ms to give CPU chance to do other things

 

(버튼을 누르면 입력이 LOW에서 HIGH로 변경된다고 가정)

 

인터럽트 및 에지 감지

 

에지는 LOW에서 HIGH(상승 에지) 또는 HIGH에서 LOW(하강 에지)로의 전기 신호 상태의 변화입니다. 종종 우리는 값보다 입력 상태의 변화에 ​​더 관심이 있습니다. 이 상태 변경은 이벤트 입니다.

 

프로그램이 다른 일을 하는 동안 버튼 누름을 놓치지 않으려면 두 가지 방법이 있습니다.

 

  • wait_for_edge() 함수
  • event_detected() 함수
  • 에지가 감지될 때 실행되는 스레드된 콜백 함수

wait_for_edge() 함수

 

wait_for_edge() 함수는 에지가 감지될 때까지 프로그램 실행을 차단하도록 설계되었습니다. 즉, 버튼 누름을 기다리는 위의 예는 다음과 같이 다시 작성할 수 있습니다. 

 

GPIO.wait_for_edge(channel, GPIO.RISING)

 

GPIO.RISING, GPIO.FALLING 또는 GPIO.BOTH 유형의 가장자리를 감지할 수 있습니다. 이 방법의 장점은 무시할 수 있는 양의 CPU를 사용하므로 다른 작업을 위한 여유 공간이 충분하다는 것입니다. 특정 시간 동안만 기다리려면 timeout 매개변수를 사용할 수 있습니다. 

 

# wait for up to 5 seconds for a rising edge (timeout is in milliseconds)
channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
if channel is None:
    print('Timeout occurred')
else:
    print('Edge detected on channel', channel)

 

event_detected() 함수

 

event_detected() 함수는 다른 것들과 함께 루프에서 사용하도록 설계되었지만, 폴링과 달리 CPU가 다른 작업을 하는 동안 입력 상태의 변화를 놓치지 않을 것입니다. 이것은 메인 루프가 적시에 GUI 이벤트를 수신하고 응답하는 Pygame 또는 PyQt와 같은 것을 사용할 때 유용할 수 있습니다. 

 

GPIO.add_event_detect(channel, GPIO.RISING)  # add rising edge detection on a channel
do_something()
if GPIO.event_detected(channel):
    print('Button pressed')

 

GPIO.RISING, GPIO.FALLING 또는 GPIO.BOTH에 대한 이벤트를 감지할 수 있습니다.

 

스레드된 콜백

 

RPi.GPIO는 콜백 함수에 대한 두 번째 스레드를 실행합니다. 이는 콜백 함수가 에지에 대한 즉각적인 응답으로 메인 프로그램과 동시에 실행될 수 있음을 의미합니다. 예를 들어: 

 

def my_callback(channel):
    print('This is a edge event callback function!')
    print('Edge detected on channel %s'%channel)
    print('This is run in a different thread to your main program')

GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback)  # add rising edge detection on a channel
...the rest of your program...

 

둘 이상의 콜백 함수를 원할 경우: 

 

def my_callback_one(channel):
    print('Callback one')

def my_callback_two(channel):
    print('Callback two')

GPIO.add_event_detect(channel, GPIO.RISING)
GPIO.add_event_callback(channel, my_callback_one)
GPIO.add_event_callback(channel, my_callback_two)

 

이 경우 콜백 함수는 동시에 실행되지 않고 순차적으로 실행됩니다. 정의된 순서대로 모든 콜백이 실행되는 콜백에 사용되는 스레드가 하나만 있기 때문입니다.

 

스위치 디바운스

 

버튼을 누를 때마다 콜백이 두 번 이상 호출되는 것을 알 수 있습니다. 이것은 '스위치 바운스'로 알려진 결과입니다. 스위치 바운스를 처리하는 두 가지 방법이 있습니다.

  • 스위치에 0.1uF 커패시터를 추가하십시오.
  • 소프트웨어 디바운싱
  • 둘의 조합

 

소프트웨어를 사용하여 디바운스하려면 콜백 함수를 지정하는 함수에 bouncetime= 매개변수를 추가하십시오. 반송 시간은 밀리초 단위로 지정해야 합니다. 예를 들어: 

 

# add rising edge detection on a channel, ignoring further edges for 200ms for switch bounce handling
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)

또는 

GPIO.add_event_callback(channel, my_callback, bouncetime=200)

이벤트 감지 제거 어떤 이유로 프로그램이 더 이상 에지 이벤트를 감지하지 않으려면 중지할 수 있습니다. 

GPIO.remove_event_detect(channel)

 

GPIO 출력

 

GPIO Outputs

1. 먼저 RPi.GPIO를 설정합니다( 여기에 설명됨 ).

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)

2. 출력을 HIGH 설정하려면:

GPIO.output(12, GPIO.HIGH)
 # or
GPIO.output(12, 1)
 # or
GPIO.output(12, True)

3. 출력을 LOW 설정하려면:

GPIO.output(12, GPIO.LOW)
 # or
GPIO.output(12, 0)
 # or
GPIO.output(12, False)

4. 동시에 여러 채널로 출력하려면:

chan_list = (11,12)
GPIO.output(chan_list, GPIO.LOW) # all LOW
GPIO.output(chan_list, (GPIO.HIGH,GPIO.LOW))  # first LOW, second HIGH

5. 프로그램 종료 시 정리

GPIO.cleanup()

input() 함수를 사용하여 출력으로 설정된 채널의 현재 상태를 읽을 수 있습니다. 예를 들어 출력을 토글하려면:

GPIO.output(12, not GPIO.input(12))

 

 

PWM 사용법

 

PWM 인스턴스를 생성하려면:

p = GPIO.PWM(channel, frequency)

PWM을 시작하려면:

p.start(dc)   # where dc is the duty cycle (0.0 <= dc <= 100.0)

frequency를 변경하려면:

p.ChangeFrequency(freq)   # where freq is the new frequency in Hz

듀티 사이클을 변경하려면:

p.ChangeDutyCycle(dc)  # where 0.0 <= dc <= 100.0

PWM을 중지하려면:

p.stop()

인스턴스 변수 'p'가 범위를 벗어나면 PWM도 중지됩니다.
2초에 한 번씩 LED를 깜박이는 예:

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)

p = GPIO.PWM(12, 0.5)
p.start(1)
input('Press return to stop:')   # use raw_input for Python 2
p.stop()
GPIO.cleanup()

LED를 밝게/흐리게 하는 예:

import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)

p = GPIO.PWM(12, 50)  # channel=12 frequency=50Hz
p.start(0)
try:
    while 1:
        for dc in range(0, 101, 5):
            p.ChangeDutyCycle(dc)
            time.sleep(0.1)
        for dc in range(100, -1, -5):
            p.ChangeDutyCycle(dc)
            time.sleep(0.1)
except KeyboardInterrupt:
    pass
p.stop()
GPIO.cleanup()

 

 

gpio_function(channel)

 

GPIO 채널의 기능을 보여줍니다. 예를 들어: 

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
func = GPIO.gpio_function(pin)

 

GPIO.IN, GPIO.OUT, GPIO.SPI, GPIO.I2C, GPIO.HARD_PWM, GPIO.SERIAL, GPIO.UNKNOWN 같은 값을 반환합니다. 

 

 

 

참고

Inputs

 

 

 

 

 

반응형