Raspberry Pi. PWM. Генерация ШИМ-сигнала.

Рассмотрев работу с портами ввода-вывода GPIO в качестве обычных входов и выходов, нельзя не затронуть и вопрос использования Raspberry Pi для генерации ШИМ (PWM).

ШИМ-сигналы могут использоваться, к примеру, для управления серво-приводами или двигателями постоянного тока, либо для контроля яркости светодиодов. И это только несколько самых основных, сразу возникающих в памяти, применений. Таким образом, необходимость в генерации ШИМ возникает довольно часто и в самых разных проектах.

Итак, ШИМ-сигнал представляет из себя последовательность импульсов с постоянной частотой следования, но разной длительностью. Давайте рассмотрим наглядный пример:

ШИМ сигнала

Поскольку частота импульсов постоянна, то значит и период имеет фиксированную величину. А вот длительность импульса может меняться, собственно так и происходит модуляция. Рассмотрим два разных сигнала, использующихся для включения/отключения светодиодов:

Пример PWM сигналов

Пусть светодиоды загораются при высоком уровне сигнала. Период в обоих случаях идентичен, а вот длительность импульсов второго сигнала больше в 2 раза. Соответственно, светодиод во втором случае будет гореть ярче, чем в первом.

Строго говоря, светодиод будет мигать, то есть часть периода гореть, а часть периода – нет. Но при высокой частоте следования импульсов глазу будут не заметны эти мигания, поэтому на практике получим 2 светодиода с разной яркостью. То есть, чем большую часть периода диод горит – тем ярче будет в результате светить.

ШИМ-сигналы характеризуют параметром, который называется – коэффициент заполнения (duty cycle). Он вычисляется по формуле:

D = \frac{\tau}{T}\medspace * \medspace 100\%

Здесь \tau – длительность импульса, а T – период сигнала.

Вернемся к рассмотренным выше сигналам – для первого случая длительность импульса составляет \frac{4}{10} периода сигнала, а значит D = 40\%. Аналогично, для второго случая D = 80\%.

На этом заканчиваем лирическое отступление на тему ШИМ и переходим к практической реализации на Raspberry Pi.

Вспоминаем таблицу распределения функций портов GPIO. Я сейчас пользуюсь Raspberry Pi 4, для любой другой модификации можно найти аналогичную информацию в даташите. Итак, для генерации ШИМ могут использоваться следующие выводы:

GPIO ШИМ Raspberry Pi

Задействуем два порта в нашем примере – GPIO12 и GPIO13. При этом пусть коэффициент заполнения будет одинаковым, а частота второго сигнала (GPIO13) – в 2 раза больше.

Для работы с PWM на Python используем все тот же модуль RPi.GPIO, установить который в случае отсутствия можно командой:

sudo apt-get install python-rpi.gpio

Создаем файл pwm_test.py:

import RPi.GPIO as GPIO
import time

GPIO_PWM_0 = 12
GPIO_PWM_1 = 13
WORK_TIME = 10
DUTY_CYCLE = 50
FREQUENCY = 100

GPIO.setmode(GPIO.BCM)

GPIO.setup(GPIO_PWM_0, GPIO.OUT)
GPIO.setup(GPIO_PWM_1, GPIO.OUT)

pwmOutput_0 = GPIO.PWM(GPIO_PWM_0, FREQUENCY)
pwmOutput_1 = GPIO.PWM(GPIO_PWM_1, 2 * FREQUENCY)

pwmOutput_0.start(DUTY_CYCLE)
pwmOutput_1.start(DUTY_CYCLE)

time.sleep(WORK_TIME)

pwmOutput_0.stop()
pwmOutput_1.stop()
GPIO.cleanup()

Разбираем написанное. Первым делом подключаем модули и объявляем переменные:

import RPi.GPIO as GPIO
import time

