Komponen · 16 mnt baca

Sensor Detak Jantung Arduino: Panduan BPM dengan Pulse Sensor dan KY-039

Panduan sensor detak jantung Arduino: pengkabelan Pulse Sensor dan KY-039, BPM dengan PulseSensorPlayground, gelombang nadi di Serial Plotter, OLED, serta kode ESP32 dan Pico.

Sensor detak jantung Arduino, yang juga disebut sensor denyut nadi, adalah modul kecil yang mengikuti aliran darah di ujung jari atau daun telingamu dengan cahaya dan mengukur berapa kali jantungmu berdetak dalam satu menit, yaitu BPM (beats per minute). Dua model yang paling sering dipakai di dunia elektronika hobi adalah Pulse Sensor yang berbentuk bulat dan KY-039 dengan LED inframerah. Keduanya dihubungkan dengan tiga kabel dan dibaca dari satu pin analog, tetapi kualitas sinyalnya dan tingkat kesulitan menulis kode yang andal untuk keduanya sangat berbeda.

Di panduan ini kamu akan belajar langkah demi langkah prinsip fisika apa yang dipakai sensor detak jantung, cara melihat gelombang nadi sungguhan di Serial Plotter, cara menghitung BPM dengan library PulseSensorPlayground, cara mengolah sinyal KY-039 yang lemah dengan algoritma tanpa library, dan cara menampilkan hasilnya di layar OLED lengkap dengan ikon hati. Kode ESP32 dan Raspberry Pi Pico, faktor-faktor yang merusak pengukuran, dan perbedaannya dengan MAX30102 juga dibahas. Satu catatan penting sejak awal: sensor-sensor ini bukan alat medis dan tidak boleh dipakai untuk keputusan apa pun yang berkaitan dengan kesehatan.

Sensor detak jantung Pulse Sensor dengan kabel penghubung
Modul Pulse Sensor: board bulat berdiameter sekitar 16 mm yang menggabungkan LED hijau, sensor cahaya, dan rangkaian penguat sinyal; modul ini dilengkapi kabel 3 pin.

Bagaimana sensor detak jantung bekerja? Fotopletismografi (PPG)

Semua sensor detak jantung bekerja dengan metode yang disebut fotopletismografi (PPG). Setiap kali jantungmu berkontraksi, jantung mengirim gelombang darah ke arteri; ketika gelombang ini mencapai pembuluh-pembuluh kecil di ujung jarimu, volume darah di jaringan naik sebentar. Karena hemoglobin dalam darah menyerap cahaya, makin banyak darah, makin sedikit cahaya yang dipantulkan kembali dari jaringan atau yang menembusnya. Sensor menyinari jaringan dengan LED, lalu sensor cahaya mengukur cahaya yang kembali; riak kecil dan teratur dalam jumlah cahaya inilah denyut nadi itu sendiri.

Bagian sulitnya, hampir semua cahaya yang terukur bersifat konstan. Kulit, otot, tulang, dan darah di pembuluh vena menyerap jumlah cahaya yang sama setiap waktu; ini disebut komponen DC sinyal. Komponen AC yang berubah di setiap detak jantung biasanya hanya sekitar 1–2% dari total cahaya. Jadi, tugas sebenarnya sensor adalah memisahkan dan memperkuat gelombang kecil yang menumpang di atas level besar yang stabil. Gelombang PPG menunjukkan kenaikan cepat menuju puncak (puncak sistolik), lalu penurunan yang lambat; takik kecil di tengah penurunan dan tonjolan kecil tepat sesudahnya (takik dikrotik) berasal dari menutupnya katup aorta. Algoritma yang baik menghitung setiap detak jantung satu kali saja dan tidak mengira takik ini sebagai detak kedua.

Cara cahaya dikirim ke jaringan juga penting. Pulse Sensor memakai metode reflektif: LED dan sensor cahaya berada di sisi yang sama dan mengukur cahaya yang dihamburkan kembali oleh kulit. Cahaya hijaunya diserap kuat oleh hemoglobin dan memberi sinyal yang jelas dari pembuluh tepat di bawah kulit; itu juga alasan kamu melihat LED hijau di bagian belakang smartwatch. KY-039 memakai metode transmisif: LED inframerah menyinari satu sisi jari, dan fototransistor di sisi seberangnya mengukur cahaya yang menembus jari. Cahaya inframerah masuk lebih dalam ke jaringan, tetapi karena KY-039 tidak punya rangkaian penguat sinyal, gelombang yang dihasilkan sangat kecil.

FiturNilai Pulse Sensor
Metode pengukuranPPG reflektif
Sumber cahayaLED hijau
Sensor cahayaAPDS-9008, sensitivitas puncak pada 565 nm
Catu daya3–5 V
ArusSekitar 4 mA (pada 5 V)
OutputAnalog; setengah tegangan catu ketika diam (~2,5 V pada 5 V, ~512 di Uno)
Diameter boardSekitar 16 mm (0,625 inci)
KabelPada versi asli: merah +, hitam GND, ungu sinyal; warnanya bisa berbeda pada klon

Pulse Sensor vs KY-039 vs MAX30102

Sensor detak jantung KY-039 (LED inframerah dan fototransistor)
KY-039: LED inframerah di atas yang ditekuk ke arah fototransistor, dan fototransistor di bawahnya; jarimu masuk di antara keduanya. Tidak ada penguat di board, jadi sinyal langsung masuk ke pin analog.
FiturPulse SensorKY-039MAX30102
MetodePPG reflektifPPG transmisif (jari di tengah)PPG reflektif
CahayaLED hijauLED inframerahMerah (660 nm) + inframerah (880 nm)
Penguat dan filterAda (op-amp)Tidak adaADC 18-bit internal, peredam cahaya sekitar
OutputAnalogAnalog (sangat lemah)Digital, I2C (alamat 0x57)
Catu daya3–5 V3,3–5 V3,3–5 V tergantung modulnya
Kualitas sinyalBaikLemah, mudah terkena derauSangat baik
SpO2 (oksigen)TidakTidakYa (dengan algoritma)
LibraryPulseSensor PlaygroundTidak ada library siap pakaiSparkFun MAX3010x

Kalau kamu pemula dan hanya ingin mengukur denyut nadi, Pulse Sensor adalah pilihan termudah: karena sinyalnya sudah diperkuat dan difilter di board, kamu akan melihat gelombang yang jelas di Serial Plotter pada percobaan pertama. Op-amp di bagian belakang menaikkan perubahan kecil ini ke level yang bisa dibaca Arduino; kamu bisa mencoba cara menghitung penguatan seperti itu di kalkulator penguatan op-amp. KY-039 murah dan ada di kebanyakan kit sensor, tetapi output-nya hanya bergerak beberapa langkah ADC, jadi kode sederhana dengan ambang tetap tidak akan memberi hasil yang andal. Kalau kamu juga ingin mengukur saturasi oksigen darah (SpO2), pilihan yang tepat adalah MAX30102; kita membahasnya di bagian tersendiri di bawah.

Pengkabelan sensor detak jantung: Arduino Uno, ESP32, dan Pico

