Представляю вам образовательный проект — “Детектор звука”, разработанный в рамках учебно-методического комплекса на базе одноплатного компьютера Repka PI 4.
Данный проект предназначен для мониторинга уровня звука в окружающей среде с наглядной индикацией результатов на OLED-дисплее. В качестве основного сенсора используется микрофонный модуль MAX9814, обеспечивающий чувствительное измерение уровня громкости.
Аналоговый сигнал с микрофона поступает на АЦП ADS1115, который преобразует его в цифровое значение для последующей обработки на одноплатном компьютере Repka Pi 4. В зависимости от зафиксированной громкости, проект управляет RGB-светодиодом, изменяя цвет подсветки:
— синий при низком уровне шума,
— зелёный при среднем,
— красный при высоком уровне звука.
Параллельно цифровые значения и соответствующий уровень громкости отображаются на OLED-дисплее 0.96" с интерфейсом I2C, позволяя в реальном времени отслеживать изменение звуковой среды.
Проект “Детектор звука” отлично подходит для изучения работы с аналоговыми датчиками, АЦП, OLED-дисплеем и основами визуальной индикации, а также может быть использован как элемент более сложных систем мониторинга или автоматизации.
Проект будет собираться с использованием “Учебно-методический комплекс REPKA”. Схему сборки можно найти в разделе "Примеры готовых проектов" учебного пособия УМК “REPKA”.
Также все необходимые материалы и схемы подключения доступны в репозитории на платформе Gitflic.
Компоненты проекта
1. Потребуется аналогово-цифровой преобразователь (далее АЦП) модели ADS1115 для считывания показаний с микрофона, см. рисунок 1.
2. Микрофонный модуль MAX9814, предназначенный для улавливания звуков из окружающей среды и формирования аналогового сигнала, пропорционального уровню громкости, см. рисунок 2.
3. Дисплей OLED 0.96″ I2C для отображения значений цифрового сигнала, см. рисунок 3.
4. Четырехконтактный светодиодный RGB модуль (RGB LED) для визуализации уровня громкости, см. рисунок 4.
Вы можете приобрести все необходимые компоненты отдельно от "Учебно-методический комплекс REPKA". Ссылки на модули приведены в таблице ниже.
Компонент | Ссылка на приобретение |
---|---|
Монтажная/макетная плата | Ссылка |
Шлейф | Ссылка |
Переходник с шлейфа на макетную плату | Ссылка |
Соединительные провода | |
АЦП (ADS1115) | Ссылка |
ЖК дисплей (1602 I2C) | Ссылка |
Микрофонный модуль (MAX9814) | Ссылка |
Дисплей OLED 0.96″ I2C | Ссылка |
Подготовительный этап
1. Подключим дополнительное питание 5V к макетной плате:
2. После чего выведем дополнительное питание на макетную плату:
3. Подключим переходник с шлейфа на макетную плату:
4. Соединим шлейф с переходником для подключения к макетной плате и Repka Pi 4:
5. Итоговый результат должен выглядеть таким образом:
Сборка проекта
Во время сборки проекта будем регулярно обращаться к электрической принципиальной схеме и монтажной схеме, представленными в учебном пособии (см. рисунки 5 и 6). Эти схемы будут служить основным ориентиром на всех этапах подключения компонентов, обеспечивая точность и правильность сборки устройства.
Для разработки кода будет использоваться текстовый редактор Geany, который входит в состав стандартного ПО Репка ОС.
Электрическая принципиальная схема #
Монтажная схема #
- Подключение АЦП (ADS1115).
Как видно из рисунков 5 и 6 АЦП подключается через интерфейс I2C и питается от 5V.
1.1. Подключим АЦП (ADS1115) к макетной плате согласно таблице 1:
Макетная плата | АЦП (ADS1115) |
---|---|
5V | V |
GND | G |
SCL1 | SCL |
SDA1 | SDA |
Таблица 1. Подключение АЦП (ADS1115) к макетной плате.
1.2. Результат подключения будет выглядеть следующим образом, см. рисунок 6:
Проверку работоспособности АЦП будем проводить после подключения микрофона, чтобы убедиться в правильности считывания аналогового сигнала и корректности преобразования данных.
2. Подключение микрофона (MAX9814).
Как видно из рисунков 6 и 7, микрофон подключается к аналоговым входу A0 внешнего АЦП, что позволяет считывать с него значения. Питание модуля осуществляется от линии 5V.
2.1. Подключаем микрофон к к макетной плате согласно таблице 2.
Макетная плата | MAX9814 | АЦП |
---|---|---|
5V | VDD | |
GND | GND | |
OUT | A0 |
Таблица 2. Подключение MAX9814 к макетной плате.
2.2. Результат подключения будет выглядеть следующим образом, см. рисунок 7.
3. Выполним проверку подключения устройств АЦП и микрофона. Для этого будем использовать python скрипт из репозитория repka-pi_iot-examples.
3.1. Клонируем репозиторий:
git clone git@gitflic.ru:repka_pi/repka-pi_iot-examples.git
3.2. Переходим в репозиторий:
cd repka-pi_iot-examples/
3.3. Выполним установку зависимостей.
3.3.1. Если хотите установить зависимости только для микрофона, выполните:
make setup-max9814
3.3.2. Если хотите установить зависимости для всех датчиков и проектов, выполните:
make setup-all
3.4. Запускаем скрипт для проверки работоспособности прибора:
make max9814
3.5. Если на этапе 3.4. возникает ошибка, необходимо внести изменения в Python-скрипт, расположенный по пути devices/input-output/max9814_example/py, корректируя номер – i2c = I2C("/dev/i2c-1") и адрес шины – ADS1115_ADDR. В случае отсутствия ошибок, данный шаг нужно пропустить.
#Адрес устройства ADS1115 на шине I2C (по умолчанию 0x48)
ADS1115_ADDR = 0x48
# Создаём объект для работы с шиной I2C на Repka Pi ("/dev/i2c-1" — это стандартный порт)
i2c = I2C("/dev/i2c-1")
3.6. Из рисунка 8 видно, что скрипт был успешно выполнен, и данные считываются с микрофона корректно.
4. Выполним подключение OLED дисплея.
Как видно из рисунков 5 и 6 устройство подключается через интерфейс I2C и питается от 5V.
4.1. Подключим дисплей OLED 0.96″ I2C к макетной плате согласно таблице 3.
Макетная плата | Дисплей OLED 0.96″ I2C |
5V | VDD |
GND | GND |
SCL1 | SCK |
SDA1 | SDA |
Таблица 3. Подключение дисплея OLED 0.96″ I2C к макетной плате.
4.2. Результат подключения будет выглядеть следующим образом, см. рисунок 9.
5. Аналогично пункту 3 выполним проверку подключения устройства.
5.1. Если ранее не устанавливали все зависимости командой setup-all, то установим зависимости для дисплей модуля, выполнив:
make setup-OLED-SSD1306
5.2. Запустим python скрипт:
make OLED-SSD1306
5.3. Из рисунка 10 видим, что скрипт успешно выполнился, тестовый текст появился на дисплее.
6. Подключение четырехконтактного светодиодного RGB модуля (RGB LED)
Обратимся к рисункам 5 и 6. Из них видно, что устройство подключается через GPIO17, GPIO27, GPIO22.
6.1. Подключим RGB LED к макетной плате согласно таблице 4:
Макетная плата | RGB LED |
GPIO23 | R |
GPIO24 | G |
GPIO25 | B |
GND | GND |
Таблица 4. Подключение RGB LED к макетной плате.
6.2. Результат подключения будет выглядеть следующим образом, см. рисунок 11.
7. Выполним проверку подключения модуля.
7.1. Если ранее не устанавливали все зависимости командой setup-all, то установим зависимости для RGB модуля, выполнив:
make setup-rgb-led
7.2. Запустим python скрипт:
make rgb-led
7.2.1. Если нет никакой реакции или появляется ошибка, то проверьте номер GPIO указанный в скрипте по пути devices/input-output/RGB_led_example/py.
PIN_R = 111 # Красный — GPIO17
PIN_G = 112 # Зелёный — GPIO27
PIN_B = 113 # Синий — GPIO22
7.2.2. Как видно из скрипта, для управления RGB-светодиодом используются уникальные числовые идентификаторы GPIO-портов, отличающиеся от стандартных номеров выводов. Чтобы правильно соотнести номера GPIO с их фактическими идентификаторами, обратимся к пособию УМК “REPKA”, в котором приведена подробная распиновка одноплатного компьютера Repka Pi 4 (см. рисунок 12).
Согласно этой распиновке, порты GPIO 23, GPIO 24 и GPIO 25 имеют следующие уникальные идентификаторы:
GPIO 23 — 354
GPIO 24 — 355
GPIO 25 — 359
7.2.3. Внесем правки в код и выполним скрипт.
PIN_R = 354 # Красный — GPIO17
PIN_G = 355 # Зелёный — GPIO27
PIN_B = 359 # Синий — GPIO22
7.3. Если все подключено верно, то в консоли появится выбор работы программы, см. рисунок 13.
7.4. Выберем только зеленый цвет и оценим результат, см. рисунок 14.
Запуск проекта
Теперь, когда все компоненты подключены, можно запустить проект "Детектор звука". Для этого в репозитории repka-pi_iot-examples выполняем команду:
make volume-detector
После запуска программы на OLED-дисплее отображается текущее цифровое значение, полученное с микрофона. По мере увеличения уровня громкости это значение возрастает, что сопровождается изменением цвета RGB-светодиода в соответствии с заданными порогами. Таким образом, пользователь может одновременно наблюдать как числовой уровень звука, так и его визуальную индикацию, см. рисунок 15.
Вы можете собрать более бюджетную версию данного проекта.
Для более бюджетной реализации проекта можно обойтись без активного охлаждения, используя Repka Pi 4 в стандартной комплектации, а также макетную плату без внешнего источника питания — при этом остальные компоненты остаются неизменными.
Для подключения нам потребуется “Распиновка портов на 40 pin разъёме на Repka Pi 4“, см. рисунок 12.
Поскольку расширительная плата GPIO полностью повторяет конфигурацию распиновки, можно применить те же таблицы и схемы, которые использовались ранее для устройств:
8. Подключим АЦП (ADS1115) к макетной плате согласно таблице 1:
9. Подключаем микрофон к к макетной плате согласно таблице 2:
Проверка подключения микрофона осуществляется аналогично пункту 3.
10. Выполним подключение OLED дисплея согласно таблице 3:
Проверка подключения дисплея осуществляется аналогично пункту 5.
11. Подключим RGB LED к макетной плате согласно таблице 4:
Проверка подключения RGB осуществляется аналогично пункту 7.
Для снижения нагрузки на линию 5 В одноплатного компьютера Repka Pi 4, рекомендуется использовать дополнительное питание 5 В:
А. Подключение с использованием лабораторного блока питания:
Б. Подключение с использованием аккумуляторного блока питания:
Разбор кода проекта.
Проект реализован на языке python. Для того чтобы понять логику работы программы рассмотрите блок схему ниже:
Код импортирует библиотеки для работы с I2C, GPIO, OLED-дисплеем, изображениями, шрифтами и временем.
Далее инициализируются:
-
I2C-шина для связи с АЦП ADS1115 (микрофон)
-
GPIO-пины для управления RGB-светодиодом
-
OLED-дисплей (через I2C)
-
Объекты для рисования на экране и шрифт для текста
from periphery import I2C, GPIO
from luma.core.interface.serial import i2c
from luma.oled.device import sh1106
from PIL import Image, ImageDraw, ImageFont
import time
# Создаем объект для работы с шиной I2C (указан порт "/dev/i2c-1" для Repka PI)
i2c_bus = I2C("/dev/i2c-1")
# Адрес устройства ADS1115 на шине I2C (по умолчанию 0x48)
ADS1115_ADDR = 0x48
# Номера GPIO пинов для подключения RGB светодиода
PIN_R = 354 # Красный (GPIO17)
PIN_G = 355 # Зеленый (GPIO27)
PIN_B = 359 # Синий (GPIO22)
# Инициализация OLED дисплея с адресом 0x3C через интерфейс I2C
serial = i2c(port=1, address=0x3C) # Используем порт I2C 1 и адрес дисплея 0x3C
device = sh1106(serial) # Создаем объект устройства sh1106 для управления дисплеем
# Создаем новое изображение (черно-белое), которое будет отображаться на дисплее
image = Image.new("1", device.size) # "1" — это черно-белое изображение
draw = ImageDraw.Draw(image) # Объект для рисования на изображении
# Загружаем шрифт, который будет использоваться для текста на дисплее
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 8)
# Инициализация пинов GPIO для RGB светодиода
R = GPIO(PIN_R, "out") # Красный пин, настроен как выход
G = GPIO(PIN_G, "out") # Зеленый пин, настроен как выход
B = GPIO(PIN_B, "out") # Синий пин, настроен как выход
Функция read_mic()
Считывает аналоговый сигнал с микрофона через ADS1115 по I2C:
-
Отправляет конфигурацию на ADS1115 для начала измерения
-
Читает два байта данных с регистра результата
-
Преобразует их в 16-битное целое число (с учетом знака)
-
Возвращает уровень громкости
# Функция для чтения данных с микрофона, подключенного к ADS1115 через I2C
def read_mic():
# Конфигурация для ADS1115
config = 0xC183 # 16-битное значение для настройки входа AIN0 и других параметров
# Отправляем конфигурацию на ADS1115 для начала измерения
i2c_bus.transfer(ADS1115_ADDR, [I2C.Message([0x01, (config >> 8) & 0xFF, config & 0xFF])])
# Читаем данные с регистра 0x00 (результаты измерений)
i2c_bus.transfer(ADS1115_ADDR, [I2C.Message([0x00])])
read = I2C.Message([0x00, 0x00], read=True) # Читаем два байта данных
i2c_bus.transfer(ADS1115_ADDR, [read])
# Преобразуем два байта в одно 16-битное число
raw = (read.data[0] << 8) | read.data[1]
# Если число отрицательное (16-битный формат со знаком), преобразуем его
if raw & 0x8000:
raw -= 1 << 16
return raw # Возвращаем значение громкости
Функция control_rgb_based_on_volume(volume)
В зависимости от уровня громкости включает определённый цвет на RGB-светодиоде:
-
Красный — громко (volume > 9000)
-
Зелёный — средне (volume > 8000)
-
Синий — тише (volume > 4000)
-
Всё выключено — очень тихо
# Функция для управления RGB светодиодом в зависимости от громкости звука
def control_rgb_based_on_volume(volume):
# Включаем красный цвет, если громкость слишком высокая
if volume > 9000:
R.write(True)
G.write(False)
B.write(False)
# Включаем зеленый цвет для среднего уровня громкости
elif volume > 8000:
R.write(False)
G.write(True)
B.write(False)
# Включаем синий цвет для низкой громкости
elif volume > 4000:
R.write(False)
G.write(False)
B.write(True)
else:
# Если громкость ниже порога, выключаем светодиод
R.write(False)
G.write(False)
B.write(False)
Функция display_volume_on_oled(volume)
Очищает изображение, рисует текст с текущим значением громкости и выводит его на OLED-дисплей:
# Функция для отображения громкости на OLED дисплее
def display_volume_on_oled(volume):
# Очищаем дисплей (черный фон)
draw.rectangle((0, 0, device.width, device.height), outline=0, fill=0)
# Рисуем текст на дисплее, который будет показывать громкость
draw.text((0, 10), f"Громкость: {volume}", font=font, fill=255) # Текст белым цветом
# Отображаем изображение на дисплее
device.display(image)
Основной цикл программы
В бесконечном цикле:
-
Считывает уровень громкости с микрофона
-
Управляет цветом RGB-светодиода в зависимости от громкости
Отображает значение громкости на OLED-дисплее
# Основной цикл программы
try:
while True:
# Чтение значения с микрофона
val = read_mic()
# Управляем цветом RGB светодиода в зависимости от громкости
control_rgb_based_on_volume(val)
# Отображаем громкость на OLED дисплее
display_volume_on_oled(val)
Завершение работы (обработка KeyboardInterrupt)
При завершении программы (например, по Ctrl+C):
-
Очищает дисплей
-
Закрывает GPIO-пины светодиода
-
Закрывает интерфейс I2C
# Обработка исключения при выходе из программы (например, через Ctrl+C)
except KeyboardInterrupt:
# Очистка дисплея перед выходом
device.clear()
# Закрытие GPIO пинов
R.close()
G.close()
B.close()
# Закрытие интерфейса I2C
i2c_bus.close()
Пример кода выше с использованием ООП:
Класс MicrophoneADC
Отвечает за работу с микрофоном через АЦП ADS1115 по I2C.
-
init_: инициализирует I2C-шину и адрес АЦП.
-
read: отправляет конфигурацию на ADS1115, читает 16-битное значение с микрофона, возвращает уровень громкости.
-
close: закрывает I2C-шину.
# Класс для работы с микрофоном через ADS1115
class MicrophoneADC:
def __init__(self, i2c_dev="/dev/i2c-1", addr=0x48):
self.i2c_bus = I2C(i2c_dev)
self.addr = addr
def read(self):
# Конфигурация для ADS1115 (канал AIN0)
config = 0xC183
# Отправляем конфигурацию
self.i2c_bus.transfer(self.addr, [I2C.Message([0x01, (config >> 8) & 0xFF, config & 0xFF])])
# Читаем данные
self.i2c_bus.transfer(self.addr, [I2C.Message([0x00])])
read = I2C.Message([0x00, 0x00], read=True)
self.i2c_bus.transfer(self.addr, [read])
raw = (read.data[0] << 8) | read.data[1]
if raw & 0x8000:
raw -= 1 << 16
return raw
def close(self):
self.i2c_bus.close()
Класс RGBLed
Инкапсулирует управление RGB-светодиодом через три GPIO-пина.
-
init_: инициализирует пины для красного, зелёного и синего каналов.
-
set_color: включает/выключает каждый цвет по отдельности.
-
control_by_volume: включает определённый цвет в зависимости от уровня громкости (красный — громко, зелёный — средне, синий — тише, всё выключено — очень тихо).
-
close: освобождает все пины.
# Класс для управления RGB светодиодом
class RGBLed:
def __init__(self, pin_r=354, pin_g=355, pin_b=359):
self.R = GPIO(pin_r, "out")
self.G = GPIO(pin_g, "out")
self.B = GPIO(pin_b, "out")
def set_color(self, r=False, g=False, b=False):
self.R.write(r)
self.G.write(g)
self.B.write(b)
def control_by_volume(self, volume):
# Управление цветом в зависимости от громкости
if volume > 9000:
self.set_color(r=True, g=False, b=False) # Красный
elif volume > 8000:
self.set_color(r=False, g=True, b=False) # Зеленый
elif volume > 4000:
self.set_color(r=False, g=False, b=True) # Синий
else:
self.set_color(r=False, g=False, b=False) # Выключено
def close(self):
self.R.close()
self.G.close()
self.B.close()
Класс OLEDDisplay
Отвечает за вывод информации на OLED-дисплей.
-
init_: инициализирует дисплей, создаёт изображение и объект для рисования, загружает шрифт.
-
display_volume: очищает изображение, рисует текст с текущей громкостью, выводит на дисплей.
-
clear: очищает дисплей.
# Класс для работы с OLED дисплеем
class OLEDDisplay:
def __init__(self, port=1, address=0x3C):
self.serial = i2c(port=port, address=address)
self.device = sh1106(self.serial)
self.image = Image.new("1", self.device.size)
self.draw = ImageDraw.Draw(self.image)
# Используем стандартный шрифт
self.font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 8)
def display_volume(self, volume):
# Очищаем экран
self.draw.rectangle((0, 0, self.device.width, self.device.height), outline=0, fill=0)
# Рисуем текст
self.draw.text((0, 10), f"Громкость: {volume}", font=self.font, fill=255)
self.device.display(self.image)
def clear(self):
self.device.clear()
Класс VolumeDetectorApp
Главный управляющий класс приложения.
-
init_: создаёт объекты для микрофона, светодиода и дисплея.
-
run: основной цикл работы.
В цикле:
-
Считывает громкость с микрофона.
-
Управляет цветом RGB-светодиода в зависимости от громкости.
-
Отображает громкость на OLED-дисплее.
При завершении (Ctrl+C) очищает дисплей и освобождает ресурсы.
# Главный класс приложения
class VolumeDetectorApp:
def __init__(self):
# Инициализация всех устройств
self.mic = MicrophoneADC()
self.led = RGBLed()
self.display = OLEDDisplay()
def run(self):
try:
while True:
# Считываем громкость с микрофона
volume = self.mic.read()
# Управляем светодиодом
self.led.control_by_volume(volume)
# Отображаем громкость на дисплее
self.display.display_volume(volume)
except KeyboardInterrupt:
# При завершении очищаем дисплей и освобождаем ресурсы
self.display.clear()
self.led.close()
self.mic.close()
Точка входа
Создаётся объект VolumeDetectorApp и запускается основной цикл приложения.
# Точка входа
if __name__ == "__main__":
# Запускаем приложение
app = VolumeDetectorApp()
app.run()
Преимущества ООП-подхода:
1. Модульность и повторное использование кода
В ООП каждая функциональная часть системы (например, работа с датчиком, реле, дисплеем) оформляется в виде отдельного класса.
Это позволяет легко переиспользовать эти классы в других проектах или расширять функциональность без переписывания кода.
Например, если потребуется добавить второй датчик или другой тип дисплея, можно просто создать новый класс или унаследовать существующий.
2. Упрощение поддержки и масштабирования
Код, разделённый на классы с чётко определённой ответственностью, проще читать, тестировать и отлаживать.
Если возникает ошибка или требуется доработка, достаточно изменить только соответствующий класс, не затрагивая остальной код.
Это особенно важно для сложных или развивающихся проектов, где часто появляются новые требования.
3. Инкапсуляция и защита данных
ООП позволяет скрыть внутренние детали реализации (например, работу с I2C или обработку ошибок) внутри класса.
Внешний код работает только с публичными методами, не заботясь о низкоуровневых деталях.
Это снижает вероятность ошибок, связанных с неправильным использованием компонентов, и делает интерфейс системы более понятным и безопасным.
Практическая значимость проекта
Проект "Детектор звука" имеет практическую значимость как в образовательной, так и в прикладной сфере. Его можно использовать для мониторинга уровня шума в помещениях, таких как классы, библиотеки, офисы или дома, где важно поддерживать акустический комфорт. Устройство может стать частью системы умного дома — например, включать свет или подавать сигнал при обнаружении громкого звука.
Также проект может применяться в системах безопасности, где резкие звуки (например, хлопок или разбитие стекла) запускают сигнал тревоги. В быту он может быть полезен для контроля тишины в ночное время, особенно в многоквартирных домах.
Кроме того, такой детектор можно использовать для помощи людям с нарушением слуха, заменяя звуковые сигналы на визуальные с помощью RGB-подсветки. На производстве проект может применяться для контроля уровня шума и своевременного оповещения о превышении допустимых значений.
Таким образом, "Детектор звука" — это не только учебный проект, но и функциональное устройство, которое может найти применение в реальных жизненных ситуациях.
Расширение проекта
Проект “Детектор звука” может быть легко модифицирован и масштабирован в различных направлениях. Одним из возможных расширений является реализация системы звуковой сигнализации — например, добавление зуммера или сирены, срабатывающей при превышении заданного порога громкости.
Также возможно вести логирование уровня шума с сохранением данных во внешнюю память или отправкой их по сети (например, по Wi-Fi или Bluetooth), что превращает устройство в полноценную систему мониторинга акустической обстановки. Подключение модуля времени (RTC) позволит привязывать измерения к реальному времени.
Дополнительно можно реализовать графическое отображение истории изменений уровня звука на дисплее, визуализируя данные в виде столбиковой диаграммы или кривой.
Проект может быть расширен до многосенсорной платформы, включающей, помимо микрофона, датчики температуры, освещённости или движения — для построения комплексных систем "умной среды" или мониторинга окружающей среды.
Таким образом, “Детектор звука” не только выполняет учебные задачи, но и служит прочной основой для построения более сложных инженерных решений в рамках IoT и автоматизации.
Видеообзор проекта
Для более детального ознакомления с проектом, вы можете посмотреть видеообзор на платформе Rutube.
Пример использования с Python
Проект полностью реализован на языке Python. Код для работы с детектором звука можно найти в репозитории на платформе Gitflic.