Cirkit Designer LogoCirkit DesignerYour all-in-one circuit design IDE Launch Cirkit Designer App

ESP32-Based Audio Frequency Analyzer with I2C LCD Display and Pushbutton Control

View and Edit Project In Cirkit DesignerImage of ESP32-Based Audio Frequency Analyzer with I2C LCD Display and Pushbutton Control

Circuit Documentation

Summary

This document provides a detailed overview of a circuit that includes an ESP32 microcontroller, an INMP441 microphone, a 16x2 I2C LCD, and a pushbutton. The circuit is designed to record audio, perform FFT analysis, and display the highest frequency detected on the LCD. The pushbutton is used to start and stop the recording process.

Component List

  1. INMP441 FRONT MIC

    • Description: A high-performance, low-power, digital-output, omnidirectional MEMS microphone.
    • Pins: L/R, WS, SCK, SD, VDD, GND
  2. 16x2 I2C LCD

    • Description: A 16x2 character LCD display with I2C interface.
    • Pins: GND, VCC, SDA, SCL
  3. ESP32 Wroom

    • Description: A powerful, generic Wi-Fi+BT+BLE MCU module that targets a wide variety of applications.
    • Pins: 2 (3V3), 3 (Reset), 4 (GPIO36), 5 (GPIO39), 6 (GPIO34), 7 (GPIO35), 8 (GPIO32), 9 (GPIO33), 10 (GPIO25), 11 (GPIO26), 12 (GPIO27), 13 (GPIO14), 14 (GPIO12), GND, 16 (GPIO13), 17 (GPIO9), 18 (GPIO10), 19 (GPIO11), 5V, 37 (GPIO23), 36 (GPIO22/SCL), 35 (GPIO1/TXD0), 34 (GPIO3/RXD0), 33 (GPIO21/SDA), 31 (GPIO19), 30 (GPIO18), 29 (GPIO5), 28 (GPIO17), 27 (GPIO16), 26 (GPIO4), 25 (GPIO0), 24 (GPIO2), 23 (GPIO15), 22 (GPIO8), 21 (GPIO7), 20 (GPIO6)
  4. Pushbutton

    • Description: A simple pushbutton used for user input.
    • Pins: Pin 2, Pin 1, Pin 3, Pin 4

Wiring Details

INMP441 FRONT MIC

16x2 I2C LCD

ESP32 Wroom

Pushbutton

Code Documentation

#include <arduinoFFT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <driver/i2s.h>

// Pin configuration for I2S
#define I2S_BCK_PIN 26  // Bit Clock (SCK)
#define I2S_WS_PIN 25   // Word Select (WS)
#define I2S_DOUT_PIN 33 // Data Output (SO)

// Button configuration
#define BUTTON_PIN 14    // GPIO pin for button
#define DEBOUNCE_DELAY 50 // Debounce delay in milliseconds

// LCD configuration
LiquidCrystal_I2C lcd(0x27, 16, 2);

// FFT configuration
#define SAMPLES 1024
#define SAMPLING_FREQUENCY 16000

float vReal[SAMPLES];
float vImag[SAMPLES];
ArduinoFFT<float> FFT = ArduinoFFT<float>(vReal, vImag, SAMPLES, SAMPLING_FREQUENCY);

int32_t samples[SAMPLES];
size_t bytes_read;
bool isRecording = false;
float highestFrequency = 0;
unsigned long lastButtonPressTime = 0;
bool buttonState = false; // Stores the last known state of the button

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.print("Initializing...");
  delay(2000);
  lcd.clear();

  // Configure button pin with internal pull-up
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  i2s_config_t i2s_config = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = SAMPLING_FREQUENCY,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = I2S_COMM_FORMAT_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8,
    .dma_buf_len = 64
  };

  i2s_pin_config_t pin_config = {
    .bck_io_num = I2S_BCK_PIN,
    .ws_io_num = I2S_WS_PIN,
    .data_out_num = -1,
    .data_in_num = I2S_DOUT_PIN
  };

  i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
  i2s_set_pin(I2S_NUM_0, &pin_config);
}

void loop() {
  bool currentButtonState = digitalRead(BUTTON_PIN) == LOW;

  // Debounce logic
  if (currentButtonState && !buttonState && (millis() - lastButtonPressTime > DEBOUNCE_DELAY)) {
    buttonState = true;
    lastButtonPressTime = millis();
    
    if (!isRecording) {
      isRecording = true;
      highestFrequency = 0;
      unsigned long startTime = millis();
      lcd.clear();
      lcd.print("Recording...");

      while (millis() - startTime < 3000) {
        recordFrequency();
      }

      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Highest Freq:");
      lcd.setCursor(0, 1);
      lcd.print(highestFrequency, 2);
      lcd.print(" Hz");
    } else {
      isRecording = false;
      lcd.clear();
      lcd.print("Click to show");
      lcd.setCursor(0, 1);
      lcd.print("frequency");
    }
  }

  if (!currentButtonState) {
    buttonState = false;
  }
}

void recordFrequency() {
  i2s_read(I2S_NUM_0, samples, sizeof(samples), &bytes_read, portMAX_DELAY);

  // Convert samples to float values for FFT processing
  for (int i = 0; i < SAMPLES; i++) {
    vReal[i] = (float)(samples[i] >> 8);  // Shift the sample data to remove noise
    vImag[i] = 0;  // No imaginary component for real signals
  }

  // Apply windowing function and compute FFT
  FFT.windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.complexToMagnitude(vReal, vImag, SAMPLES);

  // Find the major peak in the FFT output
  float currentFrequency = FFT.majorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);

  // Update highest frequency if the current frequency is higher
  if (currentFrequency > highestFrequency) {
    highestFrequency = currentFrequency;
  }
}

This code initializes the LCD, configures the I2S interface for the microphone, and sets up the pushbutton with a debounce mechanism. The main loop checks the button state