Pin sensorArduino UnoESP32Raspberry Pi Pico
+ (VCC, merah)5V3V33V3(OUT), pin 36
− (GND, hitam)GNDGNDGND, pin 38
S (sinyal, ungu)A0GPIO 34 (ADC1)GP26 (ADC0), pin 31
LED detak (opsional)D13 (LED bawaan)GPIO 2 (LED bawaan)LED di board
Input analog ESP32 dan Pico hanya tahan maksimal 3,3 V. Karena output Pulse Sensor bisa naik sampai setinggi tegangan catunya, pada board-board ini beri daya sensor dari pin 3V3, bukan dari 5V atau VBUS. Pada board klon, urutan pin dan warna kabelnya bisa berbeda; selalu baca label S, +, dan − di board sebelum menghubungkannya.

Tabel yang sama berlaku untuk KY-039: pin S ke input analog, + ke catu daya, dan − ke GND. Pastikan LED inframerah ditekuk ke arah fototransistor dan jarimu muat di antara keduanya. Komponen di bagian belakang Pulse Sensor terbuka; kalau jari atau permukaan yang berkeringat menyentuh bagian belakang, muncul derau. Karena itu, kebiasaan yang baik adalah menempelkan stiker bening yang ikut dalam kit di bagian depan dan menutup bagian belakang dengan lem tembak. Kalau kamu memakai LED eksternal, hitung resistornya dengan kalkulator resistor LED; kamu juga bisa melihat peta pin board-mu di alat diagram pin.

Tes pertama: melihat gelombang nadi mentah di Serial Plotter

Sebelum lanjut ke BPM, pastikan sensornya benar-benar menangkap denyut nadi. Kode di bawah tidak memakai library apa pun; kode ini membaca sinyal 100 kali per detik dan mengirimkannya ke Serial Plotter. Upload kodenya, buka Tools > Serial Plotter di Arduino IDE, dan atur kecepatannya ke 115200 baud. Kalau kamu belum pernah memakai Serial Plotter, artikel Serial Monitor Arduino menjelaskan cara kerja jendela ini.

C++ (Arduino IDE)
1// Nabız sensörü ham sinyal testi (Seri Çizici) / Pulse sensor raw signal test (Serial Plotter)
2const int PULSE_PIN = A0;              // sensörün S (mor) kablosu / sensor S (purple) wire
3const unsigned long PERIOD_MS = 10;    // 10 ms = saniyede 100 örnek / 10 ms = 100 samples per second
4
5unsigned long lastSample = 0;
6
7void setup() {
8  Serial.begin(115200);                // Seri Çizici'de de 115200 seç / pick 115200 in the Serial Plotter too
9  lastSample = millis();
10}
11
12void loop() {
13  if (millis() - lastSample >= PERIOD_MS) {
14    lastSample += PERIOD_MS;           // sabit aralıkla örnekle / sample at a fixed interval
15    int raw = analogRead(PULSE_PIN);   // 0-1023 arası değer / value between 0 and 1023
16    Serial.print("Sinyal:");
17    Serial.print(raw);
18    Serial.println(",Orta:512");       // boştaki orta seviye çizgisi / idle midpoint line
19  }
20}

Tanpa jari di atasnya, garis Pulse Sensor diam datar di sekitar 512 dengan sedikit getaran; itu setengah dari tegangan catu dan menandakan sensor sudah terhubung dengan benar. Ketika kamu menempelkan ujung jari dengan ringan ke sensor, dalam beberapa detik muncul gelombang yang naik cepat dan turun pelan di setiap detak jantung; amplitudonya biasanya antara 100 dan 300 langkah. Kalau gelombangnya tidak terlihat, jangan lanjut ke kode BPM: perbaiki dulu pengkabelan, catu daya, dan tekanan jari. Kalau puncaknya berubah menjadi garis datar yang menempel di 0 atau 1023, sinyalnya terpotong (clipping); biasanya jarinya bergerak atau sensornya ditekan terlalu keras. Kalau kamu penasaran dari mana rentang 0–1023 pada pembacaan analog berasal, lihat artikel Apa Itu ADC?.

Mengukur BPM dengan PulseSensorPlayground

  1. Buka Library Manager di Arduino IDE, cari PulseSensor Playground, lalu instal. Untuk detail cara menginstal library, lihat artikel Cara Instal Library Arduino.
  2. Hubungkan sensor seperti di tabel: + ke 5V, − ke GND, dan S ke A0.
  3. Upload kode di bawah dan buka Serial Plotter pada 115200 baud; garis pertama menunjukkan sinyal mentah dan garis kedua menunjukkan nilai BPM.
  4. Letakkan jarimu di sensor, sandarkan tanganmu di meja, dan diam selama 10 detik; library akan menstabilkan rata-ratanya selama beberapa detak pertama.
  5. Kalau kamu lebih suka melihat angkanya baris demi baris di Serial Monitor, ubah konstanta PLOTTER di kode menjadi false; BPM dan jarak waktu antardetak (IBI) lalu dicetak di setiap detak.
C++ (Arduino IDE)
1// PulseSensor Playground ile BPM ölçme / Measuring BPM with PulseSensor Playground
2#include <PulseSensorPlayground.h>
3
4const int PULSE_PIN = A0;              // sensörün S (mor) kablosu / sensor S (purple) wire
5const int LED_PIN = LED_BUILTIN;       // her atışta yanan LED (D13) / LED lit on each beat (D13)
6const int THRESHOLD = 550;             // başlangıç eşiği, boşta ~512 / starting threshold, idle ~512
7const bool PLOTTER = true;             // true: Seri Çizici, false: Seri Monitör / true: Serial Plotter, false: Serial Monitor
8
9PulseSensorPlayground pulseSensor;     // kütüphane nesnesi / library object
10unsigned long lastPrint = 0;
11
12void setup() {
13  Serial.begin(115200);
14  pulseSensor.analogInput(PULSE_PIN);
15  pulseSensor.blinkOnPulse(LED_PIN);
16  pulseSensor.setThreshold(THRESHOLD);
17  if (!pulseSensor.begin()) {          // 2 ms'lik zamanlayıcıyı başlatır / starts the 2 ms timer
18    Serial.println(F("PulseSensor baslatilamadi / could not start"));
19    while (true) {}
20  }
21}
22
23void loop() {
24  // Atış anı: BPM ve atışlar arası süre / moment of a beat: BPM and inter-beat interval
25  if (pulseSensor.sawStartOfBeat() && !PLOTTER) {
26    Serial.print(F("BPM: "));
27    Serial.print(pulseSensor.getBeatsPerMinute());
28    Serial.print(F("  IBI: "));
29    Serial.print(pulseSensor.getInterBeatIntervalMs());
30    Serial.println(F(" ms"));
31  }
32
33  // 20 ms'de bir çizim satırı / one plotter line every 20 ms
34  if (PLOTTER && millis() - lastPrint >= 20) {
35    lastPrint = millis();
36    Serial.print(F("Sinyal:"));
37    Serial.print(pulseSensor.getLatestSample());
38    Serial.print(F(",BPM:"));
39    Serial.println(pulseSensor.getBeatsPerMinute());
40  }
41}
FungsiKegunaannya
analogInput(pin)Memilih pin analog tempat sensor terhubung (default A0)
blinkOnPulse(pin)Menyalakan LED di pin ini selama sinyal berada di atas ambang, yaitu selama setiap detak
fadeOnPulse(pin)Menyalakan LED di pin PWM pada setiap detak lalu meredupkannya perlahan
setThreshold(nilai)Ambang awal; ketika tidak ada detak yang ditemukan, ambang kembali ke nilai ini
begin()Memulai sampling; mengembalikan true jika berhasil
sawStartOfBeat()Mengembalikan true jika detak baru sudah dimulai sejak pemanggilan terakhir
getBeatsPerMinute()BPM yang dihitung dari rata-rata 10 interval detak terakhir
getInterBeatIntervalMs()Jarak waktu antara dua detak terakhir (IBI), dalam milidetik
getLatestSample()Pembacaan mentah terbaru (0–1023)
isInsideBeat()Mengembalikan true selama sinyal berada di atas ambang

