개발자/라즈베리파이4

라즈베리파이 Python 프로그래밍 16: 아날로그 출력 및 소프트웨어 PWM

지구빵집 2021. 11. 22. 10:18
반응형

 

 

라즈베리파이 Python 프로그래밍 16: 아날로그 출력 및 소프트웨어 PWM 

 

이전의 튜토리얼에서 라즈베리파이에서 디지털 입력을 사용하는 방법을 배웠습니다. Raspberry Pi는 임베디드 컴퓨터로써 디지털 입력, 디지털 출력, 펄스폭 변조(PWM) 및 여러 직렬 통신 프로토콜(UART/USART, I2C, SPI 등)의 구현이 가능합니다.

 

여기에서는 라즈베리파이와 함께 PWM을 사용하여 아날로그 출력을 다룹니다. 나중에 우리는 Raspberry Pi의 PWM 기능을 사용하여 LED를 깜박이고 페이드 기능을 추가 할 것입니다.

 

싱글 온보드 컴퓨터 SBC

 

PWM 펄스 폭 변조, Pulse Width Modulation 혹은 pulse-duration modulation

 

대부분의 마이크로컨트롤러와 단일 보드 컴퓨터(Arduino 및 RPi 포함)는 진정한 아날로그 신호를 생성할 수 없습니다. 이 신호를 생성하려면 저가의 마이크로컨트롤러나 SBC와 쉽게 통합되지 않는 복잡한 회로가 필요하기 때문입니다.

 

그러나 컨트롤러와 임베디드 컴퓨터에는 종종 비주기적인 아날로그 입력을 사용하는 제어 장치나 액추에이터가 필요합니다. 그렇기 때문에 단일 보드 컨트롤러와 컴퓨터에는 일반적으로 PWM 기능이 장착되어 있습니다.

 

펄스 변조 신호는 정의된 전압 범위에서 아날로그 신호의 근사치입니다. 일반적으로 컨트롤러/SBC에서 생성된 PWM 출력은 단극성이며 개발 보드에 따라 피크 전압 근사치가 5 또는 3.3V입니다.

 

PWM 신호는 듀티 사이클(Duty Cycle)이 변경될 수 있는 고정(또는 설정) 주파수의 주기적인 직사각형 신호입니다. 고정 주파수 주기 구형파의 듀티 사이클을 변경하여 신호는 정의된 범위에서 아날로그 전압 레벨에 근접할 수 있습니다. 신호가 근사할 수 있는 최대 아날로그 전압은 구형파의 진폭입니다.

 

Pulse Width Modulation

 

PWM 신호가 근사할 수 있는 다른 모든 전압 레벨은 듀티 사이클의 허용된 변동에 따라 다릅니다. 예를 들어 PWM 신호의 진폭이 5V라고 가정해 보겠습니다. 듀티 사이클이 8비트 레지스터에 의해 제어되는 경우 0~5V 사이에서 256(2^8) 전압 레벨을 달성할 수 있습니다. 이제 이러한 전압 레벨이 동일한 간격으로 정확하게 배치되어 있다고 가정하면 각 전압 레벨은 인접한 전압 레벨과 19.6mV(5V/255)만큼 다릅니다.

 

반면에 듀티 사이클이 동일한 진폭의 10비트 레지스터에 의해 제어되는 경우 0~5V 사이에서 1024(2^10) 전압 레벨을 달성할 수 있습니다. 이 경우 각 전압 레벨은 인접한 전압 레벨과 4.9mV만큼 다릅니다.

 

PWM 신호의 주파수는 신호가 달성할 수 있는 전압 레벨의 수에 영향을 미치지 않습니다. PWM 신호의 주파수가 높을수록 전압 레벨의 정밀도가 높아집니다. PWM 신호의 주파수는 또한 신호가 회로 또는 오디오 애플리케이션에서 고속 스위칭 작동에 사용될 때 중요한 역할을 합니다.

 

PWM 신호는 DC 모터, 서보 모터의 속도 제어 또는 LED 페이딩과 같은 여러 임베디드 애플리케이션에 사용됩니다.

 

PWM 방식으로 아날로그 출력

 

