Собираем интернет-радио на Raspberry Pi с АЦП MCP3008

Перевод статьи Build an internet radio — Phil King, Raspberry Pi.
В этом уроке мы подключим потенциометр к АЦП MCP3008, чтобы управлять яркостью светодиода поворотом ручки. Затем добавим второй потенциометр и соберём интернет-радио, где двумя ручками будем переключать станцию и регулировать громкость.
Материал взят из книги издательства Raspberry Pi Press «Simple electronics with GPIO Zero». В прошлом мы использовали приём с конденсатором, чтобы считать показания аналогового датчика. Но лучший и самый надёжный способ для Raspberry Pi работать с аналоговыми входами — это микросхема аналого-цифрового преобразователя (АЦП), например MCP3008, у которой восемь входных каналов для подключения датчиков и других аналоговых источников. Это не только избавляет от конденсатора, но и даёт более точные и мгновенные показания по всему диапазону выходного сигнала датчика.

Рисунок 1: подключение АЦП на макетной плате
Включаем SPI#
Аналоговые значения от АЦП передаются в Raspberry Pi по протоколу SPI. В GPIO Zero это работает «из коробки», но результаты будут лучше, если включить полную поддержку SPI. Сначала убедитесь, что установлен Python-пакет spidev (по умолчанию он должен быть). Откройте терминал и введите:
$ sudo apt install python3-spidev
Затем откройте меню Raspberry Pi, выберите Preferences, откройте Control Centre и включите SPI в разделе Interfaces. Нажмите OK и перезагрузите Raspberry Pi. Можно воспользоваться и командной строкой: запустите sudo raspi-config, зайдите в Interface Options, включите SPI и перезагрузитесь.
Подключаем АЦП#
Как обычно, перед сборкой схемы Raspberry Pi нужно выключить. Как видно из рисунка 1, для подключения АЦП MCP3008 к выводам GPIO требуется довольно много проводов.
Сначала установите MCP3008 в середину макетной платы, чтобы он оседлал центральную канавку. Теперь соедините перемычки как на схеме. Две идут на шину питания «+», подключённую к выводу 3V3; ещё две — на вывод GND через шину «–». Четыре средних ноги АЦП подключаются к GPIO 8 (CE0), 10 (MOSI), 9 (MISO) и 11 (SCLK).
Читаем значение#
Подключив АЦП к Raspberry Pi, к его восьми входным каналам (пронумерованным от 0 до 7) можно подсоединять устройства. Здесь мы подключим первый (крайний слева) потенциометр — это переменный резистор: при повороте ручки Raspberry Pi считывает напряжение (от 0 В до 3,3 В). Это можно использовать для управления другими компонентами, например светодиодом. Как показано на рисунке 1, подключите одну крайнюю ногу потенциометра (снизу слева) к шине питания «+», другую — к шине земли «–», а среднюю — к первому входу MCP3008: каналу 0.
Теперь считаем значение потенциометра в Python. Создайте новый файл, сохраните его как test_pot.py и запустите:
from gpiozero import MCP3008
pot = MCP3008(channel=0)
while True:
print(pot.value)
Вверху мы импортируем класс MCP3008 из GPIO Zero, затем задаём переменную pot для канала 0 АЦП. Цикл while True: непрерывно выводит на экран значение потенциометра (от 0 до 1); попробуйте покрутить ручку во время работы кода и увидите, как меняется число. Для выхода нажмите CTRL+C.
Зажигаем светодиод#
Теперь добавим в схему светодиод, как на рисунке 2: длинную (положительную) ногу подключим к GPIO 21, а короткую через резистор — к шине земли «–». Создайте новый файл, введите следующий код и сохраните программу как source_values.py.
from gpiozero import MCP3008, PWMLED
from signal import pause
pot = MCP3008(0)
led = PWMLED(21)
led.source = pot.values
pause()
Код импортирует классы MCP3008 и PWMLED, а также функцию pause из модуля signal. Класс MCP3008 позволяет управлять яркостью светодиода широтно-импульсной модуляцией (ШИМ). Мы создаём объект PWMLED на GPIO 21 и присваиваем его переменной led. Потенциометр, как и прежде, назначаем каналу 0. Наконец, используем умную систему source и values из GPIO Zero, чтобы связать потенциометр со светодиодом и непрерывно задавать яркость второго по значению первого. Запустите код и покрутите ручку, регулируя яркость светодиода. Для выхода нажмите CTRL+C.

Рисунок 2: светодиод и потенциометры на макетной плате
Добавляем второй потенциометр#
Если ещё не сделали, добавьте в схему второй потенциометр, как на рисунке 2, подключив его среднюю ногу к каналу 1 MCP3008. Теперь двумя потенциометрами будем управлять частотой мигания светодиода. Создайте новый файл, введите код и сохраните его как two_pots.py. Здесь мы создаём две отдельные переменные pot1 и pot2, привязанные к каналам 0 и 1 АЦП соответственно. В цикле while True: выводим оба значения на экран и заставляем светодиод мигать, а времена включения и выключения зависят от двух наших потенциометров. Запустите код и покрутите обе ручки, чтобы увидеть, как это меняется.
Устанавливаем VLC#
Ту же схему используем для простого интернет-радио: одним потенциометром будем переключать станцию, другим — регулировать громкость. Если VLC не установлен по умолчанию, его нужно поставить, чтобы проигрывать M3U-потоки интернет-радио. Откройте терминал и введите:
$ sudo apt install vlc
Делаем радио#
Создайте новый файл, введите код из листинга radio_new.py и сохраните под этим именем.
В начале мы импортируем класс MCP3008, а также Popen, run и time; Popen позволит запускать и останавливать VLC. Создаём переменные для ручек станции и громкости на каналах 0 и 1 АЦП соответственно. Затем присваиваем переменным два URL радиопотоков (в примере использованы SomaFM Groove Salad и Indie Pop).
Далее создаём пару функций. Первая, set_volume, использует wpctl (утилиту командной строки для WirePlumber, менеджера сессий PipeWire) для управления громкостью. Вторая, change_station, содержит условие if, поэтому срабатывает только когда станция, заданная положением первого потенциометра, отличается от текущей (current_station). Если так, она останавливает текущий поток и запускает новый, после чего переприсваивает ему переменную current_station.
Наконец, в цикле while True: внутри блока try … except мы по очереди читаем каждый потенциометр и с помощью условных операторов if вызываем нужные функции set_volume и change_station. Запустите код и покрутите оба потенциометра, чтобы переключать станцию и регулировать громкость. Для простоты в примере всего две станции, но вы легко добавите ещё, соответственно подправив пороги station.dial.value.
Благодаря блоку try … except нажатие CTRL+C останавливает радиопоток перед выходом из программы.