Library membaca sensor di latar belakang dengan timer interrupt setiap 2 ms (500 kali per detik), jadi sampling tetap stabil meskipun kamu menjalankan tugas yang lama di loop(). Di setiap detak, library mencatat puncak dan lembah gelombang lalu memindahkan ambang tepat ke tengah-tengah keduanya; dengan kata lain, nilai yang kamu berikan ke setThreshold() hanyalah titik awal. Library mengabaikan kenaikan yang datang dalam 250 ms setelah detak sebelumnya atau sebelum tiga per lima dari interval detak terakhir berlalu, sehingga takik dikrotik tidak dihitung sebagai detak kedua. BPM dihitung dari rata-rata 10 interval detak terakhir; kalau tidak ada detak yang ditemukan selama 2,5 detik, semuanya di-reset dan getBeatsPerMinute() mengembalikan 0.

Pilih ambang awal dengan melihat sinyal mentahnya: 30–50 langkah di atas nilai tertinggi yang dicapai garis tanpa jari adalah titik awal yang bagus (antara 530 dan 600 pada kebanyakan sensor). Kalau ambangnya terlalu rendah, derau dihitung sebagai detak bahkan tanpa jari; kalau terlalu tinggi, denyut yang lemah akan terlewat. Satu peringatan lagi: di Arduino Uno, library memakai Timer1 untuk sampling, jadi analogWrite() tidak berfungsi di pin 9 dan 10. Kalau kamu menambahkan library Servo ke proyekmu, library ini beralih ke Timer2; akibatnya yang terpengaruh justru PWM di pin 3 dan 11 serta fungsi tone().

Supaya pembacaannya akurat: tekanan jari, cahaya sekitar, dan gerakan

Sebagian besar hal yang merusak pembacaan denyut nadi berkaitan dengan cara sensor dipegang, bukan dengan kodenya. Coba poin-poin di bawah satu per satu dengan Serial Plotter terbuka; melihat bagaimana masing-masing mengubah gelombang adalah cara tercepat untuk memahami sensornya.

  • Tekanan jari: tekan dengan ringan tapi stabil. Kalau sentuhanmu terlalu ringan, setiap gerakan kecil jari menimbulkan derau yang lebih besar dari gelombangnya; kalau terlalu keras, kamu menjepit pembuluh kapiler, aliran darah berkurang, dan gelombangnya jadi datar atau bahkan hilang. Hasil terbaik didapat dengan melilitkan sensor ke jari memakai tali Velcro (perekat).
  • Cahaya sekitar: sinar matahari dan lampu bocor masuk ke sensor dari samping. Listrik PLN di Indonesia 50 Hz, dan pada listrik 50 Hz banyak lampu berkedip 100 kali per detik (120 kali pada listrik 60 Hz); kedipan ini ikut masuk ke sinyal. Tutup area di sekitar sensor sepenuhnya dengan jarimu atau lilitkan pita berwarna gelap di atasnya.
  • Gerakan: kabel yang bergoyang, berbicara, menggerakkan jari, atau berjalan menghasilkan sinyal yang jauh lebih besar daripada denyut nadi. Sandarkan tanganmu di meja dan tetap diam selama pengukuran.
  • Tangan dingin: pada jari yang dingin, pembuluh darah menyempit dan sinyalnya melemah. Hangatkan tanganmu atau jepitkan sensor ke daun telinga; daun telinga juga lebih sedikit terpengaruh oleh gerakan.
  • Keringat dan minyak: kulit yang lembap menghamburkan cahaya secara berbeda dan mengotori permukaan sensor. Pakai stiker pelindung bening di bagian depan dan lap sensor sesekali dengan kain kering.
  • Waktu stabil: selama 5–10 detik pertama setelah kamu menempelkan jari, sinyalnya menjadi stabil dan rata-ratanya terisi; abaikan nilai yang kamu lihat selama waktu itu.
Ada cara mudah untuk tahu apakah sensormu mengukur dengan benar: hitung denyut nadi di pergelangan tangan atau lehermu selama 30 detik, kalikan 2, lalu bandingkan dengan BPM di layar. Ketika istirahat, selisih 3–5 BPM itu normal; kalau selisihnya lebih besar, perbaiki dulu tekanan jari dan cahaya sekitar, lalu atur ambangnya.

Tampilan detak jantung di OLED

Serial Plotter cukup untuk di meja, tetapi alat ukur detak jantung portabel butuh layar kecil. Kode di bawah menggambar BPM dengan angka besar dan ikon hati yang membesar di setiap detak di bagian atas layar OLED SSD1306 0,96 inci, serta gelombang nadi langsung yang menyapu dari kiri ke kanan di bagian bawah. Hubungkan OLED ke pin A4 (SDA) dan A5 (SCL) di Uno, dan dayanya ke 5V dan GND; cara menginstal library layar dan mengatur alamatnya dijelaskan secara rinci di artikel Cara Memakai Layar OLED (SSD1306).