Raspberry Pi의 아날로그 출력은 대부분의 다른 단일 보드 컴퓨터 및 마이크로 컨트롤러와 유사합니다. 진정한 아날로그 출력을 생성할 수 없습니다. 그러나 RPi는 26개의 GPIO 핀 모두에서 소프트웨어 PWM을 생성할 수 있습니다. 또한 다음 위치에서 하드웨어 PWM 신호를 생성할 수 있습니다.

 

  • GPIO12(보드 핀 번호 32)
  • GPIO13(보드 핀 번호 33)
  • GPIO18(보드 핀 번호 12)
  • GPIO19(보드 핀 번호 35).

하드웨어 PWM은 Broadcom SoC의 시스템 타이머를 사용하며 최대 주파수 19.2 MHz의 PWM 신호를 생성할 수 있습니다.

 

이 이미지는 하드웨어 PWM을 사용할 수 있는 RPi 채널을 보여줍니다.

 

Raspberry Pi PWM Pins 이미지 - https://www.electronicwings.com/raspberry-pi/raspberry-pi-pwm-generation-using-python-and-c

 

소프트웨어 PWM은 RPi의 GPIO 26개 모두에서 사용할 수 있으며 1Hz에서 수 킬로 헤르츠까지 PWM 주파수를 생성할 수 있습니다. 소프트웨어 PWM 신호의 듀티 사이클은 0.0과 100.0 사이에서 변할 수 있습니다.

 

하드웨어 PWM 신호를 생성하려면 pigpio 라이브러리를 가져와야 합니다. 그러나 소프트웨어 PWM 신호는 RPi.GPIO 라이브러리를 가져오기만 하면 생성할 수 있습니다. 이 튜토리얼에서는 소프트웨어 PWM 신호를 생성하는 방법을 배웁니다.

 

이미지 https://www.analogictips.com/pulse-width-modulation-pwm/

 

Python을 사용하여 소프트웨어 PWM 신호 생성

 

py_pwm.c, py_pwm.h, soft_pwm.c 및 soft_pwm.h 파일 덕분에 RPi.GPIO 라이브러리를 사용하여 RPi 채널에서 소프트웨어 PWM을 생성할 수 있습니다( RPi.GPIO 라이브러리의 소스 코드 ).

 

라이브러리는 RPi에서 소프트웨어 PWM을 생성하고 제어하기 위해 다음 Python 함수를 지원합니다 .

 

GPIO.PWM() 메서드

 

이 함수는 PWM 인스턴스를 생성하는 데 사용됩니다. 두 개의 인수가 필요합니다.

 

1. PWM 신호가 생성되어야 하는 채널 번호

2. Hertz 단위의 PWM 신호 주파수. 인스턴스는 변수에 메서드를 할당하여 생성해야 합니다.

 

이 함수/메서드의 구문은

 

soft_pwm = GPIO.PWM(channel, frequency)

 

채널 번호는 사용자 프로그램에 설정된 보드 또는 BCM 번호에 따라 지정해야 합니다.

 

start() 메서드

 

이 메서드는 소프트웨어 PWM의 인스턴스에 적용할 수 있습니다. PWM 신호의 듀티 사이클이라는 하나의 인수만 사용합니다.

 

PWM 인스턴스에서 이 메서드를 호출하면 Python 프로그램 은 지정된 듀티 사이클로 지정된 채널에서 소프트웨어 PWM 신호를 시작합니다.

 

다음은 구문입니다.

 

soft_pwm.start(duty cycle)

 

ChangeFrequency() 메서드

 

이 메서드는 소프트웨어 PWM의 인스턴스에 적용할 수 있습니다. 그것은 단 하나의 인수를 취합니다: Hertz에서 PWM 신호의 새로운 주파수.

 

PWM 인스턴스에서 이 메서드를 호출하면 Python 프로그램은 PWM 출력의 주파수를 지정된 주파수로 변경합니다.

 

구문은 다음과 같습니다.

 

soft_pwm.ChangeFrequency(frequency)

 

ChangeDutyCycle() 메서드

 

이 메서드는 소프트웨어 PWM의 인스턴스에 적용할 수 있습니다. 새로운 듀티 사이클이라는 하나의 인수만 필요합니다.

 