GPIO_PWM_0 = 12
GPIO_PWM_1 = 13
WORK_TIME = 10
DUTY_CYCLE = 50
FREQUENCY = 100
  • GPIO_PWM_0 и GPIO_PWM_1 – номера выводов GPIO, которые мы используем для генерации ШИМ
  • WORK_TIME – время выполнения программы. В этом примере не будем анализировать действия пользователя для определения момента выхода из программы. Просто включаем ШИМ и по истечении времени WORK_TIME (10 секунд) заканчиваем работу.
  • DUTY_CYCLE – коэффициент заполнения, одинаковый для обоих каналов и составляющий 50%.
  • FREQUENCY – частота сигнала (100 Гц) первого канала. На втором установим в 2 раза больше, как и планировали.

Далее настроим режим нумерации портов, чтобы номера соответствовали названию сигнала (например, GPIO12, GPIO13), а не порядковому номеру на разъеме, а также настроим нужные нам порты:

GPIO.setmode(GPIO.BCM)

GPIO.setup(GPIO_PWM_0, GPIO.OUT)
GPIO.setup(GPIO_PWM_1, GPIO.OUT)

Создаем объекты pwmOutput_0 и pwmOutput_1 для работы с каналами PWM. В качестве аргументов указываем последовательно – номер порта GPIO и частоту следования импульсов:

pwmOutput_0 = GPIO.PWM(GPIO_PWM_0, FREQUENCY)
pwmOutput_1 = GPIO.PWM(GPIO_PWM_1, 2 * FREQUENCY)

Запускаем генерацию функцией start() – аргументом является требуемая величина коэффициента заполнения (duty cycle):

pwmOutput_0.start(DUTY_CYCLE)
pwmOutput_1.start(DUTY_CYCLE)

Ожидаем 10 секунд и останавливаем процесс:

time.sleep(WORK_TIME)

pwmOutput_0.stop()
pwmOutput_1.stop()
GPIO.cleanup()

На этом базовый пример закончен, запускаем его на выполнение:

python pwm_test.py

В результате получаем сигналы ШИМ:

ШИМ на плате Raspberry Pi

Коэффициент заполнения одинаковый (50% – длительность импульса равна половине периода), а частота во втором случае в 2 раза выше, собственно, как и должно быть 🙂

Давайте реализуем еще один небольшой пример – будем менять коэффициент заполнения, а, соответственно, и длительность импульса в цикле программы. При этом период импульсов будет оставаться постоянным. Создаем файл pwm_test_dynamic.py и пишем код:

import RPi.GPIO as GPIO
import time

GPIO_PWM_0 = 12
FREQUENCY = 100
DELAY_TIME = 0.02

GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PWM_0, GPIO.OUT)

pwmOutput_0 = GPIO.PWM(GPIO_PWM_0, FREQUENCY)
pwmOutput_0.start(0)

try:
    while True:
        for dutyCycle in range(0, 101, 1):
            pwmOutput_0.ChangeDutyCycle(dutyCycle) 
            sleep(DELAY_TIME)
except KeyboardInterrupt:
    pwmOutput_0.stop()
    GPIO.cleanup()
    print('exiting')

Аналогичным образом настраиваем GPIO12 и запускаем PWM с коэффициентом заполнения 0 и частотой 100 Гц:

GPIO_PWM_0 = 12
FREQUENCY = 100
DELAY_TIME = 0.02

GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PWM_0, GPIO.OUT)

pwmOutput_0 = GPIO.PWM(GPIO_PWM_0, FREQUENCY)
pwmOutput_0.start(0)

В основном цикле программы while True каждые 0.02 с (DELAY_TIME) изменяем duty cycle в диапазоне от 0 до 100:

while True:
	for dutyCycle in range(0, 101, 1):
		pwmOutput_0.ChangeDutyCycle(dutyCycle) 
		sleep(DELAY_TIME)

При нажатии пользователем Ctrl + C завершаем выполнение программы:

pwmOutput_0.stop()
GPIO.cleanup()
print('exiting')

Запускаем:

python pwm_test_dynamic.py

И получаем:

Генерация работает как положено, так что на этом заканчиваем разбор ШИМ для Raspberry Pi на сегодня, до новых статей!

Поделиться!

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments

Присоединяйтесь!

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Ноябрь 2020
Пн Вт Ср Чт Пт Сб Вс
 1
2345678
9101112131415
16171819202122
23242526272829
30  

© 2013-2020 MicroTechnics.ru