C++ (Arduino IDE)
1// Pulse Sensor + 0,96" OLED: BPM, kalp simgesi ve nabız dalgası / BPM, heart icon and pulse wave
2#include <Wire.h>
3#include <Adafruit_GFX.h>
4#include <Adafruit_SSD1306.h>
5#include <PulseSensorPlayground.h>
6
7Adafruit_SSD1306 display(128, 64, &Wire, -1);  // 128x64, reset pini yok / no reset pin
8PulseSensorPlayground pulseSensor;
9
10const int PULSE_PIN = A0;              // sensörün S pini / sensor S pin
11const int THRESHOLD = 550;             // başlangıç eşiği / starting threshold
12const int GRAPH_TOP = 24;              // dalga alanının üst kenarı / top edge of the wave area
13const int GRAPH_H = 40;                // dalga alanının yüksekliği / height of the wave area
14
15int x = 0;                             // tarama sütunu (0-127) / sweep column (0-127)
16int lastY = GRAPH_TOP + GRAPH_H / 2;   // önceki noktanın y'si / y of the previous point
17int lo = 1023, hi = 0;                 // bu taramadaki en küçük/büyük değer / min/max in this sweep
18int scaleLo = 400, scaleHi = 624;      // çizimde kullanılan aralık / range used for drawing
19unsigned long lastDraw = 0, beatTime = 0;
20
21// İki daire ve bir üçgenle kalp çiz / draw a heart from two circles and a triangle
22void drawHeart(int cx, int cy, bool big) {
23  int r = big ? 6 : 4;                 // atış anında büyük kalp / bigger heart on a beat
24  display.fillCircle(cx - r, cy - r / 2, r, SSD1306_WHITE);
25  display.fillCircle(cx + r, cy - r / 2, r, SSD1306_WHITE);
26  display.fillTriangle(cx - 2 * r, cy, cx + 2 * r, cy, cx, cy + 2 * r, SSD1306_WHITE);
27}
28
29void setup() {
30  Serial.begin(115200);
31  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {  // I2C adresi 0x3C / I2C address 0x3C
32    Serial.println(F("SSD1306 allocation failed"));
33    while (true) {}
34  }
35  display.clearDisplay();
36  pulseSensor.analogInput(PULSE_PIN);
37  pulseSensor.setThreshold(THRESHOLD);
38  pulseSensor.begin();                 // örnekleme kesmeyle sürer / sampling runs in an interrupt
39}
40
41void loop() {
42  if (pulseSensor.sawStartOfBeat()) beatTime = millis();  // atış anını sakla / store the beat time
43
44  if (millis() - lastDraw < 40) return; // saniyede 25 kare / 25 frames per second
45  lastDraw = millis();
46
47  // Alt bölüm: soldan sağa taranan nabız dalgası / bottom: pulse wave swept left to right
48  int s = pulseSensor.getLatestSample();
49  if (s < lo) lo = s;
50  if (s > hi) hi = s;
51  int y = map(constrain(s, scaleLo, scaleHi), scaleLo, scaleHi, GRAPH_TOP + GRAPH_H - 1, GRAPH_TOP);
52  display.drawFastVLine(x, GRAPH_TOP, GRAPH_H, SSD1306_BLACK);              // eski sütunu sil / erase the old column
53  display.drawFastVLine((x + 1) % 128, GRAPH_TOP, GRAPH_H, SSD1306_BLACK);  // önündeki boşluk / gap ahead
54  if (x > 0) display.drawLine(x - 1, lastY, x, y, SSD1306_WHITE);
55  lastY = y;
56  if (++x >= 128) {                    // tarama bitti: ölçeği yenile / sweep done: refresh the scale
57    x = 0;
58    if (hi - lo > 20) { scaleLo = lo; scaleHi = hi; }
59    lo = 1023;
60    hi = 0;
61  }
62
63  // Üst bölüm: kalp ve BPM / top: heart and BPM
64  display.fillRect(0, 0, 128, GRAPH_TOP, SSD1306_BLACK);
65  drawHeart(14, 10, millis() - beatTime < 150);
66  int bpm = pulseSensor.getBeatsPerMinute();
67  display.setTextColor(SSD1306_WHITE);
68  display.setTextSize(3);
69  display.setCursor(40, 0);
70  if (bpm > 0) display.print(bpm);
71  else display.print(F("--"));         // parmak yok / no finger
72  display.setTextSize(1);
73  display.setCursor(104, 14);
74  display.print(F("BPM"));
75  display.display();                   // tamponu ekrana gönder / push the buffer to the screen
76}

Kode ini menyegarkan layar 25 kali per detik dan menambahkan satu titik ke gelombang di setiap frame, jadi lebar layar menampilkan rekaman denyut nadi sekitar 5 detik. Di akhir setiap sapuan, gelombang diskalakan ulang sesuai nilai terkecil dan terbesar dalam sapuan itu, sehingga sinyal yang lemah maupun yang kuat tetap muat di layar. Mengirim satu frame ke layar lewat I2C memakan waktu sekitar 25–30 ms, tetapi karena library melakukan sampling di dalam interrupt, tidak ada detak yang terlewat selama itu. Di Uno, buffer layar memakai 1 KB RAM; karena kode menggambar gelombang langsung ke layar tanpa menyimpannya di array, memorinya cukup, meskipun hanya tersisa sekitar 450 byte yang kosong.

Mengukur detak jantung dengan KY-039

Pada KY-039, fototransistor dirangkai seri dengan sebuah resistor, dan tegangan output-nya berubah sesuai cahaya yang diterimanya: makin banyak cahaya, makin rendah tegangannya; makin sedikit cahaya, makin tinggi. Tidak ada penguat atau filter di antaranya. Dengan jari terpasang, satu detak jantung biasanya hanya menggeser tegangan ini sebesar 2–10 langkah ADC, sekitar 10–50 mV; perubahan kecil pada cahaya sekitar pun sudah lebih besar dari itu. Karena itu, kode yang ditulis untuk Pulse Sensor dan ambang tetap seperti 550 tidak berfungsi di KY-039; kamu perlu membersihkan sinyalnya dulu, lalu memakai ambang yang menyesuaikan diri dengan ukuran gelombang itu sendiri.

Kode di bawah melakukannya dalam empat langkah. Pertama, kode membaca pin analog tanpa henti selama 20 ms (sekitar 175 pembacaan) dan merata-ratakannya; ini mengurangi derau acak dan, karena 20 ms tepat satu periode listrik 50 Hz, hampir sepenuhnya menghilangkan kedipan lampu. Lalu kode menghaluskan sinyal dengan filter low-pass ringan dan membuang level DC dengan rata-rata bergerak yang sangat lambat, sehingga yang tersisa hanya gelombang nadi. Di langkah ketiga, kode menghitung dua selubung (envelope) yang mengikuti puncak dan lembah gelombang, lalu meletakkan ambang di tengah-tengah keduanya. Terakhir, satu detak dihitung ketika sinyal memotong ambang ke arah atas, dan BPM didapat dari rata-rata 8 interval detak terakhir.