듀티 사이클의 값은 0.0에서 100.0 사이일 수 있습니다. PWM 인스턴스에서 이 메서드를 호출하면 Python 프로그램은 PWM 신호의 듀티 사이클을 지정된 듀티 사이클로 변경합니다.

 

이 메서드의 구문은

 

soft_pwm.ChangeDutyCycle(duty cycle)

 

stop() 메서드

 

이 메서드는 소프트웨어 PWM의 인스턴스에 적용할 수 있습니다. 인수가 필요하지 않습니다. 인스턴스에서 이 메서드를 호출하면 PWM 신호가 해당 채널에서 중지됩니다. 메서드의 구문은

 

soft_pwm.stop()

레시피: PWM을 사용한 LED 깜박임

 

이 레시피에서는 소프트웨어 PWM을 사용하여 Raspberry Pi의 LED를 깜박입니다.

 

필요한 구성 요소

1. Raspberry Pi 3/4 모델 B x1

2. LED x1

3. 330 Ohms 저항 x1

4. 브레드보드 x1

5. 암수 점퍼 와이어

 

회로 연결

 

먼저 Raspberry Pi의 GPIO21(보드 핀 번호 40)을 LED의 양극에 연결합니다. 다음으로 LED의 음극을 330 Ohms의 직렬 저항과 연결한 다음 저항의 다른 쪽 단자를 접지합니다.

 

DC 공급 전압과 접지는 각각 Pi 보드의 핀 번호 2와 6에서 회로에 제공될 수 있습니다.

 

 

파이썬 스크립트

 

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

soft_pwm = GPIO.PWM(12, 1)
soft_pwm.start(50)
input(“Press return to stop: “)
soft_pwm.stop()
GPIO.cleanup()

 

프로젝트 작업

 

LED는 RPi의 GPIO 헤더의 핀 40에서 인터페이스 됩니다. 연결되어 있으므로 RPi의 채널은 전원을 켜기 위해 전류를 소싱해야 합니다. Python 스크립트에서 50% 듀티 사이클로 1Hz 주파수의 소프트웨어 PWM 신호가 생성됩니다.

 

1 헤르츠는 PWM 신호가 1초의 기간을 갖는다는 것을 의미합니다. 50% 듀티 사이클에서 채널은 500밀리 초 동안 HIGH 신호를 출력한 다음 또 다른 500밀리 초 동안 LOW 신호를 출력합니다. 이것은 LED를 500밀리 초 동안 켜고 다음 500밀리 초 동안 끕니다.

 

따라서 LED는 1초 간격으로 계속 깜박입니다.

 

프로그래밍 가이드

 

Python 스크립트는 RPi.GPIO 라이브러리를 가져오는 것으로 시작합니다. RPi의 핀 번호는 GPIO.setmode() 함수를 사용하여 보드 번호로 설정됩니다. 그러나 보드 핀 40은 GPIO.setup() 메서드를 사용하여 출력 핀으로 설정됩니다.

 

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

GPIO.PWM() 메서드를 사용하여 1Hz의 소프트웨어 PWM 인스턴스가 보드 핀 40에서 생성됩니다. 소프트웨어 PWM 인스턴스의 듀티 사이클은 start() 메서드를 사용하여 50%로 설정됩니다.

 

사용자가 리턴 키를 누를 때 스크립트를 종료하기 위해 input() 함수가 호출됩니다. 입력이 수신되면 stop() 메서드를 사용하여 PWM 신호를 중지하고 GPIO.cleanup() 메서드를 사용하여 GPIO 핀을 정리합니다.

 

soft_pwm = GPIO.PWM(40, 1)
soft_pwm.start(50)
input(“Press return to stop: “)
soft_pwm.stop()
GPIO.cleanup()

 

레시피: PWM을 사용한 LED 페이딩

 

이 레시피에서는 Raspberry Pi와 함께 소프트웨어 PWM을 사용하여 LED를 페이딩 합니다.

 

필요한 구성 요소 및 회로 연결 모두 이전 레시피와 동일합니다. 파이썬 스크립트는 아래와 같습니다.

 

import RPi.GPIO as GPIO
import time

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(40, GPIO.OUT)
soft_pwm = GPIO.PWM(40, 50)

def setup():
soft_pwm.start(0)

