Untuk tahap pertama, saya sarankan fokus pada pembacaan suara dan visualisasi gelombang (waveform) terlebih dahulu. Setelah berhasil, baru kita tambahkan filter suara jantung, penguatan sinyal, dan penghitungan BPM.
1. Konsep sistem
INMP441
Menangkap getaran suara melalui mikrofon digital I2S
ESP32
Membaca sampel suara dan mengolahnya menjadi data gelombang
LCD ST77916
Menampilkan gelombang suara secara langsung
LCD ST77916 berukuran 1,53 inci umumnya memiliki resolusi 360 × 360 piksel dan menggunakan antarmuka QSPI, bukan SPI standar. Ini penting karena pemilihan library harus sesuai dengan antarmuka LCD.
2. Library yang diperlukan
Library / Board Package | Fungsi |
|---|---|
ESP32 by Espressif Systems | Board package Arduino untuk ESP32 |
GFX Library for Arduino | Mengendalikan LCD ST77916 dan menggambar gelombang |
driver/i2s.h | Membaca suara INMP441 menggunakan I2S |
Library grafis yang kita gunakan adalah Arduino_GFX karena menyediakan kelas Arduino_ST77916 dan Arduino_ESP32QSPI.
Untuk instalasi, buka Arduino IDE → Tools → Board → Boards Manager, kemudian instal esp32 by Espressif Systems. Selanjutnya buka Sketch → Include Library → Manage Libraries, cari GFX Library for Arduino dan instal.
driver/i2s.h sudah disediakan oleh board package ESP32, sehingga tidak memerlukan library mikrofon tambahan.
3. Wiring ESP32 ke INMP441
Contoh ini menggunakan ESP32 DevKit V1 / ESP32-WROOM-32. Jika Anda menggunakan ESP32-S3, pin perlu disesuaikan.
Pin INMP441 | Pin ESP32 |
|---|---|
VDD | 3V3 |
GND | GND |
SCK | GPIO 26 |
WS | GPIO 25 |
SD | GPIO 33 |
L/R | GND |
INMP441 menggunakan komunikasi I2S dengan resolusi data 24-bit. Menghubungkan L/R ke GND memilih kanal kiri. Jangan menghubungkan VDD INMP441 ke 5V.
Tujuan:
- memastikan I2S bekerja
- melihat level suara
Program:
Sintaks:
#include <Arduino.h> #include <driver/i2s.h> #define I2S_WS 25 #define I2S_SCK 26 #define I2S_SD 33 #define SAMPLE_RATE 16000 int32_t samples[256]; void setup() { Serial.begin(115200); i2s_config_t i2s_config = { .mode = (i2s_mode_t) ( I2S_MODE_MASTER | I2S_MODE_RX ), .sample_rate = SAMPLE_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = 0, .dma_buf_count = 4, .dma_buf_len = 256, .use_apll = false }; i2s_pin_config_t pin_config = { .bck_io_num = I2S_SCK, .ws_io_num = I2S_WS, .data_out_num = -1, .data_in_num = I2S_SD }; i2s_driver_install( I2S_NUM_0, &i2s_config, 0, NULL ); i2s_set_pin( I2S_NUM_0, &pin_config ); Serial.println("INMP441 READY"); } void loop() { size_t bytes_read; i2s_read( I2S_NUM_0, samples, sizeof(samples), &bytes_read, portMAX_DELAY ); int sample_count = bytes_read / sizeof(int32_t); long sum=0; for(int i=0;i<sample_count;i++) { int32_t sample = samples[i] >> 14; sum += abs(sample); } int level = sum/sample_count; Serial.println(level); delay(100); }
4. Wiring ESP32 ke LCD ST77916
Untuk modul LCD ST77916 tipe QSPI 11-pin:
Pin LCD | Pin ESP32 |
|---|---|
VCC | 3V3 |
GND | GND |
SCL / CLK | GPIO 18 |
SDA / IO0 | GPIO 23 |
IO1 | GPIO 19 |
IO2 | GPIO 21 |
IO3 | GPIO 22 |
CS | GPIO 5 |
RST | GPIO 17 |
BL | GPIO 16 |
TE | Tidak digunakan |
Susunan ini merupakan contoh pemetaan GPIO, bukan pin bawaan wajib modul. Pastikan label pada LCD sesuai dan modul menerima suplai 3,3V.
Test LCD Bisa Menggunakan Program Ini :
Sintaks:
#include <Arduino_GFX_Library.h> // ======================= // WARNA RGB565 // ======================= #define BLACK 0x0000 #define WHITE 0xFFFF #define RED 0xF800 #define GREEN 0x07E0 #define BLUE 0x001F #define YELLOW 0xFFE0 // ======================= // PIN LCD ST77916 QSPI // ======================= #define LCD_CS 5 #define LCD_SCK 18 #define LCD_D0 23 // SDA #define LCD_D1 19 // IO1 #define LCD_D2 21 // IO2 #define LCD_D3 22 // IO3 #define LCD_RST 17 #define LCD_BL 16 // ======================= // QSPI BUS // ======================= Arduino_DataBus *bus = new Arduino_ESP32QSPI( LCD_CS, LCD_SCK, LCD_D0, LCD_D1, LCD_D2, LCD_D3 ); // ======================= // LCD DRIVER // ======================= Arduino_GFX *gfx = new Arduino_ST77916( bus, LCD_RST, 0, // rotation false, // inversion 360, 360 ); void lcdReset() { pinMode(LCD_RST, OUTPUT); digitalWrite(LCD_RST,HIGH); delay(100); digitalWrite(LCD_RST,LOW); delay(100); digitalWrite(LCD_RST,HIGH); delay(300); } void setup() { Serial.begin(115200); Serial.println("Start LCD ST77916"); // Backlight pinMode(LCD_BL,OUTPUT); digitalWrite(LCD_BL,HIGH); // Reset LCD lcdReset(); // Init LCD if(!gfx->begin()) { Serial.println("LCD INIT FAILED"); while(1) { delay(1000); } } Serial.println("LCD OK"); // TEST WARNA gfx->fillScreen(RED); delay(1000); gfx->fillScreen(GREEN); delay(1000); gfx->fillScreen(BLUE); delay(1000); gfx->fillScreen(BLACK); // TEST TEXT gfx->setTextColor(WHITE); gfx->setTextSize(3); gfx->setCursor(55,140); gfx->println("ST77916"); gfx->setTextSize(2); gfx->setCursor(90,190); gfx->println("ESP32 TEST"); gfx->drawCircle( 180, 180, 170, YELLOW ); } void loop() { }#include <Arduino_GFX_Library.h>// ======================= // WARNA RGB565 // ======================= #define BLACK 0x0000 #define WHITE 0xFFFF #define RED 0xF800 #define GREEN 0x07E0 #define BLUE 0x001F #define YELLOW 0xFFE0 // ======================= // PIN LCD ST77916 QSPI // ======================= #define LCD_CS 5 #define LCD_SCK 18 #define LCD_D0 23 // SDA #define LCD_D1 19 // IO1 #define LCD_D2 21 // IO2 #define LCD_D3 22 // IO3 #define LCD_RST 17 #define LCD_BL 16 // ======================= // QSPI BUS // ======================= Arduino_DataBus *bus = new Arduino_ESP32QSPI( LCD_CS, LCD_SCK, LCD_D0, LCD_D1, LCD_D2, LCD_D3 ); // ======================= // LCD DRIVER // ======================= Arduino_GFX *gfx = new Arduino_ST77916( bus, LCD_RST, 0, // rotation false, // inversion 360, 360 ); void lcdReset() { pinMode(LCD_RST, OUTPUT); digitalWrite(LCD_RST,HIGH); delay(100); digitalWrite(LCD_RST,LOW); delay(100); digitalWrite(LCD_RST,HIGH); delay(300); } void setup() { Serial.begin(115200); Serial.println("Start LCD ST77916"); // Backlight pinMode(LCD_BL,OUTPUT); digitalWrite(LCD_BL,HIGH); // Reset LCD lcdReset(); // Init LCD if(!gfx->begin()) { Serial.println("LCD INIT FAILED"); while(1) { delay(1000); } } Serial.println("LCD OK"); // TEST WARNA gfx->fillScreen(RED); delay(1000); gfx->fillScreen(GREEN); delay(1000); gfx->fillScreen(BLUE); delay(1000); gfx->fillScreen(BLACK); // TEST TEXT gfx->setTextColor(WHITE); gfx->setTextSize(3); gfx->setCursor(55,140); gfx->println("ST77916"); gfx->setTextSize(2); gfx->setCursor(90,190); gfx->println("ESP32 TEST"); gfx->drawCircle( 180, 180, 170, YELLOW ); } void loop() { }
5. Program Arduino lengkap
Program berikut membaca mikrofon, menghitung tingkat sinyal RMS, lalu menampilkan grafik bergerak pada LCD. Grafik ini adalah amplitudo suara terhadap waktu, belum gelombang suara mentah atau hasil pengukuran detak jantung.
Kode Program ESP32 + INM441+ LCD LCD ST77916:
#include <Arduino.h>
#include <Arduino_GFX_Library.h>
#include <driver/i2s.h>
#include <math.h>
// ===== LCD ST77916 QSPI =====
#define LCD_CS 5
#define LCD_SCK 18
#define LCD_D0 23
#define LCD_D1 19
#define LCD_D2 21
#define LCD_D3 22
#define LCD_RST 17
#define LCD_BL 16
// ===== INMP441 I2S =====
#define MIC_SCK 26
#define MIC_WS 25
#define MIC_SD 33
#define SAMPLE_RATE 16000
#define SAMPLES 256
#define BLACK 0x0000
#define WHITE 0xFFFF
#define GREEN 0x07E0
#define GRAY 0x4208
Arduino_DataBus *bus = new Arduino_ESP32QSPI(
LCD_CS, LCD_SCK,
LCD_D0, LCD_D1, LCD_D2, LCD_D3
);
Arduino_GFX *gfx = new Arduino_ST77916(
bus, LCD_RST, 0, true, 360, 360
);
int32_t audioBuffer[SAMPLES];
int graphX = 70;
int previousY = 210;
float smoothLevel = 0;
void setupMicrophone() {
i2s_config_t config = {};
config.mode = (i2s_mode_t)(
I2S_MODE_MASTER | I2S_MODE_RX
);
config.sample_rate = SAMPLE_RATE;
config.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT;
config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
config.communication_format = I2S_COMM_FORMAT_STAND_I2S;
config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
config.dma_buf_count = 4;
config.dma_buf_len = SAMPLES;
config.use_apll = false;
i2s_pin_config_t pins = {};
pins.mck_io_num = I2S_PIN_NO_CHANGE;
pins.bck_io_num = MIC_SCK;
pins.ws_io_num = MIC_WS;
pins.data_out_num = I2S_PIN_NO_CHANGE;
pins.data_in_num = MIC_SD;
esp_err_t result =
i2s_driver_install(I2S_NUM_0, &config, 0, NULL);
if (result != ESP_OK) {
Serial.println("Gagal mengaktifkan I2S");
while (true) delay(1000);
}
i2s_set_pin(I2S_NUM_0, &pins);
}
void setupDisplay() {
pinMode(LCD_BL, OUTPUT);
digitalWrite(LCD_BL, HIGH);
if (!gfx->begin()) {
Serial.println("LCD gagal diinisialisasi");
while (true) delay(1000);
}
gfx->fillScreen(BLACK);
gfx->drawCircle(180, 180, 178, GRAY);
gfx->setTextColor(WHITE);
gfx->setTextSize(2);
gfx->setCursor(100, 75);
gfx->print("STETOSKOP");
gfx->setTextSize(1);
gfx->setCursor(123, 105);
gfx->print("AUDIO MONITOR");
gfx->drawFastHLine(70, 210, 220, GRAY);
}
float readSoundLevel() {
size_t bytesRead = 0;
esp_err_t result = i2s_read(
I2S_NUM_0,
audioBuffer,
sizeof(audioBuffer),
&bytesRead,
pdMS_TO_TICKS(100)
);
if (result != ESP_OK || bytesRead == 0) {
return 0;
}
int count = bytesRead / sizeof(int32_t);
double sum = 0;
double sumSquare = 0;
for (int i = 0; i < count; i++) {
// Konversi slot 32-bit ke sampel sekitar 16-bit
int32_t sample = audioBuffer[i] >> 16;
sum += sample;
sumSquare += (double)sample * sample;
}
double mean = sum / count;
double variance = sumSquare / count - mean * mean;
double rms = sqrt(fmax(variance, 0.0));
// dBFS relatif terhadap rentang 16-bit
float dbFS = 20.0f * log10f((rms + 0.01f) / 32768.0f);
// Skala visual percobaan, bukan dB SPL
float level = (dbFS + 70.0f) * (100.0f / 60.0f);
return constrain(level, 0.0f, 100.0f);
}
void drawGraph(float level) {
smoothLevel = smoothLevel * 0.7f + level * 0.3f;
int y = 210 - (int)(smoothLevel * 60.0f / 100.0f);
// Hapus satu kolom grafik lama
gfx->drawFastVLine(graphX, 140, 72, BLACK);
gfx->drawPixel(graphX, 210, GRAY);
if (graphX > 70) {
gfx->drawLine(
graphX - 1, previousY,
graphX, y,
GREEN
);
} else {
gfx->drawPixel(graphX, y, GREEN);
}
previousY = y;
graphX++;
if (graphX >= 290) {
graphX = 70;
previousY = y;
}
// Tampilkan level suara
gfx->fillRect(105, 250, 150, 22, BLACK);
gfx->setTextSize(2);
gfx->setTextColor(WHITE);
gfx->setCursor(110, 252);
gfx->printf("LEVEL %3d", (int)smoothLevel);
}
void setup() {
Serial.begin(115200);
delay(500);
setupDisplay();
setupMicrophone();
Serial.println("Stetoskop digital siap");
}
void loop() {
float level = readSoundLevel();
drawGraph(level);
static unsigned long lastPrint = 0;
if (millis() - lastPrint >= 200) {
lastPrint = millis();
Serial.print("Level: ");
Serial.println(level, 1);
}
}




