В данной статье мы рассмотрим основные принципы работы датчика звука (sound sensor) KY-038 и его подключение к модулю ESP32, который является в настоящее время одним из самых популярных микроконтроллеров с поддержкой технологий WiFi и Bluetooth. Датчик KY-038 представляет собой микрофон конденсаторного типа, способный улавливать звуковые волны, и отличается надежностью и стабильностью работы. С минимальными усилиями вы можете превратить данный проект в какое-нибудь полезное для вас устройство: детектор звукового загрязнения, систему охранной сигнализации и т.п.
Ранее на нашем сайте мы рассматривали следующие проекты с использованием микрофона для обнаружения/измерения звука:
- шпионское подслушивающее устройство на Arduino с записью голоса;
- измерение уровня звука в децибелах с помощью Arduino и микрофона;
- музыкальный фонтан на Arduino и акустическом датчике;
- переключатель по хлопку на Arduino Uno.
Необходимые компоненты
- Модуль ESP32 (купить на AliExpress).
- Датчик звука KY-038 (купить на AliExpress).
- OLED дисплей, работающий по протоколу I2C (купить на AliExpress).
- Светодиоды (3 шт.) (купить на AliExpress).
- Резисторы (3 шт.) (купить на AliExpress).
Датчик звука KY-038
Распиновка датчика звука KY-038
Датчик KY-038 содержит 4 контакта: VCC, GND, цифровой выход (Digital Out) и аналоговый выход (Analog Out). Его распиновка показана на следующем рисунке.
Назначение контактов:
VCC – контакт для подачи питания на датчик, можно подключать к 3.3V или 5V. Уровень напряжения на аналоговом выходе будет зависеть от величины приложенного питающего напряжения.
GND – контакт общего провода (земли) датчика.
DOUT – цифровой выход датчика, низкий уровень означает что датчик не обнаруживает никакого звука, высокий – датчик обнаруживает присутствие звука.
AOUT – аналоговый выход датчика.
Как работает датчик звука KY-038
Основным компонентом датчика является конденсаторный микрофон, который формирует аналоговый сигнал при соприкосновении звуковых волн с его диафрагмой. Этот аналоговый сигнал затем обрабатывается с помощью операционного усилителя и, таким образом, на выходе датчика формируется цифровой сигнал. Принцип работы датчика звука KY-038 схематично показан на следующем рисунке.
Как вы можете видеть из представленного рисунка, конденсаторный микрофон состоит из двух заряженных металлических пластин. Первая пластина называется диафрагмой, а вторая – задней пластиной. Вместе они образуют конденсатор. Когда звуковая волна ударяется о диафрагму она начинает вибрировать и расстояние между двумя пластинами изменяется, что вызывает изменение емкости данного конденсатора. Это изменение емкости преобразуется в электрический сигнал, который затем обрабатывается встроенным в датчик операционным усилителем. Модуль датчика также содержит два встроенных светодиода, один из которых сигнализирует о подаче питания на датчик, а второй – о том, что улавливаемый датчиком звуковой сигнал превосходит определенную границу, устанавливаемую с помощью потенциометра.
Компоненты датчика звука KY-038
Модуль датчика звука KY-038 состоит из простых, дешевых и широко распространенных компонентов, что снискало ему заслуженную популярность среди радиолюбителей. Его компоненты показаны на следующем рисунке.
Модуль датчика содержит 4 контакта, 2 светодиода и компаратор на операционном усилителе, который служит для преобразования аналогового сигнала в цифровой. Также модуль датчика содержит потенциометр для регулировки его чувствительности и конденсаторный микрофон для обнаружения звуковых волн.
Наиболее часто задаваемые вопросы о датчике звука KY-038
Какие основные типы датчиков звука существуют?
Существуют датчики звука с использованием различных типов микрофонов: динамических, конденсаторных, ленточных, угольных и т.д.
Какие основные преимущества датчиков звука?
Датчики звука находят широкое применение в охранных системах, также часто они работают в связке с программами распознавания речи, которые преобразуют речь человека в текст. Во многих случаях это намного более быстрый способ набора текста по сравнению с использованием клавиатуры.
Какой диапазон действия у датчика звука?
Датчик способен обнаруживать звук с уровнем до 100 дБ с частотами в диапазоне от 3 до 6 кГц.
Схема датчика звука KY-038
Показана на следующем рисунке. Как видите, она очень проста и состоит из ограниченного набора компонентов.
Ключевым компонентом данной схемы является операционный усилитель LM393, который можно запитывать от 3.3V или 5V. Необходимо помнить о том, что уровень напряжения на аналоговом выходе датчика зависит от величины поданного на датчик питающего напряжения. Потенциометр используется для установки опорного напряжения для операционного усилителя и формирования опорного напряжения для аналогового выхода датчика.
Если входное напряжение датчика не превосходит границу, установленную потенциометром, то на выходе операционного усилителя будет низкий уровень. Если превосходит – то на цифровом выходе датчика будет сигнал высокого уровня и загорится сигнальный светодиод.
Схема проекта
Схема подключения датчика звука KY-038 к модулю ESP32 представлена на следующем рисунке.
Соединения в схеме очень простые, достаточно запитать модуль от 3.3V и подключить его аналоговый контакт к модулю ESP32. Обрабатывать аналоговый сигнал с выхода мы будем с помощью АЦП модуля ESP32. Также в схеме мы использовали 3 светодиода для индикации интенсивности звука, а измеренный уровень звука в децибелах мы будем отображать на экране OLED дисплея, который подключен к модулю ESP32 по интерфейсу I2C, более подробно об особенностях подобного подключения дисплея можно прочитать в этой статье.
Внешний вид собранной конструкции проекта показан на следующем рисунке.
Объяснение кода программы для модуля ESP32
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты. В коде программы мы будем считывать аналоговый сигнал с выхода конденсаторного микрофона и преобразовывать его в цифровой сигнал с помощью АЦП модуля ESP32.
Первым делом в коде программы мы подключим все необходимые нам библиотеки: Wire.h, Adafruit_GFX.h и Adafruit_SSD1306.h. Также зададим ширину и высоту экрана OLED дисплея в пикселях.
1 2 3 4 5 6 |
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) |
Затем объявим объект для работы с OLED дисплеем.
1 |
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); |
Далее объявим две переменные для хранения данных с выхода АЦП.
1 2 |
const int sampleWindow = 50; unsigned int sample; |
После этого дадим осмысленные имена всем используемым контактам.
1 2 3 4 |
#define SENSOR_PIN 35 #define PIN_QUIET 33 #define PIN_MODERATE 25 #define PIN_LOUD 26 |
Затем, в функции setup(), мы зададим режимы работы для всех используемых контактов. Также на все контакты, к которым подключены светодиоды, мы подадим уровень LOW, и инициализируем последовательную связь.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void setup(){ pinMode(SENSOR_PIN, INPUT); // Set the signal pin as input pinMode(PIN_QUIET, OUTPUT); pinMode(PIN_MODERATE, OUTPUT); pinMode(PIN_LOUD, OUTPUT); digitalWrite(PIN_QUIET, LOW); digitalWrite(PIN_MODERATE, LOW); digitalWrite(PIN_LOUD, LOW); Serial.begin(115200); if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F("SSD1306 allocation failed")); for (;;); // Don't proceed, loop forever } display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE); display.display(); digitalWrite(PIN_LOUD, LOW); } |
Далее, в функции loop, мы будем считывать данные с выхода АЦП и сохранять его в двух переменных (минимальный и максимальный уровень).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
unsigned long startMillis = millis(); // Start of sample window float peakToPeak = 0; // peak-to-peak level unsigned int signalMax = 0; //minimum value unsigned int signalMin = 1024; //maximum value // collect data for 50 mS while (millis() - startMillis < sampleWindow) { sample = analogRead(SENSOR_PIN); if (sample < 1024) { if (sample > signalMax) { signalMax = sample; } else if (sample < signalMin) { signalMin = sample; } } } |
После этого мы будем вычитать минимальное значение из максимального и преобразовывать полученную разность в диапазон от 49dB до 90dB и отображать его на экране дисплея.
1 2 3 4 5 6 7 8 9 |
peakToPeak = signalMax - signalMin; int db = map(peakToPeak, 0, 900, 49, 90); Serial.print("\t"); Serial.println(db); display.setCursor(0, 0); display.print("Loudness: "); display.print(db); display.print("dB"); digitalWrite(PIN_LOUD, LOW); |
Затем с помощью условий if мы будем проверять полученное значение и в зависимости от этого зажигать соответствующий светодиод, индицирующий интенсивность звука. Также мы будем выводить уровень интенсивности звука на экран дисплея (Moderate, High).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
else if (db > 60 && db < 85) { display.clearDisplay(); display.setCursor(0, 1); display.print("Level:Moderate"); display.display(); digitalWrite(PIN_QUIET, LOW); digitalWrite(PIN_MODERATE, HIGH); digitalWrite(PIN_LOUD, LOW); } else if (db >= 85 && db <= 90) { display.clearDisplay(); display.setCursor(0, 1); display.print("Level:High"); display.display(); digitalWrite(PIN_QUIET, LOW); digitalWrite(PIN_MODERATE, LOW); digitalWrite(PIN_LOUD, HIGH); } else { digitalWrite(PIN_QUIET, LOW); digitalWrite(PIN_MODERATE, LOW); digitalWrite(PIN_LOUD, LOW); } delay(200); } |
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // ширина OLED дисплея, в пикселях #define SCREEN_HEIGHT 64 // высота OLED дисплея, в пикселях #define OLED_RESET -1 // контакт сброса # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); const int sampleWindow = 50; unsigned int sample; #define SENSOR_PIN 35 #define PIN_QUIET 33 #define PIN_MODERATE 25 #define PIN_LOUD 26 void setup(){ pinMode(SENSOR_PIN, INPUT); pinMode(PIN_QUIET, OUTPUT); pinMode(PIN_MODERATE, OUTPUT); pinMode(PIN_LOUD, OUTPUT); digitalWrite(PIN_QUIET, LOW); digitalWrite(PIN_MODERATE, LOW); digitalWrite(PIN_LOUD, LOW); Serial.begin(115200); if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F("SSD1306 allocation failed")); for (;;); } display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE); display.display(); digitalWrite(PIN_LOUD, LOW); } void loop() { unsigned long startMillis = millis(); float peakToPeak = 0; unsigned int signalMax = 0; unsigned int signalMin = 1024; // collect data for 50 mS while (millis() - startMillis < sampleWindow) { sample = analogRead(SENSOR_PIN); if (sample < 1024) { if (sample > signalMax) { signalMax = sample; } else if (sample < signalMin) { signalMin = sample; } } } peakToPeak = signalMax - signalMin; int db = map(peakToPeak, 0, 900, 49, 90); Serial.print("\t"); Serial.println(db); display.setCursor(0, 0); display.print("Loudness: "); display.print(db); display.print("dB"); digitalWrite(PIN_LOUD, LOW); if (db <= 55) { display.clearDisplay(); display.setCursor(0, 1); display.print("Level:Quite"); display.display(); digitalWrite(PIN_QUIET, HIGH); digitalWrite(PIN_MODERATE, LOW); digitalWrite(PIN_LOUD, LOW); // delay(3000); } else if (db > 60 && db < 85) { display.clearDisplay(); display.setCursor(0, 1); display.print("Level:Moderate"); display.display(); digitalWrite(PIN_QUIET, LOW); digitalWrite(PIN_MODERATE, HIGH); digitalWrite(PIN_LOUD, LOW); } else if (db >= 85 && db <= 90) { display.clearDisplay(); display.setCursor(0, 1); display.print("Level:High"); display.display(); digitalWrite(PIN_QUIET, LOW); digitalWrite(PIN_MODERATE, LOW); digitalWrite(PIN_LOUD, HIGH); } else { digitalWrite(PIN_QUIET, LOW); digitalWrite(PIN_MODERATE, LOW); digitalWrite(PIN_LOUD, LOW); } delay(200); } |