def loop():
for dc in range(0, 100, 1):
soft_pwm.ChangeDutyCycle(dc)
time.sleep(0.1)
for dc in range (100, 0, -1):
soft_pwm.ChangeDutyCycle(dc)
time.sleep(0.1)

def endprogram():
soft_pwm.stop()
GPIO.cleanup()

if __name__ == ‘__main__’:
setup()
try:
loop()
except KeyboardInterrupt:
print(“Keyboard Interrupt Detected”)
endprogram()

 

프로젝트 작업

 

LED를 흐리게 하려면 정류된 사인파에 가까운 아날로그 신호를 적용해야 합니다. 이에 대해 자세히 알아보려면 Arduino를 사용한 LED 페이딩 레시피를 확인하십시오.

 

RPi에서는 50Hz의 소프트웨어 PWM 신호를 생성하여 수정된 사인파를 사용하고 있습니다. 이 주파수에서 신호는 20밀리 초의 시간 주기를 갖습니다. 빈도는 응용 프로그램 전체에서 변경되지 않습니다.

 

정류된 사인파를 생성하려면 소프트웨어 PWM의 듀티 사이클이 0에서 100까지 1씩 증가해야 합니다. 각 단계 또는 증분은 0.1초 동안 적용되며 PWM 신호의 5개 펄스 열이 LED에 적용됩니다.

 

그런 다음 듀티 사이클은 -1 증분으로 100에서 1로 감소합니다. 5개의 PWM 펄스 트레인이 각 증분의 0.1초 동안 적용됩니다. 사용자 프로그램은 키보드 인터럽트가 수신될 때까지 try-exception 문을 사용하여 무한 반복하도록 만들어집니다.

 

프로그래밍 가이드

 

스크립트는 RPi.GPIO 및 시간 라이브러리를 가져오는 것으로 시작합니다. GPIO 경고는 GPIO.setwarnings() 메서드를 사용하여 false로 설정됩니다.

 

RPi의 핀 번호는 GPIO.setmode() 함수를 사용하여 보드 번호로 설정됩니다. 보드 핀 40은 GPIO.setup() 메서드를 사용하여 출력 핀으로 설정됩니다. 그러나 보드 핀 40은 GPIO.PWM() 메서드를 사용하여 소프트웨어 PWM으로 인스턴스화 됩니다.

 

import RPi.GPIO as GPIO
import time
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(40, GPIO.OUT)
soft_pwm = GPIO.PWM(40, 50)

사용자 정의 setup() 함수는 소프트웨어 PWM이 PWM 인스턴스에서 시작하는 0% 듀티 사이클을 갖도록 작성되었습니다. 이 기능은 한 번만 실행됩니다.

 

def setup()
soft_pwm.start(0)

PWM 신호의 듀티 사이클이 0에서 100으로 변경되었다가 다시 0으로 변경되는 사용자 정의 loop() 함수가 작성되었습니다. 이것은 각 증가 동안 0.1초 간격으로 1단계로 발생합니다.

 

이 기능은 LED가 무한한 횟수 동안 켜지고 꺼지도록 무한히 반복됩니다.

 

def loop():
for dc in range(0, 100, 1):
soft_pwm.ChangeDutyCycle(dc)
time.sleep(0.1)
for dc in range (100, 0, -1):
soft_pwm.ChangeDutyCycle(dc)
time.sleep(0.1)

endprogram() 함수는 키보드 인터럽트가 수신될 때 PWM 신호를 중지하기 위해 작성됩니다. 그런 다음 Raspberry Pi GPIO를 정리합니다.

 

def endprogram():
soft_pwm.stop()
GPIO.cleanup()

위에 정의된 함수는 setup() 함수가 한 번 실행되는 반면 loop() 함수는 키보드 인터럽트가 수신될 때까지 계속 반복되도록 try-exception 문에서 호출됩니다.

 

if __name__ == ‘__main__’:
setup()
try:
loop()
except KeyboardInterrupt:
print(“Keyboard Interrupt Detected”)
endprogram()

 

고생하셨습니다. 다음 포스팅에서는 라즈베리파이 씨리얼 통신에 대해 배워보겠습니다.

 

이제 이만큼 거리를 준다.

 

 

반응형