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.

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.
| Fitur | Nilai Pulse Sensor |
|---|---|
| Metode pengukuran | PPG reflektif |
| Sumber cahaya | LED hijau |
| Sensor cahaya | APDS-9008, sensitivitas puncak pada 565 nm |
| Catu daya | 3–5 V |
| Arus | Sekitar 4 mA (pada 5 V) |
| Output | Analog; setengah tegangan catu ketika diam (~2,5 V pada 5 V, ~512 di Uno) |
| Diameter board | Sekitar 16 mm (0,625 inci) |
| Kabel | Pada versi asli: merah +, hitam GND, ungu sinyal; warnanya bisa berbeda pada klon |
Pulse Sensor vs KY-039 vs MAX30102

| Fitur | Pulse Sensor | KY-039 | MAX30102 |
|---|---|---|---|
| Metode | PPG reflektif | PPG transmisif (jari di tengah) | PPG reflektif |
| Cahaya | LED hijau | LED inframerah | Merah (660 nm) + inframerah (880 nm) |
| Penguat dan filter | Ada (op-amp) | Tidak ada | ADC 18-bit internal, peredam cahaya sekitar |
| Output | Analog | Analog (sangat lemah) | Digital, I2C (alamat 0x57) |
| Catu daya | 3–5 V | 3,3–5 V | 3,3–5 V tergantung modulnya |
| Kualitas sinyal | Baik | Lemah, mudah terkena derau | Sangat baik |
| SpO2 (oksigen) | Tidak | Tidak | Ya (dengan algoritma) |
| Library | PulseSensor Playground | Tidak ada library siap pakai | SparkFun 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 sensor | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| + (VCC, merah) | 5V | 3V3 | 3V3(OUT), pin 36 |
| − (GND, hitam) | GND | GND | GND, pin 38 |
| S (sinyal, ungu) | A0 | GPIO 34 (ADC1) | GP26 (ADC0), pin 31 |
| LED detak (opsional) | D13 (LED bawaan) | GPIO 2 (LED bawaan) | LED di board |
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.
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
- Buka Library Manager di Arduino IDE, cari PulseSensor Playground, lalu instal. Untuk detail cara menginstal library, lihat artikel Cara Instal Library Arduino.
- Hubungkan sensor seperti di tabel: + ke 5V, − ke GND, dan S ke A0.
- Upload kode di bawah dan buka Serial Plotter pada 115200 baud; garis pertama menunjukkan sinyal mentah dan garis kedua menunjukkan nilai BPM.
- Letakkan jarimu di sensor, sandarkan tanganmu di meja, dan diam selama 10 detik; library akan menstabilkan rata-ratanya selama beberapa detak pertama.
- 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.
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}| Fungsi | Kegunaannya |
|---|---|
| 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.
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).
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.
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 / nilai | Kegunaannya |
|---|---|
| WINDOW_US = 20000 | Jendela 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.2 | Gelombang 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.
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.
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.
Sensor detak jantung bukan alat medis
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
| Gejala | Kemungkinan penyebab | Solusi |
|---|---|---|
| BPM selalu 0 atau “--” | Tidak ada detak yang terdeteksi: ambang terlalu tinggi, tidak ada jari, atau pin S di input yang salah | Periksa gelombangnya dengan sketch sinyal mentah; geser ambang ke tengah gelombang |
| BPM sangat tinggi, misalnya 150–220 | Derau atau takik dikrotik dihitung sebagai detak kedua | Naikkan ambang, stabilkan jari, halangi cahaya sekitar |
| BPM muncul meskipun tanpa jari | Ambang di bawah derau ketika diam; kedipan lampu masuk ke sinyal | Atur 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 rusak | Periksa pengkabelan dengan tabel; pakai 3V3 di ESP32 dan Pico |
| Ada gelombang tapi terus terputus-putus | Jari bergerak atau tekanannya berubah | Lilitkan sensor dengan tali Velcro, sandarkan tangan di meja, dan tetap diam |
| Sama sekali tidak ada gelombang di KY-039 | LED tidak ditekuk ke arah fototransistor, atau cahaya sekitar yang kuat membuat fototransistor jenuh | Tekuk 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 ESP32 | PulseSensorPlayground dikompilasi dengan versi 2.x paket board ESP32 | Perbarui paket board ke 3.x atau pakai kode ESP32 tanpa library di artikel ini |
| analogWrite() tidak berfungsi di pin 9 atau 10 | Library memakai Timer1 di Uno | Pakai pin 3, 5, 6, atau 11 untuk PWM |
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.
Proyek untuk dibuat setelah membaca ini
Lihat semua proyek
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

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.

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

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

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

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).

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.

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.
Artikel lainnya
Aplikasi BlueGrays
Rakit rangkaian ini langkah demi langkah di ponselmu
Skema pengkabelan, kode, dan daftar komponen dalam satu layar. 200+ proyek Arduino, ESP32, dan Pico siap dibuat.
Pindai dengan ponselmu
Arahkan kamera ke kode ini dan toko aplikasi di ponselmu akan terbuka.
atau buka toko aplikasi