C++ (Arduino IDE)
1// KY-039 ile nabız ölçme (kütüphanesiz) / Heart rate with the KY-039 (no library)
2const int SENSOR_PIN = A0;             // KY-039 S pini / KY-039 S pin
3const int LED_PIN = LED_BUILTIN;       // atışta yanan LED / LED lit on each beat
4const bool PLOTTER = true;             // true: Seri Çizici, false: Seri Monitör / true: Serial Plotter, false: Serial Monitor
5const unsigned long WINDOW_US = 20000; // 20 ms = 50 Hz şebekenin bir periyodu / one period of 50 Hz mains
6const float MIN_AMP = 1.2;             // tepe-tepe gürültü sınırı (ADC birimi) / peak-to-peak noise limit (ADC units)
7const int AVG_BEATS = 8;               // BPM için ortalanan aralık sayısı / intervals averaged for BPM
8
9float smooth, baseline;                // süzülmüş sinyal ve DC seviye / filtered signal and DC level
10float posEnv = 0, negEnv = 0;          // tepe ve çukur zarfları / peak and trough envelopes
11bool armed = true;                     // yeni atışa hazır mı / ready for a new beat
12unsigned long lastBeat = 0;            // son atışın zamanı / time of the last beat
13unsigned int ibi[AVG_BEATS];           // atışlar arası süreler (ms) / inter-beat intervals (ms)
14int ibiCount = 0, ibiIndex = 0, bpm = 0;
15
16// 20 ms boyunca okuyup ortalama al / read for 20 ms and average
17float readWindow() {
18  unsigned long start = micros();
19  long sum = 0;
20  int n = 0;
21  while (micros() - start < WINDOW_US) {
22    sum += analogRead(SENSOR_PIN);
23    n++;
24  }
25  return (float)sum / n;
26}
27
28float averageIbi() {
29  if (ibiCount == 0) return 500.0;     // geçmiş yoksa 120 BPM varsay (ilk bekleme 350 ms) / assume 120 BPM without history (first wait 350 ms)
30  unsigned long sum = 0;
31  for (int i = 0; i < ibiCount; i++) sum += ibi[i];
32  return (float)sum / ibiCount;
33}
34
35void addInterval(unsigned int ms) {
36  ibi[ibiIndex] = ms;                  // halka tampon / ring buffer
37  ibiIndex = (ibiIndex + 1) % AVG_BEATS;
38  if (ibiCount < AVG_BEATS) ibiCount++;
39  bpm = (int)(60000.0 / averageIbi() + 0.5);
40}
41
42void setup() {
43  Serial.begin(115200);
44  pinMode(LED_PIN, OUTPUT);
45  smooth = baseline = readWindow();    // başlangıç seviyesi / starting level
46}
47
48void loop() {
49  float x = readWindow();              // saniyede 50 örnek / 50 samples per second
50  unsigned long now = millis();
51
52  smooth += (x - smooth) * 0.5;        // hafif alçak geçiren süzgeç / light low-pass filter
53  baseline += (smooth - baseline) * 0.05;  // yavaş DC takibi (~0,4 s) / slow DC tracking (~0.4 s)
54  float ac = smooth - baseline;        // yalnız nabız dalgası / pulse wave only
55
56  // Zarflar: uçları hemen yakala, yavaşça bırak / envelopes: catch extremes fast, release slowly
57  posEnv = (ac > posEnv) ? ac : posEnv * 0.99;
58  negEnv = (ac < negEnv) ? ac : negEnv * 0.99;
59  float amp = posEnv - negEnv;         // tepe-tepe genlik / peak-to-peak amplitude
60  float mid = (posEnv + negEnv) / 2;   // eşik: dalganın ortası / threshold: middle of the wave
61
62  unsigned long sinceBeat = now - lastBeat;
63  float refractory = constrain(averageIbi() * 0.7, 250.0, 600.0);  // dikrotik çentiği atla / skip the dicrotic notch
64
65  if (armed && amp > MIN_AMP && ac > mid && sinceBeat > refractory) {
66    armed = false;                     // atış bulundu / beat found
67    digitalWrite(LED_PIN, HIGH);
68    if (sinceBeat < 2000) addInterval(sinceBeat);  // 30 BPM'den yavaşı alma / ignore gaps slower than 30 BPM
69    lastBeat = now;
70    if (!PLOTTER && bpm > 0) {
71      Serial.print(F("BPM: "));
72      Serial.println(bpm);
73    }
74  }
75  if (!armed && ac < mid - amp * 0.25) {  // dalga yeterince indi: yeniden hazır / wave fell enough: re-arm
76    armed = true;
77    digitalWrite(LED_PIN, LOW);
78  }
79  if (sinceBeat > 2500 && ibiCount > 0) {  // 2,5 s atış yok: sıfırla / no beat for 2.5 s: reset
80    ibiCount = 0;
81    bpm = 0;
82  }
83
84  if (PLOTTER) {
85    Serial.print(F("Nabiz:"));
86    Serial.print(ac);
87    Serial.print(F(",Esik:"));
88    Serial.println(mid);
89  }
90}
Konstanta / nilaiKegunaannya
WINDOW_US = 20000Jendela rata-rata; menghilangkan kedipan listrik 50 Hz (pakai 16667 di negara dengan listrik 60 Hz)
0.5 (smooth, penghalusan)Filter low-pass ringan; menghaluskan lonjakan mendadak
0.05 (baseline, garis dasar)Mengikuti level DC dalam sekitar 0,4 detik; membuang perubahan lambat pada tekanan jari
0.99 (selubung)Kecepatan pelepasan selubung puncak dan lembah (sekitar 2 detik)
MIN_AMP = 1.2Gelombang dengan amplitudo puncak-ke-puncak di bawah nilai ini dianggap derau
refractory (masa refrakter)70% dari interval rata-rata terakhir (250–600 ms; 350 ms selama belum ada riwayat, supaya denyut yang cepat tidak terlewat); mencegah takik dikrotik dihitung sebagai detak kedua
mid - amp * 0.25 (level siaga ulang)Level siaga ulang (re-arm); detak baru tidak dicari sampai gelombang turun cukup jauh

Ketika kamu meng-upload kode dan membuka Serial Plotter, kamu akan melihat dua garis: Nabiz (bahasa Turki untuk “denyut”) menunjukkan gelombang yang sudah dibersihkan, dan Esik (“ambang”) menunjukkan ambang adaptif yang melintas di tengahnya. Perhatikan seberapa banyak garis Nabiz bergerak tanpa jari, lalu atur MIN_AMP sedikit di atas nilai puncak-ke-puncak itu; turunkan kalau sinyalmu sangat lemah. Untuk teknik menghaluskan sinyal lebih lanjut, lihat artikel menyaring data sensor. Kode yang sama juga bekerja dengan Pulse Sensor; dalam hal itu cukup naikkan MIN_AMP ke sekitar 20.

Sensor detak jantung dengan ESP32

Pada ESP32, beri daya sensor dari pin 3V3 dan hubungkan sinyalnya ke GPIO 34. Pin ini termasuk kelompok ADC1; pin ADC2 tidak bisa dibaca selama Wi-Fi menyala, jadi kalau kamu akan mengirim data denyut nadi lewat internet, kamu wajib memilih salah satu pin ADC1 (GPIO 32–39). ADC ESP32 berukuran 12-bit (0–4095), dan dengan catu 3,3 V, Pulse Sensor memberi nilai sekitar 2000 ketika diam.

Versi terbaru PulseSensorPlayground juga mendukung ESP32, tetapi library ini memakai fungsi timer dari versi 3.x paket board ESP32 dan tidak bisa dikompilasi dengan versi 2.x. Di contoh-contohnya, library menurunkan ADC ke 10 bit dengan analogReadResolution(10), sehingga ambangnya diberikan pada skala 0–1023 yang sama seperti di Uno (685 di contoh ESP32). Supaya tidak terpengaruh perbedaan versi, di bawah ini ada sketch tanpa library yang memakai algoritma yang sama dengan bagian KY-039; sketch ini bekerja di kedua versi paket board.

