В данной статье мы рассмотрим основные принципы работы датчика звука (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).
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Датчик звука 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); } |
После слов что lm393 операционный усилитель перестал читать. lm393 - компаратор!!!
Компаратор на основе операционного усилителя. Продолжайте чтение ))
Здравствуйте. подскажите плиз, зачем нужно условие
if (sample < 1024)
Разве функция analogRead может выдать значение больше 1024?
Также поясните плиз строку
int db = map(peakToPeak, 0, 900, 49, 90);
Почему именно 900?
Добрый вечер, у модуля ESP32 разрядность АЦП составляет 12 бит, а не 10 как у платы Ардуино Уно, поэтому и диапазон значений на его выходе составляет от 0 до 4095. Значение 900 получается в результате вычитания минимального значения из максимального, точнее это максимально возможная разница между этими значениями. Возможно, она определена автором проекта экспериментально
Извините, все равно не понимаю. Если максимальное значение, которое может выдать функция analogRead на ESP32 составляет 4095, то почему считанное значение сравнивается с 1024...? А если analogRead выдаст больше 1024 - то что?
Это будет свидетельствовать об очень громком звуке, который в программе мы не будем обрабатывать