Использование ШИМ в python для затемнения светодиодов на GPIO Raspberry Pi(v2).

В этом видео:
– что такое ШИМ модуляция;
– модуль RPi.GPIO.PWM
– разбор Python скрипта изменяющего яркость светодиодов.

Сегодня я продолжу рассказ о том что можно делать с GPIO портами на raspberry pi.
Покажу и подробно расскажу о скрипте с помощью которого можно вот так изменять яркость светодиодов(лучше один раз увидеть, чем сто раз услышать – как это выглядит на самом деле смотри в видео).

Сегодняшнея схема – четыре светодиода загораются последовательно с плавным повышением яркости.
Особенностью данного скрипта является использование функции PWM модуля GPIO.
Имя функции PWM – расшифровывается как pulse width modulation – широтно-импульсная модуляция.
Она имеет два параметра – номер порта и частота.

Функция генерирует так называемый объект, значение которого присваивается какой-либо переменной – например, greenfrq. Переменная по сути хранит настройки модуляции для определённого порта. Переменной greefrq присваивается состояние функции PWM для порта green=7 и частотой в 50Гц. 50Гц считается оптимальной частотой для широтно-импульсной модуляции – человеческий глаз не может распознать моргание диода (считается что человек не распознаёт частоты от 24Гц). Удвоенную частоту точно заменить будет нельзя – получается, что моргающий светодиод с этой частотой будет казаться постоянно включённым. Зачем это нужно, если можно просто включить диод? Об этом чуть дальше!
greenfrq = GPIO.PWM(green, 50)
В начале все диоды выключены:
greenfrq.start(0)
Далее в теле скрипта с использованием циклов (while, for) и дополнительного метода меняется величина Скважности – в англ.источниках используется обратная величина DutyCycle (из вики).
В Википедии о скважности сказано следующее – Скважность – один из классификационных признаков импульсных систем, определяющий отношение его периода следования (повторения) к длительности импульса. Величина, обратная скважности и часто используемая в англоязычной литературе, называется коэффициентом заполнения (англ. Duty cycle).
*В анимации наглядно показано что такое скважность-коэффициент заполнения. См.ссылку:
Скважность.Википедия.

Далее метод greenfrq.ChangeDutyCycle(c) – с его помощью можно менять значение коэффициент заполнения. Если он равен нулю, то никакого сигнала подаваться на пин не будет, если 100, то сигнал будет присутствовать постоянно – аналогично, если бы диод был просто включен без всяких модулей модуляции. А вот если, например, 50, то половину цигла диод будет включен, половину выключен и при частоте 50Гц, диод будет моргать 50 раз в секунду.

Так для чего это нужно? Особенно если мы всё равно не видем моргание в 50Гц? Ответ очень прост, начну я с конца – raspberry pi может либо подавать сигнал на пин, либо не подавать. Нельзя уменьшить величину сигнала. По этому, например, нельзя заставить диод гореть слабее или двигатель крутиться медленнее – только ВКЛ или ВЫКЛ! Нельзя сказать включись на половину…
Используя коэффициент заполнения можно подавать сигнал только на 50% каждую секунду, таким образом на диод или моторчик будет подаваться меньше энергии и диод будет гореть слабже или мотор будет крутиться медленнее.

Далее, используя циклы, можно “зажечь”светодиод изменяя коэффициент заполнения от нуля до 100)%. Чтобы вы успели заметить затемнения нужно в каждом цикле оставить место для time.sleep:
for c in range(0, 100, 2):
greenfrq.ChangeDutyCycle(c)
time.sleep(0.03)

Всё тоже самое работает для “гашения” диода, но в обратную сторону:
for c in range(100, -1, -2):
greenfrq.ChangeDutyCycle(c)
time.sleep(0.03)

В конце скрипта необходимо отключить запущенные модули и очистить состояние пинов:
except KeyboardInterrupt:
greenfrq.stop()
yellowfrq.stop()
redfrq.stop()
bluefrq.stop()
GPIO.cleanup()

Сам скрипт:
$ cat 1_led-dimming_with_modulation_4LEDs.py
# PWM - pulse width modulation
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)

green=7 ; yellow=12 ; red=16 ; blue=18
LED = [green,yellow,red,blue]

for i in LED:
GPIO.setup(i, GPIO.OUT, initial=0)

greenfrq = GPIO.PWM(green, 50)
greenfrq.start(0)
yellowfrq = GPIO.PWM(yellow, 50)
yellowfrq.start(0)
redfrq = GPIO.PWM(red, 50)
redfrq.start(0)
bluefrq = GPIO.PWM(blue, 50)
bluefrq.start(0)

print ("Ctrl+C exits the program")

try:
while True:
for c in range(0, 71, 2):
greenfrq.ChangeDutyCycle(c)
time.sleep(0.03)
for c in range(0, 71, 2):
yellowfrq.ChangeDutyCycle(c)
time.sleep(0.03)
for c in range(0, 71, 2):
redfrq.ChangeDutyCycle(c)
time.sleep(0.03)
for c in range(0, 71, 2):
bluefrq.ChangeDutyCycle(c)
time.sleep(0.03)

for c in range(70, -1, -2):
greenfrq.ChangeDutyCycle(c)
time.sleep(0.03)
for c in range(70, -1, -2):
yellowfrq.ChangeDutyCycle(c)
time.sleep(0.03)
for c in range(70, -1, -2):
redfrq.ChangeDutyCycle(c)
time.sleep(0.03)
for c in range(70, -1, -2):
bluefrq.ChangeDutyCycle(c)
time.sleep(0.03)

except KeyboardInterrupt:
greenfrq.stop()
yellowfrq.stop()
redfrq.stop()
bluefrq.stop()
GPIO.cleanup()

На этом всё.
Удачи!