C++ (Arduino IDE)
1// ESP32 + Pulse Sensor: kütüphanesiz BPM / BPM without a library
2const int SENSOR_PIN = 34;             // ADC1 pini, Wi-Fi açıkken de çalışır / ADC1 pin, works with Wi-Fi on
3const int LED_PIN = 2;                 // çoğu DevKit'te dahili LED / built-in LED on most DevKits
4const unsigned long PERIOD_MS = 10;    // saniyede 100 örnek / 100 samples per second
5const float MIN_AMP = 80;              // 12 bitte tepe-tepe gürültü sınırı / peak-to-peak noise limit in 12-bit units
6const int AVG_BEATS = 8;               // BPM için ortalanan aralık sayısı / intervals averaged for BPM
7
8float smooth, baseline, posEnv = 0, negEnv = 0;
9bool armed = true;
10unsigned long lastSample = 0, lastBeat = 0;
11unsigned long ibi[AVG_BEATS];
12int ibiCount = 0, ibiIndex = 0, bpm = 0;
13
14// 8 okumanın ortalaması: ESP32 ADC'si gürültülüdür / average of 8 reads: the ESP32 ADC is noisy
15float readSensor() {
16  long sum = 0;
17  for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
18  return sum / 8.0;
19}
20
21float averageIbi() {
22  if (ibiCount == 0) return 500.0;     // geçmiş yoksa 120 BPM varsay (ilk bekleme 350 ms) / assume 120 BPM without history (first wait 350 ms)
23  unsigned long sum = 0;
24  for (int i = 0; i < ibiCount; i++) sum += ibi[i];
25  return (float)sum / ibiCount;
26}
27
28void setup() {
29  Serial.begin(115200);
30  pinMode(LED_PIN, OUTPUT);
31  analogReadResolution(12);            // 0-4095 arası değer / values from 0 to 4095
32  smooth = baseline = readSensor();
33  lastSample = millis();
34}
35
36void loop() {
37  if (millis() - lastSample < PERIOD_MS) return;
38  lastSample += PERIOD_MS;             // sabit aralıkla örnekle / sample at a fixed interval
39  unsigned long now = millis();
40
41  float x = readSensor();
42  smooth += (x - smooth) * 0.3;        // alçak geçiren süzgeç (~6 Hz) / low-pass filter (~6 Hz)
43  baseline += (smooth - baseline) * 0.02;  // DC takibi (~0,5 s) / DC tracking (~0.5 s)
44  float ac = smooth - baseline;
45
46  posEnv = (ac > posEnv) ? ac : posEnv * 0.995;  // tepe zarfı / peak envelope
47  negEnv = (ac < negEnv) ? ac : negEnv * 0.995;  // çukur zarfı / trough envelope
48  float amp = posEnv - negEnv;
49  float mid = (posEnv + negEnv) / 2;
50
51  unsigned long sinceBeat = now - lastBeat;
52  float refractory = constrain(averageIbi() * 0.7, 250.0, 600.0);
53
54  if (armed && amp > MIN_AMP && ac > mid && sinceBeat > refractory) {
55    armed = false;
56    digitalWrite(LED_PIN, HIGH);
57    if (sinceBeat < 2000) {            // 30-240 BPM aralığı / 30-240 BPM range
58      ibi[ibiIndex] = sinceBeat;
59      ibiIndex = (ibiIndex + 1) % AVG_BEATS;
60      if (ibiCount < AVG_BEATS) ibiCount++;
61      bpm = (int)(60000.0 / averageIbi() + 0.5);
62      Serial.printf("BPM: %d  IBI: %lu ms\n", bpm, sinceBeat);
63    }
64    lastBeat = now;
65  }
66  if (!armed && ac < mid - amp * 0.25) {
67    armed = true;
68    digitalWrite(LED_PIN, LOW);
69  }
70  if (sinceBeat > 2500 && ibiCount > 0) {  // parmak çekildi / finger removed
71    ibiCount = 0;
72    bpm = 0;
73    Serial.println("Parmak yok / no finger");
74  }
75}

Di kode ini sinyal dibaca 100 kali per detik, dan karena ADC ESP32 cukup berderau, setiap sampel adalah rata-rata dari 8 pembacaan. Nilai ambang dan selubung diatur untuk skala 12-bit, jadi MIN_AMP bernilai 80 (sekitar 65 mV). Kekuatan sebenarnya ESP32 adalah Wi-Fi: kamu bisa mengalirkan BPM secara langsung ke halaman web lewat WebSocket, mengirim pesan Telegram ketika denyut nadi melewati batas tertentu, atau mencatat hasil pengukuranmu ke Google Sheets.

Mengukur detak jantung dengan Raspberry Pi Pico dan MicroPython

Pada Raspberry Pi Pico, hubungkan pin + sensor ke 3V3(OUT) (pin 36), − ke GND (pin 38), dan S ke GP26 (ADC0, pin 31). Di MicroPython, read_u16() mengembalikan nilai dari 0 sampai 65535; kode menggesernya 4 bit ke kanan untuk menurunkannya ke skala 0–4095 yang sama dengan ESP32, sehingga nilai ambangnya tetap sama di kedua board. Kalau kamu menyimpan kode ke Pico sebagai main.py di Thonny, kode akan berjalan sendiri setiap kali board dinyalakan.

MicroPython
1# Raspberry Pi Pico + Pulse Sensor: MicroPython ile BPM / BPM with MicroPython
2from machine import ADC, Pin
3import time
4
5sensor = ADC(26)                   # GP26 = ADC0, sensörün S pini / sensor S pin
6led = Pin("LED", Pin.OUT)          # kartın üzerindeki LED / on-board LED
7
8PERIOD_MS = 10                     # saniyede 100 örnek / 100 samples per second
9MIN_AMP = 80                       # 12 bitte tepe-tepe gürültü sınırı / peak-to-peak noise limit (12-bit)
10AVG_BEATS = 8                      # BPM için ortalanan aralık / intervals averaged for BPM
11
12def read12():
13    # 4 okumanın ortalaması, 0-4095 / average of 4 reads, 0-4095
14    s = 0
15    for _ in range(4):
16        s += sensor.read_u16() >> 4
17    return s / 4
18
19smooth = baseline = read12()
20pos_env = neg_env = 0.0
21armed = True
22ibis = []
23bpm = 0
24last_beat = time.ticks_ms()
25next_t = time.ticks_ms()
26
27while True:
28    while time.ticks_diff(time.ticks_ms(), next_t) < 0:
29        pass                       # bir sonraki örnek zamanını bekle / wait for the next sample time
30    next_t = time.ticks_add(next_t, PERIOD_MS)
31    now = time.ticks_ms()
32
33    x = read12()
34    smooth += (x - smooth) * 0.3            # alçak geçiren süzgeç / low-pass filter
35    baseline += (smooth - baseline) * 0.02  # DC takibi / DC tracking
36    ac = smooth - baseline
37
38    pos_env = ac if ac > pos_env else pos_env * 0.995
39    neg_env = ac if ac < neg_env else neg_env * 0.995
40    amp = pos_env - neg_env
41    mid = (pos_env + neg_env) / 2
42
43    since = time.ticks_diff(now, last_beat)
44    avg_ibi = sum(ibis) / len(ibis) if ibis else 500   # geçmiş yoksa 120 BPM varsay / assume 120 BPM without history
45    refractory = min(max(avg_ibi * 0.7, 250), 600)   # dikrotik çentiği atla / skip the dicrotic notch
46
47    if armed and amp > MIN_AMP and ac > mid and since > refractory:
48        armed = False
49        led.on()
50        if since < 2000:                    # 30 BPM'den yavaşı alma / ignore gaps slower than 30 BPM
51            ibis.append(since)
52            if len(ibis) > AVG_BEATS:
53                ibis.pop(0)
54            bpm = round(60000 / (sum(ibis) / len(ibis)))
55            print("BPM:", bpm, "IBI:", since)
56        last_beat = now
57    if not armed and ac < mid - amp * 0.25:
58        armed = True
59        led.off()
60    if since > 2500 and ibis:               # parmak çekildi / finger removed
61        ibis = []
62        bpm = 0
63        print("Parmak yok / no finger")

Kode ini bekerja dengan logika yang sama seperti versi ESP32: mengambil sampel setiap 10 ms, membuang level DC, menemukan detak dengan ambang adaptif, dan menghitung BPM dari rata-rata 8 interval terakhir. Di setiap detak, LED di board menyala, dan BPM serta interval detak dicetak di jendela Shell Thonny. Kalau sintaks Python masih baru buatmu, artikel dasar-dasar MicroPython adalah tempat yang bagus untuk memulai.

Bedanya dengan MAX30102: mengukur oksigen darah (SpO2)

MAX30102 adalah sensor satu chip yang dirancang Analog Devices (dulu Maxim Integrated) untuk mengukur detak jantung dan saturasi oksigen darah. Di dalamnya ada dua LED, merah (660 nm) dan inframerah (880 nm), sebuah fotodioda, rangkaian peredam cahaya sekitar, dan ADC 18-bit. Sensor ini melakukan pengukurannya sendiri, menyimpan sampel di memori 32 sampel (FIFO), dan mengirimkannya sebagai angka lewat bus I2C (alamat 0x57). Karena derau yang tertangkap kabel analog dan batas ADC 10-bit Arduino tidak lagi berpengaruh, sinyalnya jauh lebih bersih daripada Pulse Sensor.

Rahasia pengukuran SpO2 adalah memakai cahaya dengan dua warna berbeda. Hemoglobin yang membawa oksigen menyerap lebih banyak cahaya inframerah dan lebih sedikit cahaya merah; hemoglobin yang sudah melepaskan oksigennya justru sebaliknya. Sensor mengukur komponen AC dan DC gelombang nadi untuk kedua cahaya dan menghitung rasio R = (AC_merah / DC_merah) / (AC_inframerah / DC_inframerah); SpO2 didapat dari rasio ini dengan kurva kalibrasi empiris. Pulse Sensor dan KY-039 memakai cahaya satu warna, jadi keduanya tidak bisa menghitung rasio ini, artinya tidak bisa mengukur oksigen. Library Arduino yang paling populer untuk MAX30102 adalah SparkFun MAX3010x; contoh Example5_HeartRate menghitung detak jantung dan Example8_SPO2 menghitung saturasi oksigen.

Pada sebagian board MAX30102 yang murah, resistor pull-up I2C terhubung ke 1,8 V; Arduino Uno 5 V tidak mengenali level itu sebagai HIGH, jadi sensornya tidak terdeteksi. Kalau board-mu punya jumper solder untuk memilih antara 1,8 V dan 3,3 V, pindahkan ke sisi 3,3 V. Modul-modul ini juga sangat peka terhadap tekanan jari dan gerakan.

Sensor detak jantung bukan alat medis

Rangkaian dan kode di artikel ini untuk pendidikan dan hobi. Modul Pulse Sensor, KY-039, dan MAX30102 belum diuji atau disetujui sebagai alat medis; jangan membuat diagnosis atau memutuskan obat maupun pengobatan berdasarkan hasil bacaannya. Kalau kamu mengalami nyeri dada, jantung berdebar, pusing, pingsan, atau sesak napas, jangan mengandalkan sensor: segera cari pertolongan medis, dan dalam keadaan darurat hubungi nomor darurat 112.

Ada alasan konkret untuk ini. Monitor detak jantung dan oksimeter medis dikalibrasi sesuai batas akurasi tertentu dan diuji pada berbagai warna kulit, pada aliran darah rendah, dan ketika bergerak; modul hobi dan algoritma yang kita tulis tidak melewati pengujian ini. Selain itu, mengukur denyut nadi tidak sama dengan menilai irama jantung: untuk memahami gangguan irama dibutuhkan EKG, yang merekam sinyal listrik jantung. Sebagai informasi umum, detak jantung orang dewasa ketika istirahat biasanya antara 60 dan 100 kali per menit; pada orang yang rutin berolahraga bisa turun ke 40–60. Kalau hasil pengukuranmu berada di luar rentang ini, periksa dulu sensor dan kodenya; kalau kamu masih khawatir, bicarakan dengan dokter.

Ide proyek dengan sensor detak jantung

  • Lampu yang berdetak bersama jantungmu: di setiap detak, nyalakan ring LED WS2812B berwarna merah lalu redupkan perlahan; geser warnanya dari biru ke merah seiring naiknya BPM.
  • Monitor detak jantung dengan bunyi bip: bunyikan bip pendek di buzzer setiap kali sawStartOfBeat() mengembalikan true; proyek seru yang meniru suara monitor di rumah sakit.
  • Alat ukur detak jantung portabel: masukkan kode OLED ke dalam kotak bersama baterai dan rangkaian pengisi daya; matikan layar ketika pengukuran selesai supaya baterainya lebih awet.
  • Tes pemulihan setelah olahraga: ukur tepat setelah kamu selesai berolahraga dan hitung berapa detak denyut nadimu turun di menit pertama; catat nilainya setiap hari dan pantau perkembanganmu.
  • Pencatat detak jantung: tulis nilai BPM beserta penanda waktunya ke kartu SD atau kirim ke Excel lalu buat grafiknya.
  • Game latihan pernapasan: tampilkan di layar bagaimana denyut nadimu berubah ketika kamu bernapas pelan dan dalam; kamu menang kalau berhasil menurunkan denyut nadimu di bawah nilai target.

Kesalahan umum dan cara memperbaikinya

GejalaKemungkinan penyebabSolusi
BPM selalu 0 atau “--”Tidak ada detak yang terdeteksi: ambang terlalu tinggi, tidak ada jari, atau pin S di input yang salahPeriksa gelombangnya dengan sketch sinyal mentah; geser ambang ke tengah gelombang
BPM sangat tinggi, misalnya 150–220Derau atau takik dikrotik dihitung sebagai detak keduaNaikkan ambang, stabilkan jari, halangi cahaya sekitar
BPM muncul meskipun tanpa jariAmbang di bawah derau ketika diam; kedipan lampu masuk ke sinyalAtur ambang 30–50 langkah di atas nilai diam tertinggi, tutup sensornya
Sinyal diam datar di 0 atau 1023+ dan − tertukar, kabel putus, pin S di tempat yang salah, atau sensor rusakPeriksa pengkabelan dengan tabel; pakai 3V3 di ESP32 dan Pico
Ada gelombang tapi terus terputus-putusJari bergerak atau tekanannya berubahLilitkan sensor dengan tali Velcro, sandarkan tangan di meja, dan tetap diam
Sama sekali tidak ada gelombang di KY-039LED tidak ditekuk ke arah fototransistor, atau cahaya sekitar yang kuat membuat fototransistor jenuhTekuk LED supaya berada di atas jarimu, pakai sensor di tempat teduh, turunkan MIN_AMP
“too few arguments to function 'hw_timer_t* timerBegin(uint8_t, uint16_t, bool)'” di ESP32PulseSensorPlayground dikompilasi dengan versi 2.x paket board ESP32Perbarui paket board ke 3.x atau pakai kode ESP32 tanpa library di artikel ini
analogWrite() tidak berfungsi di pin 9 atau 10Library memakai Timer1 di UnoPakai pin 3, 5, 6, atau 11 untuk PWM
Ketika mencari sumber masalah, selalu mulai dari kode yang paling sederhana: kalau tes sinyal mentah menunjukkan gelombang yang bersih, perangkat kerasnya baik-baik saja dan masalahnya ada di ambang atau kodenya; kalau tidak ada gelombang, mengubah kode tidak akan membantu, jadi perbaiki dulu pengkabelan dan kontak sensor dengan jarimu.

Sensor detak jantung adalah salah satu proyek langka yang mengajarkan pembacaan analog, penyaringan sinyal, timer interrupt, dan plotting real-time sekaligus hanya dengan satu pin analog, dan kamu melihat hasilnya di tubuhmu sendiri. Kalau kamu ingin proyek pemula yang juga mengukur cahaya, sensor cahaya LDR adalah langkah berikutnya yang bagus. Di aplikasi BlueGrays kamu akan menemukan proyek-proyek yang memakai komponen di artikel ini, seperti membaca intensitas cahaya dengan LDR, buzzer, proyek ESP32 dengan layar OLED, dan efek napas PWM di Pico, lengkap dengan skema rangkaian dan kode langkah demi langkah.

Pertanyaan umum

Seberapa akurat sensor detak jantung Arduino?

Kalau dipegang dengan baik dan orangnya duduk diam, Pulse Sensor biasanya mengukur detak jantung istirahat dengan selisih hanya beberapa BPM. Gerakan, cahaya sekitar, tangan dingin, dan tekanan jari dengan cepat memperbesar kesalahannya. Sinyal KY-039 jauh lebih lemah, jadi hasil bacaannya lebih melompat-lompat; tidak satu pun dari sensor ini cocok untuk pengukuran medis.

Apa bedanya Pulse Sensor dan KY-039?

Pulse Sensor memakai LED hijau dan metode reflektif, memperkuat dan memfilter sinyal dengan op-amp di board, dan diam di setengah tegangan catu. KY-039 mengukur cahaya inframerah yang menembus jarimu, tidak punya penguat di board, dan output-nya hanya bergerak beberapa langkah ADC. Karena itu, Pulse Sensor mudah dipakai dengan library siap pakai, sedangkan KY-039 butuh penyaringan dan ambang adaptif.

Apakah sensor detak jantung bisa mengukur oksigen darah (SpO2)?

Pulse Sensor dan KY-039 tidak bisa, karena perhitungan SpO2 bergantung pada perbandingan cahaya di dua panjang gelombang berbeda, yaitu merah dan inframerah. Untuk itu kamu butuh sensor dengan dua LED, seperti MAX30102. Bahkan hasil bacaan MAX30102 pun hanya perkiraan yang belum dikalibrasi dan tidak bisa menggantikan oksimeter medis.

Kenapa sensor detak jantungku menunjukkan nilai yang sangat tinggi atau melompat-lompat?

Penyebab paling umum adalah derau atau takik dikrotik pada gelombang nadi yang dihitung sebagai detak kedua; dalam kasus ini BPM yang keluar kira-kira dua kali nilai sebenarnya. Naikkan ambang, tahan jarimu di tempatnya dengan tali Velcro, dan lindungi sensor dari cahaya. Melihat gelombang mentah di Serial Plotter langsung menunjukkan sumber masalahnya.

Apakah Pulse Sensor bisa dipakai dengan ESP32 dan Raspberry Pi Pico?

Bisa, tetapi di kedua board kamu sebaiknya memberi daya sensor dari pin 3V3, karena input analognya tidak tahan lebih dari 3,3 V. Di ESP32 pakai pin ADC1 seperti GPIO 34 supaya tidak bentrok dengan Wi-Fi; di Pico pakai GP26, GP27, atau GP28. PulseSensorPlayground membutuhkan versi 3.x paket board ESP32, dan di MicroPython kamu menulis algoritmamu sendiri seperti yang ditunjukkan di artikel ini.

Berapa detak jantung yang normal?

Pada orang dewasa yang sedang istirahat, detak jantung biasanya antara 60 dan 100 kali per menit; pada orang yang rutin berolahraga bisa 40–60, dan pada anak-anak lebih tinggi. Denyut nadimu secara alami naik karena olahraga, stres, kafein, dan demam. Ini informasi umum; bicarakan hasil pengukuranmu atau keluhan apa pun dengan dokter.

Lihat semua proyek
Mengukur Intensitas Cahaya dengan LDR
#11Pemula

Mengukur Intensitas Cahaya dengan LDR

Ingin melihat seberapa terang kamarmu dalam bentuk angka? LDR, komponen kecil yang bereaksi terhadap cahaya, mengukur cahaya di sekitarnya, dan Arduino menulis nilainya ke layar komputermu setiap sete

4.6(81)
139
Membaca Intensitas Cahaya dengan Modul LDR ESP32
#113Pemula

Membaca Intensitas Cahaya dengan Modul LDR ESP32

Memantau secara real-time di Serial Monitor nilai ADC mentah modul LDR dan persentase cahaya relatif yang dihitung dari nilai acuan gelap dan terang. Persentase ini bukan pengukuran lux. Mengajarkan logika kalibrasi modul. Ideal dikerjakan sebelum Proyek 10, karena dipakai untuk menentukan nilai ambang.

4.6(36)
55
Menggunakan Buzzer
#13Pemula

Menggunakan Buzzer

Pernah penasaran bagaimana bel pintu atau alarm mengeluarkan suaranya? Arduino membuat buzzer kecil berbunyi bip dengan jeda singkat: bip, jeda, bip, jeda. Kamu melihat bagaimana suara dibuat dengan l

4.7(89)
161
Suhu dan Kelembapan dengan DHT11
#55Menengah

Suhu dan Kelembapan dengan DHT11

Seberapa hangat kamarmu, dan apakah udaranya lembap atau kering? Sensor DHT11 mengukur suhu dan kelembapan, dan Arduino menulis nilainya di layar LCD dua baris, diperbarui setiap beberapa detik. Jika

4.7(47)
73
Voltmeter Digital dengan Layar LCD
#56Menengah
Premium

Voltmeter Digital dengan Layar LCD

Cari tahu berapa tegangan yang diberikan baterai atau adaptor daya dengan alat ukur buatanmu sendiri. Pembagi dari dua resistor menurunkan tegangan tinggi ke tingkat yang bisa dibaca board, dan Arduin

4.5(27)
36
HTTPClient + API Cuaca ESP32 (dengan Layar OLED SSD1306)
#134Mahir
Premium

HTTPClient + API Cuaca ESP32 (dengan Layar OLED SSD1306)

Di proyek ini, kita memakai ESP32 untuk melakukan panggilan REST API ke API cuaca (wttr.in) lewat internet dengan HTTPClient.h. Berbeda dengan versi LCD I2C sebelumnya, di sini kita memakai layar OLED SSD1306 (128×64), yang memungkinkan font besar, ikon vektor, dan tampilan visual yang kaya di satu layar. Tujuh ikon vektor untuk kondisi cuaca (cerah, berawan sebagian, berawan, hujan, salju, badai, berkabut) digambar ketika program berjalan (tanpa file bitmap).

4.3(10)
19
Deep Sleep ESP32: Hemat Baterai (OLED + Penghitung RTC RAM)
#135Mahir
Premium

Deep Sleep ESP32: Hemat Baterai (OLED + Penghitung RTC RAM)

Mode Deep Sleep ESP32 menurunkan konsumsi arus hingga ~10 µA dengan mematikan CPU dan sebagian besar periferal, sehingga sangat penting untuk perangkat IoT bertenaga baterai. Di proyek ini, kita memakai tiga sumber bangun yang berbeda: timer (15 detik), pin eksternal (EXT0, tombol GPIO 33), dan sentuhan (T0/GPIO 4). Variabel yang ditandai RTC_DATA_ATTR dipertahankan selama deep sleep; penghitung boot, penghitung bangun karena timer, dan penghitung bangun karena tombol terus dilacak.

4.3(10)
16
LED Fade PWM Raspberry Pi Pico (Efek Bernapas)
#160Pemula

LED Fade PWM Raspberry Pi Pico (Efek Bernapas)

LED tidak lagi sekadar berkedip, ia bernapas! Dengan PWM (Pulse Width Modulation) Pico, kecerahan LED naik lalu turun perlahan, seperti lampu MacBook yang tidur. Pelajari kelas machine.PWM, duty_u16() (kecerahan 16-bit 0–65535), frekuensi PWM (freq(1000): 1000 siklus per detik, tanpa kedipan terlihat), loop range() bertahap, dan output mirip analog dari pin digital. PWM juga dipakai untuk warna RGB, motor, servo, dan buzzer.

0.0(0)
4